Skip to content

Instantly share code, notes, and snippets.

@0xJCN
Last active June 9, 2023 13:45
Show Gist options
  • Save 0xJCN/40a25671cde00e756fcfc43b7a5ec4af to your computer and use it in GitHub Desktop.
Save 0xJCN/40a25671cde00e756fcfc43b7a5ec4af to your computer and use it in GitHub Desktop.

Final diff for Auction.sol

diff --git a/contracts/Auction.sol b/contracts/Auction.sol
index ae5fd02..fe74efc 100644
--- a/contracts/Auction.sol
+++ b/contracts/Auction.sol
@@ -13,7 +13,7 @@ import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.

 contract Auction is IAuction, Initializable, AccessControlUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable {
     IStaderConfig public override staderConfig;
-    uint256 public override nextLot;
+    uint96 public override nextLot;
     uint256 public override bidIncrement;
     uint256 public override duration;

@@ -47,15 +47,14 @@ contract Auction is IAuction, Initializable, AccessControlUpgradeable, PausableU

     function createLot(uint256 _sdAmount) external override whenNotPaused {
         lots[nextLot].startBlock = block.number;
-        lots[nextLot].endBlock = block.number + duration;
+        uint256 _duration = duration;
+        lots[nextLot].endBlock = block.number + _duration;
         lots[nextLot].sdAmount = _sdAmount;

-        LotItem storage lotItem = lots[nextLot];
-
         if (!IERC20(staderConfig.getStaderToken()).transferFrom(msg.sender, address(this), _sdAmount)) {
             revert SDTransferFailed();
         }
-        emit LotCreated(nextLot, lotItem.sdAmount, lotItem.startBlock, lotItem.endBlock, bidIncrement);
+        emit LotCreated(nextLot, _sdAmount, block.number, block.number + _duration, bidIncrement);
         nextLot++;
     }

@@ -80,14 +79,16 @@ contract Auction is IAuction, Initializable, AccessControlUpgradeable, PausableU
     function claimSD(uint256 lotId) external override {
         LotItem storage lotItem = lots[lotId];
         if (block.number <= lotItem.endBlock) revert AuctionNotEnded();
-        if (msg.sender != lotItem.highestBidder) revert notQualified();
+        address _highestBidder = lotItem.highestBidder;
+        if (msg.sender != _highestBidder) revert notQualified();
         if (lotItem.sdClaimed) revert AlreadyClaimed();

         lotItem.sdClaimed = true;
-        if (!IERC20(staderConfig.getStaderToken()).transfer(lotItem.highestBidder, lotItem.sdAmount)) {
+        uint256 _sdAmount = lotItem.sdAmount;
+        if (!IERC20(staderConfig.getStaderToken()).transfer(_highestBidder, _sdAmount)) {
             revert SDTransferFailed();
         }
-        emit SDClaimed(lotId, lotItem.highestBidder, lotItem.sdAmount);
+        emit SDClaimed(lotId, _highestBidder, _sdAmount);
     }

     function transferHighestBidToSSPM(uint256 lotId) external override nonReentrant {

Final diff for IAuctionFinal.sol

diff --git a/contracts/interfaces/SDCollateral/IAuction.sol b/contracts/interfaces/SDCollateral/IAuction.sol
index 04d3164..ea95207 100644
--- a/contracts/interfaces/SDCollateral/IAuction.sol
+++ b/contracts/interfaces/SDCollateral/IAuction.sol
@@ -65,9 +65,10 @@ interface IAuction {
     //getters
     function staderConfig() external view returns (IStaderConfig);

-    function nextLot() external view returns (uint256);
+    function nextLot() external view returns (uint96);

     function bidIncrement() external view returns (uint256);

     function duration() external view returns (uint256);
 }

Final diff for NodeElRewardVault.sol

diff --git a/contracts/NodeELRewardVault.sol b/contracts/NodeELRewardVault.sol
index b10417a..2ae0d59 100644
--- a/contracts/NodeELRewardVault.sol
+++ b/contracts/NodeELRewardVault.sol
@@ -22,25 +22,46 @@ contract NodeELRewardVault is INodeELRewardVault {
     }

     function withdraw() external override {
-        uint8 poolId = IVaultProxy(address(this)).poolId();
-        uint256 operatorId = IVaultProxy(address(this)).id();
-        IStaderConfig staderConfig = IVaultProxy(address(this)).staderConfig();
+        uint8 poolId;
+        uint256 operatorId;
+        IStaderConfig staderConfig;
+        assembly {
+            // function sigs for "poolId()", "id()", and "staderConfig()"
+            mstore(0x00, 0x490ffa35af640d0f3e0dc34e)
+            if iszero(staticcall(gas(), address(), 0x1c, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            poolId := mload(0x20)
+            if iszero(staticcall(gas(), address(), 0x18, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            operatorId := mload(0x20)
+            if iszero(staticcall(gas(), address(), 0x14, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            staderConfig := mload(0x20)
+        }
         uint256 totalRewards = address(this).balance;
         if (totalRewards == 0) {
             revert NotEnoughRewardToWithdraw();
         }
-        (uint256 userShare, uint256 operatorShare, uint256 protocolShare) = IPoolUtils(staderConfig.getPoolUtils())
-            .calculateRewardShare(poolId, totalRewards);
+        IPoolUtils poolUtils = IPoolUtils(staderConfig.getPoolUtils());
+        (uint256 userShare, uint256 operatorShare, uint256 protocolShare) = poolUtils.calculateRewardShare(poolId, totalRewards);

         // Distribute rewards
         IStaderStakePoolManager(staderConfig.getStakePoolManager()).receiveExecutionLayerRewards{value: userShare}();
         // slither-disable-next-line arbitrary-send-eth
         UtilLib.sendValue(payable(staderConfig.getStaderTreasury()), protocolShare);
-        address operator = UtilLib.getOperatorAddressByOperatorId(poolId, operatorId, staderConfig);
+        address operator = getOperatorAddressByOperatorId(poolId, operatorId, poolUtils);
         IOperatorRewardsCollector(staderConfig.getOperatorRewardsCollector()).depositFor{value: operatorShare}(
             operator
         );

         emit Withdrawal(protocolShare, operatorShare, userShare);
     }
+
+    function getOperatorAddressByOperatorId(
+        uint8 _poolId,
+        uint256 _operatorId,
+        IPoolUtils poolUtils
+    ) internal view returns (address) {
+        address nodeRegistry = poolUtils.getNodeRegistry(_poolId);
+        (, , , , address operatorAddress) = INodeRegistry(nodeRegistry).operatorStructById(_operatorId);
+        return operatorAddress;
+    }
 }

Final diff for OperatorRewardsCollector.sol

diff --git a/contracts/OperatorRewardsCollector.sol b/contracts/OperatorRewardsCollector.sol
index e80db8a..d284367 100644
--- a/contracts/OperatorRewardsCollector.sol
+++ b/contracts/OperatorRewardsCollector.sol
@@ -46,7 +46,7 @@ contract OperatorRewardsCollector is
     function claim() external whenNotPaused {
         address operator = msg.sender;
         uint256 amount = balances[operator];
-        balances[operator] -= amount;
+        balances[operator] = 0;

         address operatorRewardsAddr = UtilLib.getOperatorRewardAddress(msg.sender, staderConfig);
         UtilLib.sendValue(operatorRewardsAddr, amount);

Final diff for Penalty.sol

diff --git a/contracts/Penalty.sol b/contracts/Penalty.sol
index d6a28dc..9e0bfa6 100644
--- a/contracts/Penalty.sol
+++ b/contracts/Penalty.sol
@@ -98,13 +98,14 @@ contract Penalty is IPenalty, Initializable, AccessControlUpgradeable, Reentranc
     function updateTotalPenaltyAmount(bytes[] calldata _pubkey) external override nonReentrant {
         uint256 reportedValidatorCount = _pubkey.length;
         for (uint256 i; i < reportedValidatorCount; ) {
-            if (UtilLib.getValidatorSettleStatus(_pubkey[i], staderConfig)) {
+            IStaderConfig _staderConfig = staderConfig;
+            if (UtilLib.getValidatorSettleStatus(_pubkey[i], _staderConfig)) {
                 revert ValidatorSettled();
             }
             bytes32 pubkeyRoot = UtilLib.getPubkeyRoot(_pubkey[i]);
             // Retrieve the penalty for changing the fee recipient address based on Rated.network data.
             uint256 _mevTheftPenalty = calculateMEVTheftPenalty(pubkeyRoot);
-            uint256 _missedAttestationPenalty = calculateMissedAttestationPenalty(pubkeyRoot);
+            uint256 _missedAttestationPenalty = _calculateMissedAttestationPenalty(_staderConfig, pubkeyRoot);

             // Compute the total penalty for the given validator public key,
             // taking into account additional penalties and penalty reversals from the DAO.
@@ -119,6 +120,12 @@ contract Penalty is IPenalty, Initializable, AccessControlUpgradeable, Reentranc
         }
     }

+    function _calculateMissedAttestationPenalty(IStaderConfig _staderConfig, bytes32 _pubkeyRoot) internal view returns (uint256) {
+        return
+            IStaderOracle(_staderConfig.getStaderOracle()).missedAttestationPenalty(_pubkeyRoot) *
+            missedAttestationPenaltyPerStrike;
+    }
+
     /// @inheritdoc IPenalty
     function calculateMEVTheftPenalty(bytes32 _pubkeyRoot) public override returns (uint256) {
         // Retrieve the epochs in which the validator violated the fee recipient change rule.
@@ -130,9 +137,7 @@ contract Penalty is IPenalty, Initializable, AccessControlUpgradeable, Reentranc

     /// @inheritdoc IPenalty
     function calculateMissedAttestationPenalty(bytes32 _pubkeyRoot) public view override returns (uint256) {
-        return
-            IStaderOracle(staderConfig.getStaderOracle()).missedAttestationPenalty(_pubkeyRoot) *
-            missedAttestationPenaltyPerStrike;
+        return _calculateMissedAttestationPenalty(staderConfig, _pubkeyRoot);
     }

     /// @inheritdoc IPenalty

Final diff for PermissionedNodeRegistry.sol

diff --git a/contracts/PermissionedNodeRegistry.sol b/contracts/PermissionedNodeRegistry.sol
index ca8aa81..bba1423 100644
--- a/contracts/PermissionedNodeRegistry.sol
+++ b/contracts/PermissionedNodeRegistry.sol
@@ -115,7 +115,8 @@ contract PermissionedNodeRegistry is
         }
         IPoolUtils(poolUtils).onlyValidName(_operatorName);
         UtilLib.checkNonZeroAddress(_operatorRewardAddress);
-        if (nextOperatorId > maxOperatorId) {
+        uint256 _nextOperatorId = nextOperatorId;
+        if (_nextOperatorId > maxOperatorId) {
             revert MaxOperatorLimitReached();
         }
         if (!permissionList[msg.sender]) {
@@ -126,7 +127,7 @@ contract PermissionedNodeRegistry is
             revert OperatorAlreadyOnBoardedInProtocol();
         }
         feeRecipientAddress = staderConfig.getPermissionedSocializingPool();
-        onboardOperator(_operatorName, _operatorRewardAddress);
+        onboardOperator(_nextOperatorId, _operatorName, _operatorRewardAddress);
         return feeRecipientAddress;
     }

@@ -143,41 +144,47 @@ contract PermissionedNodeRegistry is
         bytes[] calldata _depositSignature
     ) external override whenNotPaused {
         uint256 operatorId = onlyActiveOperator(msg.sender);
+        IStaderConfig _staderConfig = staderConfig;
         (uint256 keyCount, uint256 operatorTotalKeys) = checkInputKeysCountAndCollateral(
+            _staderConfig,
             _pubkey.length,
             _preDepositSignature.length,
             _depositSignature.length,
             operatorId
         );

-        address vaultFactory = staderConfig.getVaultFactory();
+        address vaultFactory = _staderConfig.getVaultFactory();
         address poolUtils = staderConfig.getPoolUtils();
+        uint256 _nextValidatorId = nextValidatorId;
         for (uint256 i; i < keyCount; ) {
             IPoolUtils(poolUtils).onlyValidKeys(_pubkey[i], _preDepositSignature[i], _depositSignature[i]);
-            address withdrawVault = IVaultFactory(vaultFactory).deployWithdrawVault(
-                POOL_ID,
-                operatorId,
-                operatorTotalKeys + i, //operator totalKeys
-                nextValidatorId
-            );
-            validatorRegistry[nextValidatorId] = Validator(
-                ValidatorStatus.INITIALIZED,
-                _pubkey[i],
-                _preDepositSignature[i],
-                _depositSignature[i],
-                withdrawVault,
-                operatorId,
-                0,
-                0
-            );
-            validatorIdByPubkey[_pubkey[i]] = nextValidatorId;
-            validatorIdsByOperatorId[operatorId].push(nextValidatorId);
-            emit AddedValidatorKey(msg.sender, _pubkey[i], nextValidatorId);
-            nextValidatorId++;
+            { // @audit: used due to `stack too deep` errors
+                address withdrawVault = IVaultFactory(vaultFactory).deployWithdrawVault(
+                    POOL_ID,
+                    operatorId,
+                    operatorTotalKeys + i, //operator totalKeys
+                    _nextValidatorId
+                );
+                // @audit: stored seperately due to `stack too deep` errors
+                validatorRegistry[_nextValidatorId].status = ValidatorStatus.INITIALIZED;
+                validatorRegistry[_nextValidatorId].pubkey = _pubkey[i];
+                validatorRegistry[_nextValidatorId].preDepositSignature = _preDepositSignature[i];
+                validatorRegistry[_nextValidatorId].depositSignature = _depositSignature[i];
+                validatorRegistry[_nextValidatorId].operatorId = operatorId;
+                validatorRegistry[_nextValidatorId].withdrawVaultAddress = withdrawVault;
+                validatorRegistry[_nextValidatorId].depositBlock = 0;
+                validatorRegistry[_nextValidatorId].withdrawnBlock = 0;
+            }
+
+            validatorIdByPubkey[_pubkey[i]] = _nextValidatorId;
+            validatorIdsByOperatorId[operatorId].push(_nextValidatorId);
+            emit AddedValidatorKey(msg.sender, _pubkey[i], _nextValidatorId);
+            _nextValidatorId++;
             unchecked {
                 ++i;
             }
         }
+        nextValidatorId = _nextValidatorId;
     }

     /**
@@ -320,7 +327,7 @@ contract PermissionedNodeRegistry is
                 revert UNEXPECTED_STATUS();
             }
             validatorRegistry[validatorId].status = ValidatorStatus.WITHDRAWN;
-            validatorRegistry[validatorId].withdrawnBlock = block.number;
+            validatorRegistry[validatorId].withdrawnBlock = uint48(block.number);
             IValidatorWithdrawalVault(validatorRegistry[validatorId].withdrawVaultAddress).settleFunds();
             emit ValidatorWithdrawn(_pubkeys[i], validatorId);
             unchecked {
@@ -375,7 +382,7 @@ contract PermissionedNodeRegistry is
      */
     function updateDepositStatusAndBlock(uint256 _validatorId) external override {
         UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.PERMISSIONED_POOL());
-        validatorRegistry[_validatorId].depositBlock = block.number;
+        validatorRegistry[_validatorId].depositBlock = uint48(block.number);
         markValidatorDeposited(_validatorId);
         emit UpdatedValidatorDepositBlock(_validatorId, block.number);
     }
@@ -401,8 +408,7 @@ contract PermissionedNodeRegistry is
     function updateOperatorDetails(string calldata _operatorName, address payable _rewardAddress) external override {
         IPoolUtils(staderConfig.getPoolUtils()).onlyValidName(_operatorName);
         UtilLib.checkNonZeroAddress(_rewardAddress);
-        onlyActiveOperator(msg.sender);
-        uint256 operatorId = operatorIDByAddress[msg.sender];
+        uint256 operatorId = onlyActiveOperator(msg.sender);
         operatorStructById[operatorId].operatorName = _operatorName;
         operatorStructById[operatorId].operatorRewardAddress = _rewardAddress;
         emit UpdatedOperatorDetails(msg.sender, _operatorName, _rewardAddress);
@@ -658,8 +664,8 @@ contract PermissionedNodeRegistry is
         onlyPreDepositValidator(validatorId);
     }

-    function onboardOperator(string calldata _operatorName, address payable _operatorRewardAddress) internal {
-        operatorStructById[nextOperatorId] = Operator(true, true, _operatorName, _operatorRewardAddress, msg.sender);
+    function onboardOperator(uint256 _nextOperatorId, string calldata _operatorName, address payable _operatorRewardAddress) internal {
+        operatorStructById[_nextOperatorId] = Operator(true, true, _operatorName, _operatorRewardAddress, msg.sender);
         operatorIDByAddress[msg.sender] = nextOperatorId;
         socializingPoolStateChangeBlock[nextOperatorId] = block.number;
         nextOperatorId++;
@@ -685,6 +691,7 @@ contract PermissionedNodeRegistry is

     // validate the input of `addValidatorKeys` function
     function checkInputKeysCountAndCollateral(
+        IStaderConfig _staderConfig,
         uint256 _pubkeyLength,
         uint256 _preDepositSignatureLength,
         uint256 _depositSignatureLength,
@@ -706,7 +713,7 @@ contract PermissionedNodeRegistry is
         //checks if operator has enough SD collateral for adding `keyCount` keys
         //SD threshold for permissioned NOs is 0 for phase1
         if (
-            !ISDCollateral(staderConfig.getSDCollateral()).hasEnoughSDCollateral(
+            !ISDCollateral(_staderConfig.getSDCollateral()).hasEnoughSDCollateral(
                 msg.sender,
                 POOL_ID,
                 totalNonTerminalKeys + keyCount

Final diff for PermissionedPool.sol

diff --git a/contracts/PermissionedPool.sol b/contracts/PermissionedPool.sol
index 85ec85d..9c58bc4 100644
--- a/contracts/PermissionedPool.sol
+++ b/contracts/PermissionedPool.sol
@@ -23,10 +23,10 @@ contract PermissionedPool is IStaderPoolBase, Initializable, AccessControlUpgrad

     IStaderConfig public staderConfig;
     // @inheritdoc IStaderPoolBase
-    uint256 public override protocolFee;
+    uint48 public override protocolFee;

     // @inheritdoc IStaderPoolBase
-    uint256 public override operatorFee;
+    uint48 public override operatorFee;

     uint256 public preDepositValidatorCount;

@@ -97,6 +97,7 @@ contract PermissionedPool is IStaderPoolBase, Initializable, AccessControlUpgrad

         // i is the operator Id
         uint256 selectedOperatorCapacityLength = selectedOperatorCapacity.length;
+        IStaderConfig _staderConfig = staderConfig;
         for (uint256 i = 1; i < selectedOperatorCapacityLength; ) {
             uint256 validatorToDeposit = selectedOperatorCapacity[i];
             if (validatorToDeposit == 0) {
@@ -112,7 +113,7 @@ contract PermissionedPool is IStaderPoolBase, Initializable, AccessControlUpgrad
                 index++
             ) {
                 uint256 validatorId = INodeRegistry(nodeRegistryAddress).validatorIdsByOperatorId(i, index);
-                preDepositOnBeaconChain(nodeRegistryAddress, vaultFactory, ethDepositContract, validatorId);
+                preDepositOnBeaconChain(_staderConfig, nodeRegistryAddress, vaultFactory, ethDepositContract, validatorId);
             }
             IPermissionedNodeRegistry(nodeRegistryAddress).updateQueuedValidatorIndex(
                 i,
@@ -137,7 +138,7 @@ contract PermissionedPool is IStaderPoolBase, Initializable, AccessControlUpgrad
         for (uint256 i; i < pubkeyCount; ) {
             IPermissionedNodeRegistry(nodeRegistryAddress).onlyPreDepositValidator(_pubkey[i]);
             uint256 validatorId = INodeRegistry(nodeRegistryAddress).validatorIdByPubkey(_pubkey[i]);
-            (, , , bytes memory depositSignature, address withdrawVaultAddress, , , ) = INodeRegistry(
+            (, , , bytes memory depositSignature, , address withdrawVaultAddress, , ) = INodeRegistry(
                 nodeRegistryAddress
             ).validatorRegistry(validatorId);
             bytes memory withdrawCredential = IVaultFactory(vaultFactory).getValidatorWithdrawCredential(
@@ -238,8 +239,8 @@ contract PermissionedPool is IStaderPoolBase, Initializable, AccessControlUpgrad
         if (_protocolFee + _operatorFee > MAX_COMMISSION_LIMIT_BIPS) {
             revert InvalidCommission();
         }
-        protocolFee = _protocolFee;
-        operatorFee = _operatorFee;
+        protocolFee = uint48(_protocolFee);
+        operatorFee = uint48(_operatorFee);

         emit UpdatedCommissionFees(_protocolFee, _operatorFee);
     }
@@ -286,19 +287,20 @@ contract PermissionedPool is IStaderPoolBase, Initializable, AccessControlUpgrad

     // deposit `PRE_DEPOSIT_SIZE` for validator
     function preDepositOnBeaconChain(
+        IStaderConfig _staderConfig,
         address _nodeRegistryAddress,
         address _vaultFactory,
         address _ethDepositContract,
         uint256 _validatorId
     ) internal {
-        (, bytes memory pubkey, bytes memory preDepositSignature, , address withdrawVaultAddress, , , ) = INodeRegistry(
+        (, bytes memory pubkey, bytes memory preDepositSignature, , , address withdrawVaultAddress, , ) = INodeRegistry(
             _nodeRegistryAddress
         ).validatorRegistry(_validatorId);

         bytes memory withdrawCredential = IVaultFactory(_vaultFactory).getValidatorWithdrawCredential(
             withdrawVaultAddress
         );
-        uint256 preDepositSize = staderConfig.getPreDepositSize();
+        uint256 preDepositSize = _staderConfig.getPreDepositSize();
         bytes32 depositDataRoot = this.computeDepositDataRoot(
             pubkey,
             preDepositSignature,

Final diff for PermissionlessNodeRegistry.sol

diff --git a/contracts/PermissionlessNodeRegistry.sol b/contracts/PermissionlessNodeRegistry.sol
index 9640556..536dee6 100644
--- a/contracts/PermissionlessNodeRegistry.sol
+++ b/contracts/PermissionlessNodeRegistry.sol
@@ -107,11 +107,12 @@ contract PermissionlessNodeRegistry is
             POOL_ID,
             nextOperatorId
         );
-        nodeELRewardVaultByOperatorId[nextOperatorId] = nodeELRewardVault;
+        uint256 _nextOperatorId = nextOperatorId;
+        nodeELRewardVaultByOperatorId[_nextOperatorId] = nodeELRewardVault;
         feeRecipientAddress = _optInForSocializingPool
             ? staderConfig.getPermissionlessSocializingPool()
             : nodeELRewardVault;
-        onboardOperator(_optInForSocializingPool, _operatorName, _operatorRewardAddress);
+        onboardOperator(_nextOperatorId, _optInForSocializingPool, _operatorName, _operatorRewardAddress);
         return feeRecipientAddress;
     }

@@ -128,42 +129,47 @@ contract PermissionlessNodeRegistry is
         bytes[] calldata _depositSignature
     ) external payable override nonReentrant whenNotPaused {
         uint256 operatorId = onlyActiveOperator(msg.sender);
+        IStaderConfig _staderConfig = staderConfig;
         (uint256 keyCount, uint256 operatorTotalKeys) = checkInputKeysCountAndCollateral(
+            _staderConfig,
             _pubkey.length,
             _preDepositSignature.length,
             _depositSignature.length,
             operatorId
         );

-        address vaultFactory = staderConfig.getVaultFactory();
+        address vaultFactory = _staderConfig.getVaultFactory();
         address poolUtils = staderConfig.getPoolUtils();
+        uint256 _nextValidatorId = nextValidatorId;
         for (uint256 i; i < keyCount; ) {
             IPoolUtils(poolUtils).onlyValidKeys(_pubkey[i], _preDepositSignature[i], _depositSignature[i]);
-            address withdrawVault = IVaultFactory(vaultFactory).deployWithdrawVault(
-                POOL_ID,
-                operatorId,
-                operatorTotalKeys + i, //operator totalKeys
-                nextValidatorId
-            );
-            validatorRegistry[nextValidatorId] = Validator(
-                ValidatorStatus.INITIALIZED,
-                _pubkey[i],
-                _preDepositSignature[i],
-                _depositSignature[i],
-                withdrawVault,
-                operatorId,
-                0,
-                0
-            );
-
-            validatorIdByPubkey[_pubkey[i]] = nextValidatorId;
-            validatorIdsByOperatorId[operatorId].push(nextValidatorId);
-            emit AddedValidatorKey(msg.sender, _pubkey[i], nextValidatorId);
-            nextValidatorId++;
+            { // @audit: used due to `stack too deep` errors
+                address withdrawVault = IVaultFactory(vaultFactory).deployWithdrawVault(
+                    POOL_ID,
+                    operatorId,
+                    operatorTotalKeys + i, //operator totalKeys
+                    _nextValidatorId
+                );
+                // @audit: stored seperately due to `stack too deep` errors
+                validatorRegistry[_nextValidatorId].status = ValidatorStatus.INITIALIZED;
+                validatorRegistry[_nextValidatorId].pubkey = _pubkey[i];
+                validatorRegistry[_nextValidatorId].preDepositSignature = _preDepositSignature[i];
+                validatorRegistry[_nextValidatorId].depositSignature = _depositSignature[i];
+                validatorRegistry[_nextValidatorId].operatorId = operatorId;
+                validatorRegistry[_nextValidatorId].withdrawVaultAddress = withdrawVault;
+                validatorRegistry[_nextValidatorId].depositBlock = 0;
+                validatorRegistry[_nextValidatorId].withdrawnBlock = 0;
+            }
+
+            validatorIdByPubkey[_pubkey[i]] = _nextValidatorId;
+            validatorIdsByOperatorId[operatorId].push(_nextValidatorId);
+            emit AddedValidatorKey(msg.sender, _pubkey[i], _nextValidatorId);
+            _nextValidatorId++;
             unchecked {
                 ++i;
             }
         }
+        nextValidatorId = _nextValidatorId;

         //slither-disable-next-line arbitrary-send-eth
         IPermissionlessPool(staderConfig.getPermissionlessPool()).preDepositOnBeaconChain{
@@ -196,15 +202,19 @@ contract PermissionlessNodeRegistry is
             revert TooManyVerifiedKeysReported();
         }

+        uint256 _validatorQueueSize = validatorQueueSize;
         for (uint256 i; i < readyToDepositValidatorsLength; ) {
             uint256 validatorId = validatorIdByPubkey[_readyToDepositPubkey[i]];
             onlyInitializedValidator(validatorId);
-            markKeyReadyToDeposit(validatorId);
+            validatorRegistry[validatorId].status = ValidatorStatus.PRE_DEPOSIT;
+            queuedValidators[_validatorQueueSize] = validatorId;
+            _validatorQueueSize++;
             emit ValidatorMarkedReadyToDeposit(_readyToDepositPubkey[i], validatorId);
             unchecked {
                 ++i;
             }
         }
+        validatorQueueSize = _validatorQueueSize;

         if (frontRunValidatorsLength > 0) {
             IStaderInsuranceFund(staderConfig.getStaderInsuranceFund()).depositFund{
@@ -250,7 +260,7 @@ contract PermissionlessNodeRegistry is
                 revert UNEXPECTED_STATUS();
             }
             validatorRegistry[validatorId].status = ValidatorStatus.WITHDRAWN;
-            validatorRegistry[validatorId].withdrawnBlock = block.number;
+            validatorRegistry[validatorId].withdrawnBlock = uint48(block.number);
             IValidatorWithdrawalVault(validatorRegistry[validatorId].withdrawVaultAddress).settleFunds();
             emit ValidatorWithdrawn(_pubkeys[i], validatorId);
             unchecked {
@@ -278,7 +288,7 @@ contract PermissionlessNodeRegistry is
      */
     function updateDepositStatusAndBlock(uint256 _validatorId) external override {
         UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.PERMISSIONLESS_POOL());
-        validatorRegistry[_validatorId].depositBlock = block.number;
+        validatorRegistry[_validatorId].depositBlock = uint48(block.number);
         markValidatorDeposited(_validatorId);
         emit UpdatedValidatorDepositBlock(_validatorId, block.number);
     }
@@ -366,8 +376,7 @@ contract PermissionlessNodeRegistry is
     function updateOperatorDetails(string calldata _operatorName, address payable _rewardAddress) external override {
         IPoolUtils(staderConfig.getPoolUtils()).onlyValidName(_operatorName);
         UtilLib.checkNonZeroAddress(_rewardAddress);
-        onlyActiveOperator(msg.sender);
-        uint256 operatorId = operatorIDByAddress[msg.sender];
+        uint256 operatorId = onlyActiveOperator(msg.sender);
         operatorStructById[operatorId].operatorName = _operatorName;
         operatorStructById[operatorId].operatorRewardAddress = _rewardAddress;
         emit UpdatedOperatorDetails(msg.sender, _operatorName, _rewardAddress);
@@ -596,11 +605,12 @@ contract PermissionlessNodeRegistry is
     }

     function onboardOperator(
+        uint256 _nextOperatorId,
         bool _optInForSocializingPool,
         string calldata _operatorName,
         address payable _operatorRewardAddress
     ) internal {
-        operatorStructById[nextOperatorId] = Operator(
+        operatorStructById[_nextOperatorId] = Operator(
             true,
             _optInForSocializingPool,
             _operatorName,
@@ -614,13 +624,6 @@ contract PermissionlessNodeRegistry is
         emit OnboardedOperator(msg.sender, _operatorRewardAddress, nextOperatorId - 1, _optInForSocializingPool);
     }

-    // mark validator  `PRE_DEPOSIT` after successful key verification and front run check
-    function markKeyReadyToDeposit(uint256 _validatorId) internal {
-        validatorRegistry[_validatorId].status = ValidatorStatus.PRE_DEPOSIT;
-        queuedValidators[validatorQueueSize] = _validatorId;
-        validatorQueueSize++;
-    }
-
     // handle front run validator by changing their status, deactivating operator and imposing penalty
     function handleFrontRun(uint256 _validatorId) internal {
         validatorRegistry[_validatorId].status = ValidatorStatus.FRONT_RUN;
@@ -641,6 +644,7 @@ contract PermissionlessNodeRegistry is

     // validate the input of `addValidatorKeys` function
     function checkInputKeysCountAndCollateral(
+        IStaderConfig _staderConfig,
         uint256 _pubkeyLength,
         uint256 _preDepositSignatureLength,
         uint256 _depositSignatureLength,
@@ -666,7 +670,7 @@ contract PermissionlessNodeRegistry is
         }
         //checks if operator has enough SD collateral for adding `keyCount` keys
         if (
-            !ISDCollateral(staderConfig.getSDCollateral()).hasEnoughSDCollateral(
+            !ISDCollateral(_staderConfig.getSDCollateral()).hasEnoughSDCollateral(
                 msg.sender,
                 POOL_ID,
                 totalNonTerminalKeys + keyCount

Final diff for PermissionlessPool.sol

diff --git a/contracts/PermissionlessPool.sol b/contracts/PermissionlessPool.sol
index 046761d..797e213 100644
--- a/contracts/PermissionlessPool.sol
+++ b/contracts/PermissionlessPool.sol
@@ -23,10 +23,10 @@ contract PermissionlessPool is IStaderPoolBase, Initializable, AccessControlUpgr
     uint256 public constant DEPOSIT_NODE_BOND = 3 ether;

     /// @inheritdoc IStaderPoolBase
-    uint256 public override protocolFee;
+    uint48 public override protocolFee;

     /// @inheritdoc IStaderPoolBase
-    uint256 public override operatorFee;
+    uint48 public override operatorFee;

     uint256 public constant MAX_COMMISSION_LIMIT_BIPS = 1500;

@@ -68,8 +68,8 @@ contract PermissionlessPool is IStaderPoolBase, Initializable, AccessControlUpgr
         if (_protocolFee + _operatorFee > MAX_COMMISSION_LIMIT_BIPS) {
             revert InvalidCommission();
         }
-        protocolFee = _protocolFee;
-        operatorFee = _operatorFee;
+        protocolFee = uint48(_protocolFee);
+        operatorFee = uint48(_operatorFee);

         emit UpdatedCommissionFees(_protocolFee, _operatorFee);
     }
@@ -245,7 +245,7 @@ contract PermissionlessPool is IStaderPoolBase, Initializable, AccessControlUpgr
         uint256 _validatorId,
         uint256 _DEPOSIT_SIZE
     ) internal {
-        (, bytes memory pubkey, , bytes memory depositSignature, address withdrawVaultAddress, , , ) = INodeRegistry(
+        (, bytes memory pubkey, , bytes memory depositSignature, , address withdrawVaultAddress, , ) = INodeRegistry(
             _nodeRegistryAddress
         ).validatorRegistry(_validatorId);

Final diff for INodeRegistry.sol

diff --git a/contracts/interfaces/INodeRegistry.sol b/contracts/interfaces/INodeRegistry.sol
index 5360913..182ab42 100644
--- a/contracts/interfaces/INodeRegistry.sol
+++ b/contracts/interfaces/INodeRegistry.sol
@@ -8,10 +8,10 @@ struct Validator {
     bytes pubkey; //pubkey of the validator
     bytes preDepositSignature; //signature for 1 ETH deposit on beacon chain
     bytes depositSignature; //signature for 31 ETH deposit on beacon chain
-    address withdrawVaultAddress; //withdrawal vault address of validator
     uint256 operatorId; // stader network assigned Id
-    uint256 depositBlock; // block number of the 31ETH deposit
-    uint256 withdrawnBlock; //block number when oracle report validator as withdrawn
+    address withdrawVaultAddress; //withdrawal vault address of validator
+    uint48 depositBlock; // block number of the 31ETH deposit
+    uint48 withdrawnBlock; //block number when oracle report validator as withdrawn
 }

 struct Operator {
@@ -72,10 +72,10 @@ interface INodeRegistry {
             bytes calldata pubkey,
             bytes calldata preDepositSignature,
             bytes calldata depositSignature,
-            address withdrawVaultAddress,
             uint256 operatorId,
-            uint256 depositTime,
-            uint256 withdrawnTime
+            address withdrawVaultAddress,
+            uint48 depositTime,
+            uint48 withdrawnTime
         );

Final diff for SDCollateral.sol

diff --git a/contracts/SDCollateral.sol b/contracts/SDCollateral.sol
index 0b5e22b..56c9c62 100644
--- a/contracts/SDCollateral.sol
+++ b/contracts/SDCollateral.sol
@@ -58,14 +58,15 @@ contract SDCollateral is ISDCollateral, Initializable, AccessControlUpgradeable,
     function withdraw(uint256 _requestedSD) external override {
         address operator = msg.sender;
         uint256 opSDBalance = operatorSDBalance[operator];
-
-        if (opSDBalance < getOperatorWithdrawThreshold(operator) + _requestedSD) {
+
+        IStaderConfig _staderConfig = staderConfig;
+        if (opSDBalance < _getOperatorWithdrawThreshold(_staderConfig, operator) + _requestedSD) {
             revert InsufficientSDToWithdraw(opSDBalance);
         }
-        operatorSDBalance[operator] -= _requestedSD;
+        operatorSDBalance[operator] = opSDBalance - _requestedSD;

         // cannot use safeERC20 as this contract is an upgradeable contract
-        if (!IERC20(staderConfig.getStaderToken()).transfer(payable(operator), _requestedSD)) {
+        if (!IERC20(_staderConfig.getStaderToken()).transfer(payable(operator), _requestedSD)) {
             revert SDTransferFailed();
         }

@@ -76,26 +77,27 @@ contract SDCollateral is ISDCollateral, Initializable, AccessControlUpgradeable,
     /// @dev callable only by respective withdrawVaults
     /// @param _validatorId validator SD collateral to slash
     function slashValidatorSD(uint256 _validatorId, uint8 _poolId) external override nonReentrant {
-        address operator = UtilLib.getOperatorForValidSender(_poolId, _validatorId, msg.sender, staderConfig);
-        isPoolThresholdValid(_poolId);
+        IStaderConfig _staderConfig = staderConfig;
+        address operator = UtilLib.getOperatorForValidSender(_poolId, _validatorId, msg.sender, _staderConfig);
         PoolThresholdInfo storage poolThreshold = poolThresholdbyPoolId[_poolId];
-        uint256 sdToSlash = convertETHToSD(poolThreshold.minThreshold);
-        slashSD(operator, sdToSlash);
+        isPoolThresholdValid(poolThreshold);
+        uint256 sdToSlash = _convertETHToSD(_staderConfig, poolThreshold.minThreshold);
+        slashSD(_staderConfig, operator, sdToSlash);
     }

     /// @notice used to slash operator SD, incase of operator default
     /// @dev do provide SD approval to auction contract using `maxApproveSD()`
     /// @param _operator which operator SD collateral to slash
     /// @param _sdToSlash amount of SD to slash
-    function slashSD(address _operator, uint256 _sdToSlash) internal {
+    function slashSD(IStaderConfig _staderConfig, address _operator, uint256 _sdToSlash) internal {
         uint256 sdBalance = operatorSDBalance[_operator];
         uint256 sdSlashed = Math.min(_sdToSlash, sdBalance);
         if (sdSlashed == 0) {
             return;
         }
-        operatorSDBalance[_operator] -= sdSlashed;
-        IAuction(staderConfig.getAuctionContract()).createLot(sdSlashed);
-        emit SDSlashed(_operator, staderConfig.getAuctionContract(), sdSlashed);
+        operatorSDBalance[_operator] = sdBalance - sdSlashed;
+        IAuction(_staderConfig.getAuctionContract()).createLot(sdSlashed);
+        emit SDSlashed(_operator, _staderConfig.getAuctionContract(), sdSlashed);
     }

     /// @notice for max approval to auction contract for spending SD tokens
@@ -142,10 +144,14 @@ contract SDCollateral is ISDCollateral, Initializable, AccessControlUpgradeable,

     // returns sum of withdraw threshold accounting for all its(op's) validators
     function getOperatorWithdrawThreshold(address _operator) public view returns (uint256 operatorWithdrawThreshold) {
-        (uint8 poolId, , uint256 validatorCount) = getOperatorInfo(_operator);
-        isPoolThresholdValid(poolId);
+        return _getOperatorWithdrawThreshold(staderConfig, _operator);
+    }
+
+    function _getOperatorWithdrawThreshold(IStaderConfig _staderConfig, address _operator) internal view returns (uint256 operatorWithdrawThreshold) {
+        (uint8 poolId, , uint256 validatorCount) = getOperatorInfo(_staderConfig, _operator);
         PoolThresholdInfo storage poolThreshold = poolThresholdbyPoolId[poolId];
-        return convertETHToSD(poolThreshold.withdrawThreshold * validatorCount);
+        isPoolThresholdValid(poolThreshold);
+        return _convertETHToSD(_staderConfig, poolThreshold.withdrawThreshold * validatorCount);
     }

     /// @notice checks if operator has enough SD collateral to onboard validators in a specific pool
@@ -169,8 +175,8 @@ contract SDCollateral is ISDCollateral, Initializable, AccessControlUpgradeable,
         override
         returns (uint256 _minSDToBond)
     {
-        isPoolThresholdValid(_poolId);
         PoolThresholdInfo storage poolThreshold = poolThresholdbyPoolId[_poolId];
+        isPoolThresholdValid(poolThreshold);

         _minSDToBond = convertETHToSD(poolThreshold.minThreshold);
         _minSDToBond *= _numValidator;
@@ -191,10 +197,10 @@ contract SDCollateral is ISDCollateral, Initializable, AccessControlUpgradeable,
     }

     function getRewardEligibleSD(address _operator) external view override returns (uint256 _rewardEligibleSD) {
-        (uint8 poolId, , uint256 validatorCount) = getOperatorInfo(_operator);
+        (uint8 poolId, , uint256 validatorCount) = getOperatorInfo(staderConfig, _operator);

-        isPoolThresholdValid(poolId);
         PoolThresholdInfo storage poolThreshold = poolThresholdbyPoolId[poolId];
+        isPoolThresholdValid(poolThreshold);

         uint256 totalMinThreshold = validatorCount * convertETHToSD(poolThreshold.minThreshold);
         uint256 totalMaxThreshold = validatorCount * convertETHToSD(poolThreshold.maxThreshold);
@@ -208,13 +214,17 @@ contract SDCollateral is ISDCollateral, Initializable, AccessControlUpgradeable,
     }

     function convertETHToSD(uint256 _ethAmount) public view override returns (uint256) {
-        uint256 sdPriceInETH = IStaderOracle(staderConfig.getStaderOracle()).getSDPriceInETH();
-        return (_ethAmount * staderConfig.getDecimals()) / sdPriceInETH;
+        return _convertETHToSD(staderConfig, _ethAmount);
+    }
+
+    function _convertETHToSD(IStaderConfig _staderConfig, uint256 _ethAmount) internal view returns (uint256) {
+        uint256 sdPriceInETH = IStaderOracle(_staderConfig.getStaderOracle()).getSDPriceInETH();
+        return (_ethAmount * _staderConfig.getDecimals()) / sdPriceInETH;
     }

     // HELPER

-    function getOperatorInfo(address _operator)
+    function getOperatorInfo(IStaderConfig _staderConfig, address _operator)
         internal
         view
         returns (
@@ -223,7 +233,7 @@ contract SDCollateral is ISDCollateral, Initializable, AccessControlUpgradeable,
             uint256 _validatorCount
         )
     {
-        IPoolUtils poolUtils = IPoolUtils(staderConfig.getPoolUtils());
+        IPoolUtils poolUtils = IPoolUtils(_staderConfig.getPoolUtils());
         _poolId = poolUtils.getOperatorPoolId(_operator);
         INodeRegistry nodeRegistry = INodeRegistry(poolUtils.getNodeRegistry(_poolId));
         _operatorId = nodeRegistry.operatorIDByAddress(_operator);
@@ -235,8 +245,8 @@ contract SDCollateral is ISDCollateral, Initializable, AccessControlUpgradeable,
         );
     }

-    function isPoolThresholdValid(uint8 _poolId) internal view {
-        if (bytes(poolThresholdbyPoolId[_poolId].units).length == 0) {
+    function isPoolThresholdValid(PoolThresholdInfo storage poolThreshold) internal view {
+        if (bytes(poolThreshold.units).length == 0) {
             revert InvalidPoolId();
         }
     }

Final diff for SocializingPool.sol

diff --git a/contracts/SocializingPool.sol b/contracts/SocializingPool.sol
index 19d8cb2..42d3cad 100644
--- a/contracts/SocializingPool.sol
+++ b/contracts/SocializingPool.sol
@@ -21,15 +21,20 @@ contract SocializingPool is
     PausableUpgradeable,
     ReentrancyGuardUpgradeable
 {
+    RewardsData public lastReportedRewardsData;
     IStaderConfig public override staderConfig;
     uint256 public override totalOperatorETHRewardsRemaining;
     uint256 public override totalOperatorSDRewardsRemaining;
     uint256 public override initialBlock;

+    struct RewardsInfo {
+        RewardsData rewardsDataMap;
+        bool handledRewards;
+    }
+
+    mapping(uint256 => RewardsInfo) rewardsInfo;
+
     mapping(address => mapping(uint256 => bool)) public override claimedRewards;
-    mapping(uint256 => bool) public handledRewards;
-    RewardsData public lastReportedRewardsData;
-    mapping(uint256 => RewardsData) public rewardsDataMap;

     /// @custom:oz-upgrades-unsafe-allow constructor
     constructor() {
@@ -60,29 +65,32 @@ contract SocializingPool is

     function handleRewards(RewardsData calldata _rewardsData) external override nonReentrant {
         UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.STADER_ORACLE());
-
-        if (handledRewards[_rewardsData.index]) {
+
+        RewardsInfo storage _rewardsInfo = rewardsInfo[_rewardsData.index];
+        if (_rewardsInfo.handledRewards) {
             revert RewardAlreadyHandled();
         }
+        uint256 _totalOperatorETHRewardsRemaining = totalOperatorSDRewardsRemaining;
         if (
             _rewardsData.operatorETHRewards + _rewardsData.userETHRewards + _rewardsData.protocolETHRewards >
-            address(this).balance - totalOperatorETHRewardsRemaining
+            address(this).balance - _totalOperatorETHRewardsRemaining
         ) {
             revert InsufficientETHRewards();
         }
+        uint256 _totalOperatorSDRewardsRemaining = totalOperatorSDRewardsRemaining;
         if (
             _rewardsData.operatorSDRewards >
-            IERC20(staderConfig.getStaderToken()).balanceOf(address(this)) - totalOperatorSDRewardsRemaining
+            IERC20(staderConfig.getStaderToken()).balanceOf(address(this)) - _totalOperatorSDRewardsRemaining
         ) {
             revert InsufficientSDRewards();
         }

-        handledRewards[_rewardsData.index] = true;
-        totalOperatorETHRewardsRemaining += _rewardsData.operatorETHRewards;
-        totalOperatorSDRewardsRemaining += _rewardsData.operatorSDRewards;
+        _rewardsInfo.handledRewards = true;
+        totalOperatorETHRewardsRemaining = _totalOperatorETHRewardsRemaining + _rewardsData.operatorETHRewards;
+        totalOperatorSDRewardsRemaining = _totalOperatorSDRewardsRemaining + _rewardsData.operatorSDRewards;

         lastReportedRewardsData = _rewardsData;
-        rewardsDataMap[_rewardsData.index] = _rewardsData;
+        _rewardsInfo.rewardsDataMap = _rewardsData;

         IStaderStakePoolManager(staderConfig.getStakePoolManager()).receiveExecutionLayerRewards{
             value: _rewardsData.userETHRewards
@@ -110,10 +118,9 @@ contract SocializingPool is
         uint256[] calldata _amountETH,
         bytes32[][] calldata _merkleProof
     ) external override nonReentrant whenNotPaused {
-        address operator = msg.sender;
-        (uint256 totalAmountSD, uint256 totalAmountETH) = _claim(_index, operator, _amountSD, _amountETH, _merkleProof);
+        (uint256 totalAmountSD, uint256 totalAmountETH) = _claim(_index, _amountSD, _amountETH, _merkleProof);

-        address operatorRewardsAddr = UtilLib.getOperatorRewardAddress(operator, staderConfig);
+        address operatorRewardsAddr = UtilLib.getOperatorRewardAddress(msg.sender, staderConfig);

         bool success;
         if (totalAmountETH > 0) {
@@ -136,45 +143,54 @@ contract SocializingPool is

     function _claim(
         uint256[] calldata _index,
-        address _operator,
         uint256[] calldata _amountSD,
         uint256[] calldata _amountETH,
         bytes32[][] calldata _merkleProof
     ) internal returns (uint256 _totalAmountSD, uint256 _totalAmountETH) {
         uint256 indexLength = _index.length;
+        mapping(uint256 => bool) storage _claimedRewards = claimedRewards[msg.sender];
         for (uint256 i = 0; i < indexLength; i++) {
             if (_amountSD[i] == 0 && _amountETH[i] == 0) {
                 revert InvalidAmount();
             }
-            if (claimedRewards[_operator][_index[i]]) {
-                revert RewardAlreadyClaimed(_operator, _index[i]);
+            if (_claimedRewards[_index[i]]) {
+                revert RewardAlreadyClaimed(msg.sender, _index[i]);
             }

             _totalAmountSD += _amountSD[i];
             _totalAmountETH += _amountETH[i];
-            claimedRewards[_operator][_index[i]] = true;
+            _claimedRewards[_index[i]] = true;

-            if (!verifyProof(_index[i], _operator, _amountSD[i], _amountETH[i], _merkleProof[i])) {
-                revert InvalidProof(_index[i], _operator);
+            if (!_verifyProof(_index[i], _amountSD[i], _amountETH[i], _merkleProof[i])) {
+                revert InvalidProof(_index[i], msg.sender);
             }
         }
     }

-    function verifyProof(
+    function _verifyProof(
         uint256 _index,
-        address _operator,
         uint256 _amountSD,
         uint256 _amountETH,
         bytes32[] calldata _merkleProof
-    ) public view returns (bool) {
+    ) internal view returns (bool) {
         if (_index == 0 || _index > lastReportedRewardsData.index) {
             revert InvalidCycleIndex();
         }
-        bytes32 merkleRoot = rewardsDataMap[_index].merkleRoot;
-        bytes32 node = keccak256(abi.encodePacked(_operator, _amountSD, _amountETH));
+        bytes32 merkleRoot = rewardsInfo[_index].rewardsDataMap.merkleRoot;
+        bytes32 node = keccak256(abi.encodePacked(msg.sender, _amountSD, _amountETH));
         return MerkleProofUpgradeable.verify(_merkleProof, merkleRoot, node);
     }

+    function verifyProof(
+        uint256 _index,
+        address _operator,
+        uint256 _amountSD,
+        uint256 _amountETH,
+        bytes32[] calldata _merkleProof
+    ) public view returns (bool) {
+        return _verifyProof(_index, _amountSD, _amountETH, _merkleProof);
+    }
+
     // SETTERS
     function updateStaderConfig(address _staderConfig) external override onlyRole(DEFAULT_ADMIN_ROLE) {
         UtilLib.checkNonZeroAddress(_staderConfig);
@@ -214,15 +230,16 @@ contract SocializingPool is
         }

         // for past cycles
-        _startBlock = rewardsDataMap[_index - 1].reportingBlockNumber + 1;
-        _endBlock = rewardsDataMap[_index].reportingBlockNumber;
+        _startBlock = rewardsInfo[_index - 1].rewardsDataMap.reportingBlockNumber + 1;
+        _endBlock = rewardsInfo[_index].rewardsDataMap.reportingBlockNumber;

         // for current cycle
-        if (rewardsDataMap[_index].reportingBlockNumber == 0) {
-            if (rewardsDataMap[_index - 1].reportingBlockNumber == 0) {
+        if (rewardsInfo[_index].rewardsDataMap.reportingBlockNumber == 0) {
+            if (rewardsInfo[_index - 1].rewardsDataMap.reportingBlockNumber == 0) {
                 revert FutureCycleIndex();
             }
-            _endBlock = rewardsDataMap[_index - 1].reportingBlockNumber + cycleDuration;
+            _endBlock = rewardsInfo[_index - 1].rewardsDataMap.reportingBlockNumber + cycleDuration;
         }
     }
 }

Final diff for StaderOracle.sol

diff --git a/contracts/StaderOracle.sol b/contracts/StaderOracle.sol
index ba007c5..7078a04 100644
--- a/contracts/StaderOracle.sol
+++ b/contracts/StaderOracle.sol
@@ -17,10 +17,10 @@ import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.
 contract StaderOracle is IStaderOracle, AccessControlUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable {
     bool public override erInspectionMode;
     bool public override isPORFeedBasedERData;
-    SDPriceData public lastReportedSDPriceData;
+    uint40 public override erInspectionModeStartBlock;
     IStaderConfig public override staderConfig;
-    ExchangeRate public inspectionModeExchangeRate;
     ExchangeRate public exchangeRate;
+    SDPriceData public lastReportedSDPriceData;
     ValidatorStats public validatorStats;

     uint256 public constant MAX_ER_UPDATE_FREQUENCY = 7200 * 7; // 7 days
@@ -29,16 +29,13 @@ contract StaderOracle is IStaderOracle, AccessControlUpgradeable, PausableUpgrad
     uint256 public constant MIN_TRUSTED_NODES = 5;

     /// @inheritdoc IStaderOracle
-    uint256 public override reportingBlockNumberForWithdrawnValidators;
+    bool public override safeMode;
+    uint208 public override reportingBlockNumberForWithdrawnValidators;
+    ExchangeRate public inspectionModeExchangeRate;
     /// @inheritdoc IStaderOracle
     uint256 public override trustedNodesCount;
     /// @inheritdoc IStaderOracle
     uint256 public override lastReportedMAPDIndex;
-    uint256 public override erInspectionModeStartBlock;
-
-    // indicate the health of protocol on beacon chain
-    // enabled by `MANAGER` if heavy slashing on protocol on beacon chain
-    bool public override safeMode;

     /// @inheritdoc IStaderOracle
     mapping(address => bool) public override isTrustedNode;
@@ -432,7 +429,7 @@ contract StaderOracle is IStaderOracle, AccessControlUpgradeable, PausableUpgrad
             submissionCount == trustedNodesCount / 2 + 1 &&
             _withdrawnValidators.reportingBlockNumber > reportingBlockNumberForWithdrawnValidators
         ) {
-            reportingBlockNumberForWithdrawnValidators = _withdrawnValidators.reportingBlockNumber;
+            reportingBlockNumberForWithdrawnValidators = uint208(_withdrawnValidators.reportingBlockNumber);
             INodeRegistry(_withdrawnValidators.nodeRegistry).withdrawnValidators(_withdrawnValidators.sortedPubkeys);

             // Emit withdrawn validators updated event
@@ -626,8 +623,9 @@ contract StaderOracle is IStaderOracle, AccessControlUpgradeable, PausableUpgrad
             revert DuplicateSubmissionFromNode();
         }
         nodeSubmissionKeys[_nodeSubmissionKey] = true;
-        submissionCountKeys[_submissionCountKey]++;
-        _submissionCount = submissionCountKeys[_submissionCountKey];
+        uint8 submissionCountKeyUpdated = submissionCountKeys[_submissionCountKey] + 1;
+        submissionCountKeys[_submissionCountKey] = submissionCountKeyUpdated;
+        _submissionCount = submissionCountKeyUpdated;
     }

     function getSDPriceInETH() external view override returns (uint256) {
@@ -666,10 +664,10 @@ contract StaderOracle is IStaderOracle, AccessControlUpgradeable, PausableUpgrad
                 newExchangeRate <= ((currentExchangeRate * (ER_CHANGE_MAX_BPS + erChangeLimit)) / ER_CHANGE_MAX_BPS))
         ) {
             erInspectionMode = true;
-            erInspectionModeStartBlock = block.number;
+            erInspectionModeStartBlock = uint40(block.number);
             inspectionModeExchangeRate.totalETHBalance = _newTotalETHBalance;
             inspectionModeExchangeRate.totalETHXSupply = _newTotalETHXSupply;
-            inspectionModeExchangeRate.reportingBlockNumber = _reportingBlockNumber;
+            inspectionModeExchangeRate.reportingBlockNumber = uint40(_reportingBlockNumber);
             emit ERInspectionModeActivated(erInspectionMode, block.timestamp);
             return;
         }
@@ -683,7 +681,7 @@ contract StaderOracle is IStaderOracle, AccessControlUpgradeable, PausableUpgrad
     ) internal {
         exchangeRate.totalETHBalance = _totalETHBalance;
         exchangeRate.totalETHXSupply = _totalETHXSupply;
-        exchangeRate.reportingBlockNumber = _reportingBlockNumber;
+        exchangeRate.reportingBlockNumber = uint40(_reportingBlockNumber);

         // Emit balances updated event
         emit ExchangeRateUpdated(

Final diff for StaderStakePoolsManager.sol

diff --git a/contracts/StaderStakePoolsManager.sol b/contracts/StaderStakePoolsManager.sol
index c4bb7d5..9ebddd5 100644
--- a/contracts/StaderStakePoolsManager.sol
+++ b/contracts/StaderStakePoolsManager.sol
@@ -35,8 +35,8 @@ contract StaderStakePoolsManager is
     using Math for uint256;
     using SafeMath for uint256;
     IStaderConfig public staderConfig;
-    uint256 public lastExcessETHDepositBlock;
-    uint256 public excessETHDepositCoolDown;
+    uint48 public lastExcessETHDepositBlock;
+    uint48 public excessETHDepositCoolDown;

     /// @custom:oz-upgrades-unsafe-allow constructor
     constructor() {
@@ -53,7 +53,7 @@ contract StaderStakePoolsManager is
         __AccessControl_init();
         __Pausable_init();
         __ReentrancyGuard_init();
-        lastExcessETHDepositBlock = block.number;
+        lastExcessETHDepositBlock = uint48(block.number);
         excessETHDepositCoolDown = 3 * 7200;
         staderConfig = IStaderConfig(_staderConfig);
         _grantRole(DEFAULT_ADMIN_ROLE, _admin);
@@ -108,7 +108,7 @@ contract StaderStakePoolsManager is

     function updateExcessETHDepositCoolDown(uint256 _excessETHDepositCoolDown) external {
         UtilLib.onlyManagerRole(msg.sender, staderConfig);
-        excessETHDepositCoolDown = _excessETHDepositCoolDown;
+        excessETHDepositCoolDown = uint48(_excessETHDepositCoolDown);
         emit UpdatedExcessETHDepositCoolDown(_excessETHDepositCoolDown);
     }

@@ -238,7 +238,7 @@ contract StaderStakePoolsManager is
             uint256 poolDepositSize = staderConfig.getStakedEthPerNode() -
                 IPoolUtils(poolUtils).getCollateralETH(poolIdArray[i]);

-            lastExcessETHDepositBlock = block.number;
+            lastExcessETHDepositBlock = uint48(block.number);
             //slither-disable-next-line arbitrary-send-eth
             IStaderPoolBase(poolAddress).stakeUserETHToBeaconChain{value: validatorToDeposit * poolDepositSize}();
             emit ETHTransferredToPool(i, poolAddress, validatorToDeposit * poolDepositSize);

Final diff for ISocializingPool.sol

diff --git a/contracts/interfaces/ISocializingPool.sol b/contracts/interfaces/ISocializingPool.sol
index aceee8b..ab49093 100644
--- a/contracts/interfaces/ISocializingPool.sol
+++ b/contracts/interfaces/ISocializingPool.sol
@@ -7,14 +7,10 @@ import './IStaderConfig.sol';
 /// @title RewardsData
 /// @notice This struct holds rewards merkleRoot and rewards split
 struct RewardsData {
-    /// @notice The block number when the rewards data was last updated
-    uint256 reportingBlockNumber;
     /// @notice The index of merkle tree or rewards cycle
     uint256 index;
     /// @notice The merkle root hash
     bytes32 merkleRoot;
-    /// @notice pool id of operators
-    uint8 poolId;
     /// @notice operator ETH rewards for index cycle
     uint256 operatorETHRewards;
     /// @notice user ETH rewards for index cycle
@@ -23,6 +19,10 @@ struct RewardsData {
     uint256 protocolETHRewards;
     /// @notice operator SD rewards for index cycle
     uint256 operatorSDRewards;
+    /// @notice pool id of operators
+    uint8 poolId;
+    /// @notice The block number when the rewards data was last updated
+    uint48 reportingBlockNumber;
 }

Final diff for IStaderOracle.sol

diff --git a/contracts/interfaces/IStaderOracle.sol b/contracts/interfaces/IStaderOracle.sol
index d514c32..6f68195 100644
--- a/contracts/interfaces/IStaderOracle.sol
+++ b/contracts/interfaces/IStaderOracle.sol
@@ -31,7 +31,7 @@ struct MissedAttestationReportInfo {
 /// @notice This struct holds data related to the exchange rate between ETH and ETHX.
 struct ExchangeRate {
     /// @notice The block number when the exchange rate was last updated.
-    uint256 reportingBlockNumber;
+    uint40 reportingBlockNumber;
     /// @notice The total balance of Ether (ETH) in the system.
     uint256 totalETHBalance;
     /// @notice The total supply of the liquid staking token (ETHX) in the system.
@@ -247,7 +247,7 @@ interface IStaderOracle {

     function erChangeLimit() external view returns (uint256);

-    function reportingBlockNumberForWithdrawnValidators() external view returns (uint256);
+    function reportingBlockNumberForWithdrawnValidators() external view returns (uint208);

     // returns the count of trusted nodes
     function trustedNodesCount() external view returns (uint256);
@@ -255,7 +255,7 @@ interface IStaderOracle {
     //returns the latest consensus index for missed attestation penalty data report
     function lastReportedMAPDIndex() external view returns (uint256);

-    function erInspectionModeStartBlock() external view returns (uint256);
+    function erInspectionModeStartBlock() external view returns (uint40);

     function safeMode() external view returns (bool);

Final diff for IStaderPoolBase.sol

diff --git a/contracts/interfaces/IStaderPoolBase.sol b/contracts/interfaces/IStaderPoolBase.sol
index f0fdcc0..57ae0f4 100644
--- a/contracts/interfaces/IStaderPoolBase.sol
+++ b/contracts/interfaces/IStaderPoolBase.sol
@@ -24,9 +24,9 @@ interface IStaderPoolBase {

     //Getters

-    function protocolFee() external view returns (uint256); // returns the protocol fee
+    function protocolFee() external view returns (uint48); // returns the protocol fee

-    function operatorFee() external view returns (uint256); // returns the operator fee
+    function operatorFee() external view returns (uint48); // returns the operator fee

     function getTotalActiveValidatorCount() external view returns (uint256); // returns the total number of active validators across all operators

Final diff for UserWithdrawalManager.sol

diff --git a/contracts/UserWithdrawalManager.sol b/contracts/UserWithdrawalManager.sol
index f563434..eb346e1 100644
--- a/contracts/UserWithdrawalManager.sol
+++ b/contracts/UserWithdrawalManager.sol
@@ -40,10 +40,10 @@ contract UserWithdrawalManager is
     /// @notice structure representing a user request for withdrawal.
     struct UserWithdrawInfo {
         address payable owner; // address that can claim eth on behalf of this request
+        uint96 requestBlock; // block number of withdraw request
         uint256 ethXAmount; //amount of ethX share locked for withdrawal
         uint256 ethExpected; //eth requested according to given share and exchangeRate
         uint256 ethFinalized; // final eth for claiming according to finalize exchange rate
-        uint256 requestBlock; // block number of withdraw request
     }

     /// @custom:oz-upgrades-unsafe-allow constructor
@@ -98,13 +98,14 @@ contract UserWithdrawalManager is
         if (assets < staderConfig.getMinWithdrawAmount() || assets > staderConfig.getMaxWithdrawAmount()) {
             revert InvalidWithdrawAmount();
         }
-        if (requestIdsByUserAddress[_owner].length + 1 > maxNonRedeemedUserRequestCount) {
+        uint256[] storage _requestIdsByUserAddress = requestIdsByUserAddress[_owner];
+        if (_requestIdsByUserAddress.length + 1 > maxNonRedeemedUserRequestCount) {
             revert MaxLimitOnWithdrawRequestCountReached();
         }
         IERC20Upgradeable(staderConfig.getETHxToken()).safeTransferFrom(msg.sender, (address(this)), _ethXAmount);
         ethRequestedForWithdraw += assets;
-        userWithdrawRequests[nextRequestId] = UserWithdrawInfo(payable(_owner), _ethXAmount, assets, 0, block.number);
-        requestIdsByUserAddress[_owner].push(nextRequestId);
+        userWithdrawRequests[nextRequestId] = UserWithdrawInfo(payable(_owner), uint96(block.number), _ethXAmount, assets, 0);
+        _requestIdsByUserAddress.push(nextRequestId);
         emit WithdrawRequestReceived(msg.sender, _owner, nextRequestId, _ethXAmount, assets);
         nextRequestId++;
         return nextRequestId - 1;
@@ -128,21 +129,22 @@ contract UserWithdrawalManager is
         uint256 lockedEthXToBurn;
         uint256 ethToSendToFinalizeRequest;
         uint256 requestId;
+        uint256 requiredEth;
+        uint256 minBlockDelay = staderConfig.getMinBlockDelayToFinalizeWithdrawRequest();
         uint256 pooledETH = poolManager.balance;
         for (requestId = nextRequestIdToFinalize; requestId <= maxRequestIdToFinalize; ) {
             UserWithdrawInfo memory userWithdrawInfo = userWithdrawRequests[requestId];
-            uint256 requiredEth = userWithdrawInfo.ethExpected;
             uint256 lockedEthX = userWithdrawInfo.ethXAmount;
-            uint256 minEThRequiredToFinalizeRequest = Math.min(requiredEth, (lockedEthX * exchangeRate) / DECIMALS);
+            uint256 minEThRequiredToFinalizeRequest = Math.min(userWithdrawInfo.ethExpected, (lockedEthX * exchangeRate) / DECIMALS);
             if (
                 (ethToSendToFinalizeRequest + minEThRequiredToFinalizeRequest > pooledETH) ||
-                (userWithdrawInfo.requestBlock + staderConfig.getMinBlockDelayToFinalizeWithdrawRequest() >
+                (userWithdrawInfo.requestBlock + minBlockDelay >
                     block.number)
             ) {
                 break;
             }
             userWithdrawRequests[requestId].ethFinalized = minEThRequiredToFinalizeRequest;
-            ethRequestedForWithdraw -= requiredEth;
+            requiredEth += userWithdrawInfo.ethExpected;
             lockedEthXToBurn += lockedEthX;
             ethToSendToFinalizeRequest += minEThRequiredToFinalizeRequest;
             unchecked {
@@ -151,6 +153,7 @@ contract UserWithdrawalManager is
         }
         // at here, upto (requestId-1) is finalized
         if (requestId > nextRequestIdToFinalize) {
+            ethRequestedForWithdraw = ethRequestedForWithdraw - requiredEth;
             nextRequestIdToFinalize = requestId;
             ETHx(staderConfig.getETHxToken()).burnFrom(address(this), lockedEthXToBurn);
             IStaderStakePoolManager(poolManager).transferETHToUserWithdrawManager(ethToSendToFinalizeRequest);
@@ -166,8 +169,9 @@ contract UserWithdrawalManager is
         if (_requestId >= nextRequestIdToFinalize) {
             revert requestIdNotFinalized(_requestId);
         }
-        UserWithdrawInfo memory userRequest = userWithdrawRequests[_requestId];
-        if (msg.sender != userRequest.owner) {
+        UserWithdrawInfo storage userRequest = userWithdrawRequests[_requestId];
+        address payable _owner = userRequest.owner;
+        if (msg.sender != _owner) {
             revert CallerNotAuthorizedToRedeem();
         }
         // below is a default entry as no userRequest will be found for a redeemed request.
@@ -175,9 +179,9 @@ contract UserWithdrawalManager is
             revert RequestAlreadyRedeemed(_requestId);
         }
         uint256 etherToTransfer = userRequest.ethFinalized;
-        deleteRequestId(_requestId, userRequest.owner);
-        sendValue(userRequest.owner, etherToTransfer);
-        emit RequestRedeemed(msg.sender, userRequest.owner, etherToTransfer);
+        deleteRequestId(_requestId, _owner);
+        sendValue(_owner, etherToTransfer);
+        emit RequestRedeemed(msg.sender, _owner, etherToTransfer);
     }

     /// @notice return the list of ongoing withdraw requestIds for a user
@@ -205,8 +209,8 @@ contract UserWithdrawalManager is
     // delete entry from userWithdrawRequests mapping and in requestIdsByUserAddress mapping
     function deleteRequestId(uint256 _requestId, address _owner) internal {
         delete (userWithdrawRequests[_requestId]);
-        uint256 userRequestCount = requestIdsByUserAddress[_owner].length;
         uint256[] storage requestIds = requestIdsByUserAddress[_owner];
+        uint256 userRequestCount = requestIds.length;
         for (uint256 i; i < userRequestCount; ) {
             if (_requestId == requestIds[i]) {
                 requestIds[i] = requestIds[userRequestCount - 1];

Final diff for IUserWithdrawalManager.sol

diff --git a/contracts/interfaces/IUserWithdrawalManager.sol b/contracts/interfaces/IUserWithdrawalManager.sol
index 82fc86b..bd5a574 100644
--- a/contracts/interfaces/IUserWithdrawalManager.sol
+++ b/contracts/interfaces/IUserWithdrawalManager.sol
@@ -52,10 +52,10 @@ interface IUserWithdrawalManager {
         view
         returns (
             address payable owner,
+            uint96 requestTime,
             uint256 ethXAmount,
             uint256 ethExpected,
-            uint256 ethFinalized,
-            uint256 requestTime
+            uint256 ethFinalized
         );

Final diff for ValidatorWithdrawalVault.sol

diff --git a/contracts/ValidatorWithdrawalVault.sol b/contracts/ValidatorWithdrawalVault.sol
index eb3de50..0f065b4 100644
--- a/contracts/ValidatorWithdrawalVault.sol
+++ b/contracts/ValidatorWithdrawalVault.sol
@@ -1,7 +1,6 @@
 // SPDX-License-Identifier: MIT
 pragma solidity 0.8.16;

-import './library/UtilLib.sol';
 import './library/ValidatorStatus.sol';

 import './VaultProxy.sol';
@@ -28,9 +27,19 @@ contract ValidatorWithdrawalVault is IValidatorWithdrawalVault {
     }

     function distributeRewards() external override {
-        uint8 poolId = VaultProxy(payable(address(this))).poolId();
-        uint256 validatorId = VaultProxy(payable(address(this))).id();
-        IStaderConfig staderConfig = VaultProxy(payable(address(this))).staderConfig();
+        uint8 poolId;
+        uint256 validatorId;
+        IStaderConfig staderConfig;
+        assembly {
+            // sigs for "poolId()" + "id()" + "staderConfig()"
+            mstore(0x00, 0x490ffa35af640d0f3e0dc34e)
+            if iszero(staticcall(gas(), address(), 0x1c, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            poolId := mload(0x20)
+            if iszero(staticcall(gas(), address(), 0x18, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            validatorId := mload(0x20)
+            if iszero(staticcall(gas(), address(), 0x14, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            staderConfig := mload(0x20)
+        }
         uint256 totalRewards = address(this).balance;
         if (!staderConfig.onlyOperatorRole(msg.sender) && totalRewards > staderConfig.getRewardsThreshold()) {
             emit DistributeRewardFailed(totalRewards, staderConfig.getRewardsThreshold());
@@ -39,29 +48,46 @@ contract ValidatorWithdrawalVault is IValidatorWithdrawalVault {
         if (totalRewards == 0) {
             revert NotEnoughRewardToDistribute();
         }
-        (uint256 userShare, uint256 operatorShare, uint256 protocolShare) = IPoolUtils(staderConfig.getPoolUtils())
-            .calculateRewardShare(poolId, totalRewards);
+        IPoolUtils poolUtils = IPoolUtils(staderConfig.getPoolUtils());
+        (uint256 userShare, uint256 operatorShare, uint256 protocolShare) = poolUtils.calculateRewardShare(poolId, totalRewards);

         // Distribute rewards
         IStaderStakePoolManager(staderConfig.getStakePoolManager()).receiveWithdrawVaultUserShare{value: userShare}();
         UtilLib.sendValue(payable(staderConfig.getStaderTreasury()), protocolShare);
         IOperatorRewardsCollector(staderConfig.getOperatorRewardsCollector()).depositFor{value: operatorShare}(
-            getOperatorAddress(poolId, validatorId, staderConfig)
+            getOperatorAddress(validatorId, poolUtils.getNodeRegistry(poolId))
         );
         emit DistributedRewards(userShare, operatorShare, protocolShare);
     }

     function settleFunds() external override {
-        uint8 poolId = VaultProxy(payable(address(this))).poolId();
-        uint256 validatorId = VaultProxy(payable(address(this))).id();
-        IStaderConfig staderConfig = VaultProxy(payable(address(this))).staderConfig();
-        address nodeRegistry = IPoolUtils(staderConfig.getPoolUtils()).getNodeRegistry(poolId);
+        uint8 poolId;
+        uint256 validatorId;
+        IStaderConfig staderConfig;
+        IPoolUtils poolUtils;
+        address nodeRegistry;
+        assembly {
+            // sigs for "getNodeRegistry(uint8)" + "poolId()" + "id()" + "staderConfig()" + "getPoolUtils()"
+            mstore(0x00, 0x6ccb9d70490ffa35af640d0f3e0dc34e99d055c8)
+            if iszero(staticcall(gas(), address(), 0x18, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            poolId := mload(0x20)
+            if iszero(staticcall(gas(), address(), 0x14, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            validatorId := mload(0x20)
+            if iszero(staticcall(gas(), address(), 0x10, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            staderConfig := mload(0x20)
+            if iszero(staticcall(gas(), staderConfig, 0xc, 0x04, 0x20, 0x20)) {revert(0, 0)}
+            poolUtils := mload(0x20)
+            mstore(0x20, poolId)
+            if iszero(staticcall(gas(), poolUtils, 0x1c, 0x24, 0x20, 0x20)) {revert(0, 0)}
+            nodeRegistry := mload(0x20)
+        }
         if (msg.sender != nodeRegistry) {
             revert CallerNotNodeRegistryContract();
         }
-        (uint256 userSharePrelim, uint256 operatorShare, uint256 protocolShare) = calculateValidatorWithdrawalShare();
+        (uint256 userSharePrelim, uint256 operatorShare, uint256 protocolShare) = _calculateValidatorWithdrawalShare(staderConfig, poolId, poolUtils);

-        uint256 penaltyAmount = getUpdatedPenaltyAmount(poolId, validatorId, staderConfig);
+        IPenalty penalty = IPenalty(staderConfig.getPenaltyContract());
+        uint256 penaltyAmount = getUpdatedPenaltyAmount(validatorId, nodeRegistry, penalty);

         if (operatorShare < penaltyAmount) {
             ISDCollateral(staderConfig.getSDCollateral()).slashValidatorSD(validatorId, poolId);
@@ -73,11 +99,11 @@ contract ValidatorWithdrawalVault is IValidatorWithdrawalVault {

         // Final settlement
         vaultSettleStatus = true;
-        IPenalty(staderConfig.getPenaltyContract()).markValidatorSettled(poolId, validatorId);
+        penalty.markValidatorSettled(poolId, validatorId);
         IStaderStakePoolManager(staderConfig.getStakePoolManager()).receiveWithdrawVaultUserShare{value: userShare}();
         UtilLib.sendValue(payable(staderConfig.getStaderTreasury()), protocolShare);
         IOperatorRewardsCollector(staderConfig.getOperatorRewardsCollector()).depositFor{value: operatorShare}(
-            getOperatorAddress(poolId, validatorId, staderConfig)
+            getOperatorAddress(validatorId, nodeRegistry)
         );
         emit SettledFunds(userShare, operatorShare, protocolShare);
     }
@@ -91,10 +117,25 @@ contract ValidatorWithdrawalVault is IValidatorWithdrawalVault {
             uint256 _protocolShare
         )
     {
-        uint8 poolId = VaultProxy(payable(address(this))).poolId();
         IStaderConfig staderConfig = VaultProxy(payable(address(this))).staderConfig();
+        return _calculateValidatorWithdrawalShare(
+            staderConfig,
+            VaultProxy(payable(address(this))).poolId(),
+            IPoolUtils(staderConfig.getPoolUtils())
+        );
+    }
+
+    function _calculateValidatorWithdrawalShare(IStaderConfig staderConfig, uint8 poolId, IPoolUtils poolUtils)
+        internal
+        view
+        returns (
+            uint256 _userShare,
+            uint256 _operatorShare,
+            uint256 _protocolShare
+        )
+    {
         uint256 TOTAL_STAKED_ETH = staderConfig.getStakedEthPerNode();
-        uint256 collateralETH = getCollateralETH(poolId, staderConfig); // 0, incase of permissioned NOs
+        uint256 collateralETH = getCollateralETH(poolId, poolUtils); // 0, incase of permissioned NOs
         uint256 usersETH = TOTAL_STAKED_ETH - collateralETH;
         uint256 contractBalance = address(this).balance;

@@ -113,9 +154,7 @@ contract ValidatorWithdrawalVault is IValidatorWithdrawalVault {
             _userShare = usersETH;
         }
         if (totalRewards > 0) {
-            (uint256 userReward, uint256 operatorReward, uint256 protocolReward) = IPoolUtils(
-                staderConfig.getPoolUtils()
-            ).calculateRewardShare(poolId, totalRewards);
+            (uint256 userReward, uint256 operatorReward, uint256 protocolReward) = poolUtils.calculateRewardShare(poolId, totalRewards);
             _userShare += userReward;
             _operatorShare += operatorReward;
             _protocolShare += protocolReward;
@@ -124,28 +163,28 @@ contract ValidatorWithdrawalVault is IValidatorWithdrawalVault {

     // HELPER METHODS

-    function getCollateralETH(uint8 _poolId, IStaderConfig _staderConfig) internal view returns (uint256) {
-        return IPoolUtils(_staderConfig.getPoolUtils()).getCollateralETH(_poolId);
+    function getCollateralETH(uint8 _poolId, IPoolUtils poolUtils) internal view returns (uint256) {
+        return poolUtils.getCollateralETH(_poolId);
     }

     function getOperatorAddress(
-        uint8 _poolId,
         uint256 _validatorId,
-        IStaderConfig _staderConfig
+        address nodeRegistry
     ) internal view returns (address) {
-        return UtilLib.getOperatorAddressByValidatorId(_poolId, _validatorId, _staderConfig);
+        (, , , , uint256 operatorId, , , ) = INodeRegistry(nodeRegistry).validatorRegistry(_validatorId);
+        (, , , , address operatorAddress) = INodeRegistry(nodeRegistry).operatorStructById(operatorId);
+        return operatorAddress;
     }

     function getUpdatedPenaltyAmount(
-        uint8 _poolId,
         uint256 _validatorId,
-        IStaderConfig _staderConfig
+        address nodeRegistry,
+        IPenalty penalty
     ) internal returns (uint256) {
-        address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
         (, bytes memory pubkey, , , , , , ) = INodeRegistry(nodeRegistry).validatorRegistry(_validatorId);
         bytes[] memory pubkeyArray = new bytes[](1);
         pubkeyArray[0] = pubkey;
-        IPenalty(_staderConfig.getPenaltyContract()).updateTotalPenaltyAmount(pubkeyArray);
-        return IPenalty(_staderConfig.getPenaltyContract()).totalPenaltyAmount(pubkey);
+        penalty.updateTotalPenaltyAmount(pubkeyArray);
+        return penalty.totalPenaltyAmount(pubkey);
     }
 }

Final diff for UtilLib.sol

diff --git a/contracts/library/UtilLib.sol b/contracts/library/UtilLib.sol
index 75b2bc2..11e1fbc 100644
--- a/contracts/library/UtilLib.sol
+++ b/contracts/library/UtilLib.sol
@@ -53,7 +53,7 @@ library UtilLib {
         IStaderConfig _staderConfig
     ) internal view returns (bytes memory) {
         address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
-        (, bytes memory pubkey, , , address withdrawVaultAddress, , , ) = INodeRegistry(nodeRegistry).validatorRegistry(
+        (, bytes memory pubkey, , , , address withdrawVaultAddress, , ) = INodeRegistry(nodeRegistry).validatorRegistry(
             _validatorId
         );
         if (_addr != withdrawVaultAddress) {
@@ -69,7 +69,7 @@ library UtilLib {
         IStaderConfig _staderConfig
     ) internal view returns (address) {
         address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
-        (, , , , address withdrawVaultAddress, uint256 operatorId, , ) = INodeRegistry(nodeRegistry).validatorRegistry(
+        (, , , , uint256 operatorId, address withdrawVaultAddress, , ) = INodeRegistry(nodeRegistry).validatorRegistry(
             _validatorId
         );
         if (_addr != withdrawVaultAddress) {
@@ -86,7 +86,7 @@ library UtilLib {
         IStaderConfig _staderConfig
     ) internal view {
         address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
-        (, , , , address withdrawVaultAddress, , , ) = INodeRegistry(nodeRegistry).validatorRegistry(_validatorId);
+        (, , , , , address withdrawVaultAddress, , ) = INodeRegistry(nodeRegistry).validatorRegistry(_validatorId);
         if (_addr != withdrawVaultAddress) {
             revert CallerNotWithdrawVault();
         }
@@ -98,7 +98,7 @@ library UtilLib {
         IStaderConfig _staderConfig
     ) internal view returns (address) {
         address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
-        (, , , , , uint256 operatorId, , ) = INodeRegistry(nodeRegistry).validatorRegistry(_validatorId);
+        (, , , , uint256 operatorId, , , ) = INodeRegistry(nodeRegistry).validatorRegistry(_validatorId);
         (, , , , address operatorAddress) = INodeRegistry(nodeRegistry).operatorStructById(operatorId);

         return operatorAddress;
@@ -148,7 +148,7 @@ library UtilLib {
         uint8 poolId = IPoolUtils(_staderConfig.getPoolUtils()).getValidatorPoolId(_pubkey);
         address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(poolId);
         uint256 validatorId = INodeRegistry(nodeRegistry).validatorIdByPubkey(_pubkey);
-        (, , , , address withdrawVaultAddress, , , ) = INodeRegistry(nodeRegistry).validatorRegistry(validatorId);
+        (, , , , , address withdrawVaultAddress, , ) = INodeRegistry(nodeRegistry).validatorRegistry(validatorId);
         return IVaultProxy(withdrawVaultAddress).vaultSettleStatus();
     }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment