diff --git a/contracts/Escrow.sol b/contracts/Escrow.sol index 9c24f542..24fd9130 100644 --- a/contracts/Escrow.sol +++ b/contracts/Escrow.sol @@ -19,13 +19,11 @@ import {EscrowState} from "./libraries/EscrowState.sol"; import {WithdrawalsBatchesQueue} from "./libraries/WithdrawalBatchesQueue.sol"; import {HolderAssets, StETHAccounting, UnstETHAccounting, AssetsAccounting} from "./libraries/AssetsAccounting.sol"; -/// @notice Summary of the total locked assets in the Escrow -/// @param stETHLockedShares Total number of stETH shares locked in the Escrow -/// @param stETHClaimedETH Total amount of ETH claimed from the stETH locked in the Escrow -/// @param unstETHUnfinalizedShares Total number of shares from unstETH NFTs that have not yet been -/// marked as finalized -/// @param unstETHFinalizedETH Total claimable amount of ETH from unstETH NFTs that have been marked -/// as finalized +/// @notice Summary of the total locked assets in the Escrow. +/// @param stETHLockedShares The total number of stETH shares currently locked in the Escrow. +/// @param stETHClaimedETH The total amount of ETH claimed from the stETH shares locked in the Escrow. +/// @param unstETHUnfinalizedShares The total number of shares from unstETH NFTs that have not yet been marked as finalized. +/// @param unstETHFinalizedETH The total amount of ETH claimable from unstETH NFTs that have been marked as finalized. struct LockedAssetsTotals { uint256 stETHLockedShares; uint256 stETHClaimedETH; @@ -33,6 +31,11 @@ struct LockedAssetsTotals { uint256 unstETHFinalizedETH; } +/// @notice Summary of the assets locked in the Escrow by a specific vetoer. +/// @param stETHLockedShares The total number of stETH shares currently locked in the Escrow by the vetoer. +/// @param unstETHLockedShares The total number of unstETH shares currently locked in the Escrow by the vetoer. +/// @param unstETHIdsCount The total number of unstETH NFTs locked in the Escrow by the vetoer. +/// @param lastAssetsLockTimestamp The timestamp of the last time the vetoer locked stETH, wstETH, or unstETH in the Escrow. struct VetoerState { uint256 stETHLockedShares; uint256 unstETHLockedShares; @@ -40,6 +43,9 @@ struct VetoerState { uint256 lastAssetsLockTimestamp; } +/// @notice This contract is used to accumulate stETH, wstETH, unstETH, and withdrawn ETH from vetoers during the +/// veto signalling and rage quit processes. +/// @dev This contract is intended to be used behind a minimal proxy deployed by the DualGovernance contract. contract Escrow is IEscrow { using EscrowState for EscrowState.Context; using AssetsAccounting for AssetsAccounting.Context; @@ -48,12 +54,12 @@ contract Escrow is IEscrow { // --- // Errors // --- + error EmptyUnstETHIds(); error UnclaimedBatches(); error UnexpectedUnstETHId(); error UnfinalizedUnstETHIds(); error NonProxyCallsForbidden(); error BatchesQueueIsNotClosed(); - error EmptyUnstETHIds(); error InvalidBatchSize(uint256 size); error CallerIsNotDualGovernance(address caller); error InvalidHintsLength(uint256 actual, uint256 expected); @@ -64,40 +70,57 @@ contract Escrow is IEscrow { // --- /// @dev The lower limit for stETH transfers when requesting a withdrawal batch - /// during the Rage Quit phase. For more details, see https://github.com/lidofinance/lido-dao/issues/442. - /// The current value is chosen to ensure functionality over an extended period, spanning several decades. + /// during the Rage Quit phase. For more details, see https://github.com/lidofinance/lido-dao/issues/442. + /// The current value is chosen to ensure functionality over an extended period, spanning several decades. uint256 private constant _MIN_TRANSFERRABLE_ST_ETH_AMOUNT = 8 wei; // --- - // Sanity check params immutables + // Sanity Check Parameters & Immutables // --- + /// @notice The minimum number of withdrawal requests allowed to create during a single call of + /// the `Escrow.requestNextWithdrawalsBatch(batchSize)` method. uint256 public immutable MIN_WITHDRAWALS_BATCH_SIZE; // --- - // Dependencies immutables + // Dependencies Immutables // --- + /// @notice The address of the stETH token. IStETH public immutable ST_ETH; + + /// @notice The address of the wstETH token. IWstETH public immutable WST_ETH; + + /// @notice The address of Lido's Withdrawal Queue and the unstETH token. IWithdrawalQueue public immutable WITHDRAWAL_QUEUE; // --- - // Implementation immutables + // Implementation Immutables + // --- + /// @dev Reference to the address of the implementation contract, used to distinguish whether the call + /// is made to the proxy or directly to the implementation. address private immutable _SELF; + + /// @dev The address of the Dual Governance contract. IDualGovernance public immutable DUAL_GOVERNANCE; // --- // Aspects // --- + /// @dev Provides the functionality to manage the state of the Escrow. EscrowState.Context internal _escrowState; + + /// @dev Handles the accounting of assets locked in the Escrow. AssetsAccounting.Context private _accounting; + + /// @dev Manages the queue of withdrawal request batches generated from the locked stETH and wstETH tokens. WithdrawalsBatchesQueue.Context private _batchesQueue; // --- - // Construction & initializing + // Construction & Initializing // --- constructor( @@ -117,6 +140,9 @@ contract Escrow is IEscrow { MIN_WITHDRAWALS_BATCH_SIZE = minWithdrawalsBatchSize; } + /// @notice Initializes the proxy instance with the specified minimum assets lock duration. + /// @param minAssetsLockDuration The minimum duration that must pass from the last stETH, wstETH, or unstETH lock + /// by the vetoer before they are allowed to unlock assets from the Escrow. function initialize(Duration minAssetsLockDuration) external { if (address(this) == _SELF) { revert NonProxyCallsForbidden(); @@ -130,9 +156,13 @@ contract Escrow is IEscrow { } // --- - // Lock & unlock stETH + // Lock & Unlock stETH // --- + /// @notice Locks the vetoer's specified `amount` of stETH in the Veto Signalling Escrow, thereby increasing + /// the rage quit support proportionally to the number of stETH shares locked. + /// @param amount The amount of stETH to be locked. + /// @return lockedStETHShares The number of stETH shares locked in the Escrow during the current invocation. function lockStETH(uint256 amount) external returns (uint256 lockedStETHShares) { DUAL_GOVERNANCE.activateNextState(); _escrowState.checkSignallingEscrow(); @@ -144,6 +174,9 @@ contract Escrow is IEscrow { DUAL_GOVERNANCE.activateNextState(); } + /// @notice Unlocks all previously locked stETH and wstETH tokens, returning them in the form of stETH tokens. + /// This action decreases the rage quit support proportionally to the number of unlocked stETH shares. + /// @return unlockedStETHShares The total number of stETH shares unlocked from the Escrow. function unlockStETH() external returns (uint256 unlockedStETHShares) { DUAL_GOVERNANCE.activateNextState(); _escrowState.checkSignallingEscrow(); @@ -156,9 +189,13 @@ contract Escrow is IEscrow { } // --- - // Lock & unlock wstETH + // Lock & Unlock wstETH // --- + /// @notice Locks the vetoer's specified `amount` of wstETH in the Veto Signalling Escrow, thereby increasing + /// the rage quit support proportionally to the number of locked wstETH shares. + /// @param amount The amount of wstETH to be locked. + /// @return lockedStETHShares The number of wstETH shares locked in the Escrow during the current invocation. function lockWstETH(uint256 amount) external returns (uint256 lockedStETHShares) { DUAL_GOVERNANCE.activateNextState(); _escrowState.checkSignallingEscrow(); @@ -170,6 +207,9 @@ contract Escrow is IEscrow { DUAL_GOVERNANCE.activateNextState(); } + /// @notice Unlocks all previously locked stETH and wstETH tokens, returning them in the form of wstETH tokens. + /// This action decreases the rage quit support proportionally to the number of unlocked wstETH shares. + /// @return unlockedStETHShares The total number of wstETH shares unlocked from the Escrow. function unlockWstETH() external returns (uint256 unlockedStETHShares) { DUAL_GOVERNANCE.activateNextState(); _escrowState.checkSignallingEscrow(); @@ -183,9 +223,13 @@ contract Escrow is IEscrow { } // --- - // Lock & unlock unstETH + // Lock & Unlock unstETH // --- + /// @notice Locks the specified unstETH NFTs, identified by their ids, in the Veto Signalling Escrow, thereby increasing + /// the rage quit support proportionally to the total number of stETH shares contained in the locked unstETH NFTs. + /// @dev Locking finalized or already claimed unstETH NFTs is prohibited. + /// @param unstETHIds An array of ids representing the unstETH NFTs to be locked. function lockUnstETH(uint256[] memory unstETHIds) external { if (unstETHIds.length == 0) { revert EmptyUnstETHIds(); @@ -203,6 +247,9 @@ contract Escrow is IEscrow { DUAL_GOVERNANCE.activateNextState(); } + /// @notice Unlocks the specified unstETH NFTs, identified by their ids, from the Veto Signalling Escrow + /// that were previously locked by the vetoer. + /// @param unstETHIds An array of ids representing the unstETH NFTs to be unlocked. function unlockUnstETH(uint256[] memory unstETHIds) external { DUAL_GOVERNANCE.activateNextState(); _escrowState.checkSignallingEscrow(); @@ -217,6 +264,16 @@ contract Escrow is IEscrow { DUAL_GOVERNANCE.activateNextState(); } + /// @notice Marks the specified locked unstETH NFTs as finalized to update the rage quit support value + /// in the Veto Signalling Escrow. + /// @dev Finalizing a withdrawal NFT results in the following state changes: + /// - The value of the finalized unstETH NFT is no longer influenced by stETH token rebases. + /// - The total supply of stETH is adjusted according to the value of the finalized unstETH NFT. + /// These changes impact the rage quit support value. This function updates the status of the specified + /// unstETH NFTs to ensure accurate rage quit support accounting in the Veto Signalling Escrow. + /// @param unstETHIds An array of ids representing the unstETH NFTs to be marked as finalized. + /// @param hints An array of hints required by the WithdrawalQueue to efficiently retrieve + /// the claimable amounts for the unstETH NFTs. function markUnstETHFinalized(uint256[] memory unstETHIds, uint256[] calldata hints) external { DUAL_GOVERNANCE.activateNextState(); _escrowState.checkSignallingEscrow(); @@ -227,9 +284,14 @@ contract Escrow is IEscrow { } // --- - // Convert to NFT + // Convert To NFT // --- + /// @notice Allows vetoers to convert their locked stETH or wstETH tokens into unstETH NFTs on behalf of the + /// Veto Signalling Escrow contract. + /// @param stETHAmounts An array representing the amounts of stETH to be converted into unstETH NFTs. + /// @return unstETHIds An array of ids representing the newly created unstETH NFTs corresponding to + /// the converted stETH amounts. function requestWithdrawals(uint256[] calldata stETHAmounts) external returns (uint256[] memory unstETHIds) { DUAL_GOVERNANCE.activateNextState(); _escrowState.checkSignallingEscrow(); @@ -245,13 +307,21 @@ contract Escrow is IEscrow { _accounting.accountUnstETHLock(msg.sender, unstETHIds, statuses); /// @dev Skip calling activateNextState here to save gas, as converting stETH to unstETH NFTs - /// does not affect the RageQuit support. + /// does not affect the RageQuit support. } // --- - // Start rage quit + // Start Rage Quit // --- + /// @notice Irreversibly converts the Signalling Escrow into the Rage Quit Escrow, allowing vetoers who have locked + /// their funds in the Signalling Escrow to withdraw them in the form of ETH after the Rage Quit process + /// is completed and the specified withdrawal delay has passed. + /// @param rageQuitExtensionPeriodDuration The duration that starts after all withdrawal batches are formed, extending + /// the Rage Quit state in Dual Governance. This extension period ensures that users who have locked their unstETH + /// have sufficient time to claim it. + /// @param rageQuitEthWithdrawalsDelay The waiting period that vetoers must observe after the Rage Quit process + /// is finalized before they can withdraw ETH from the Escrow. function startRageQuit(Duration rageQuitExtensionPeriodDuration, Duration rageQuitEthWithdrawalsDelay) external { _checkCallerIsDualGovernance(); _escrowState.startRageQuit(rageQuitExtensionPeriodDuration, rageQuitEthWithdrawalsDelay); @@ -259,9 +329,13 @@ contract Escrow is IEscrow { } // --- - // Request withdrawal batches + // Request Withdrawal Batches // --- + /// @notice Creates unstETH NFTs from the stETH held in the Rage Quit Escrow via the WithdrawalQueue contract. + /// This function can be called multiple times until the Rage Quit Escrow no longer holds enough stETH + /// to create a withdrawal request. + /// @param batchSize The number of withdrawal requests to process in this batch. function requestNextWithdrawalsBatch(uint256 batchSize) external { _escrowState.checkRageQuitEscrow(); @@ -274,7 +348,7 @@ contract Escrow is IEscrow { uint256 maxStETHWithdrawalRequestAmount = WITHDRAWAL_QUEUE.MAX_STETH_WITHDRAWAL_AMOUNT(); /// @dev This check ensures that even if MIN_STETH_WITHDRAWAL_AMOUNT is set too low, - /// the withdrawal batch request process can still be completed successfully + /// the withdrawal batch request process can still be completed successfully if (stETHRemaining < Math.max(_MIN_TRANSFERRABLE_ST_ETH_AMOUNT, minStETHWithdrawalRequestAmount)) { return _batchesQueue.close(); } @@ -295,9 +369,28 @@ contract Escrow is IEscrow { } // --- - // Claim requested withdrawal batches + // Claim Requested Withdrawal Batches // --- + /// @notice Allows the claim of finalized withdrawal NFTs generated via the `Escrow.requestNextWithdrawalsBatch()` method. + /// The unstETH NFTs must be claimed sequentially, starting from the provided `fromUnstETHId`, which must be + /// the first unclaimed unstETH NFT. + /// @param fromUnstETHId The id of the first unclaimed unstETH NFT in the batch to be claimed. + /// @param hints An array of hints required by the `WithdrawalQueue` contract to efficiently process + /// the claiming of unstETH NFTs. + function claimNextWithdrawalsBatch(uint256 fromUnstETHId, uint256[] calldata hints) external { + _escrowState.checkRageQuitEscrow(); + _escrowState.checkBatchesClaimingInProgress(); + + uint256[] memory unstETHIds = _batchesQueue.claimNextBatch(hints.length); + + _claimNextWithdrawalsBatch(fromUnstETHId, unstETHIds, hints); + } + + /// @notice An overloaded version of `Escrow.claimNextWithdrawalsBatch(uint256, uint256[] calldata)` that calculates + /// hints for the WithdrawalQueue on-chain. This method provides a more convenient claiming process but is + /// less gas efficient compared to `Escrow.claimNextWithdrawalsBatch(uint256, uint256[] calldata)`. + /// @param maxUnstETHIdsCount The maximum number of unstETH NFTs to claim in this batch. function claimNextWithdrawalsBatch(uint256 maxUnstETHIdsCount) external { _escrowState.checkRageQuitEscrow(); _escrowState.checkBatchesClaimingInProgress(); @@ -311,32 +404,28 @@ contract Escrow is IEscrow { ); } - function claimNextWithdrawalsBatch(uint256 fromUnstETHId, uint256[] calldata hints) external { - _escrowState.checkRageQuitEscrow(); - _escrowState.checkBatchesClaimingInProgress(); - - uint256[] memory unstETHIds = _batchesQueue.claimNextBatch(hints.length); - - _claimNextWithdrawalsBatch(fromUnstETHId, unstETHIds, hints); - } - // --- - // Start rage quit extension delay + // Start Rage Quit Extension Delay // --- + /// @notice Initiates the Rage Quit Extension Period once all withdrawal batches have been claimed. + /// For cases where the `Escrow` instance holds only locked unstETH NFTs, this function ensures that the last + /// unstETH NFT registered in the `WithdrawalQueue` at the time of the `Escrow.startRageQuit()` call is finalized. + /// The Rage Quit Extension Period provides additional time for vetoers who locked their unstETH NFTs in the + /// Escrow to claim them. function startRageQuitExtensionPeriod() external { if (!_batchesQueue.isClosed()) { revert BatchesQueueIsNotClosed(); } /// @dev This check is primarily required when only unstETH NFTs are locked in the Escrow - /// and there are no WithdrawalBatches. In this scenario, the RageQuitExtensionPeriod can only begin - /// when the last locked unstETH id is finalized in the WithdrawalQueue. - /// When the WithdrawalBatchesQueue is not empty, this invariant is maintained by the following: - /// - Any locked unstETH during the VetoSignalling phase has an id less than any unstETH NFT created - /// during the request for withdrawal batches. - /// - Claiming the withdrawal batches requires the finalization of the unstETH with the given id. - /// - The finalization of unstETH NFTs occurs in FIFO order. + /// and there are no WithdrawalBatches. In this scenario, the RageQuitExtensionPeriod can only begin + /// when the last locked unstETH id is finalized in the WithdrawalQueue. + /// When the WithdrawalBatchesQueue is not empty, this invariant is maintained by the following: + /// - Any locked unstETH during the VetoSignalling phase has an id less than any unstETH NFT created + /// during the request for withdrawal batches. + /// - Claiming the withdrawal batches requires the finalization of the unstETH with the given id. + /// - The finalization of unstETH NFTs occurs in FIFO order. if (_batchesQueue.getLastClaimedOrBoundaryUnstETHId() > WITHDRAWAL_QUEUE.getLastFinalizedRequestId()) { revert UnfinalizedUnstETHIds(); } @@ -349,9 +438,17 @@ contract Escrow is IEscrow { } // --- - // Claim locked unstETH NFTs + // Claim Locked unstETH NFTs // --- + /// @notice Allows users to claim finalized unstETH NFTs locked in the Rage Quit Escrow contract. + /// To safeguard the ETH associated with withdrawal NFTs, this function should be invoked while the `Escrow` + /// is in the `RageQuitEscrow` state and before the `RageQuitExtensionPeriod` ends. Any ETH corresponding to + /// unclaimed withdrawal NFTs after this period will remain controlled by code potentially influenced by pending + /// and future DAO decisions. + /// @param unstETHIds An array of ids representing the unstETH NFTs to be claimed. + /// @param hints An array of hints required by the `WithdrawalQueue` contract to efficiently process + /// the claiming of unstETH NFTs. function claimUnstETH(uint256[] calldata unstETHIds, uint256[] calldata hints) external { _escrowState.checkRageQuitEscrow(); uint256[] memory claimableAmounts = WITHDRAWAL_QUEUE.getClaimableEther(unstETHIds, hints); @@ -365,18 +462,24 @@ contract Escrow is IEscrow { } // --- - // Escrow management + // Escrow Management // --- + /// @notice Sets the minimum duration that must elapse after the last stETH, wstETH, or unstETH lock + /// by a vetoer before they are permitted to unlock their assets from the Escrow. + /// @param newMinAssetsLockDuration The new minimum lock duration to be set. function setMinAssetsLockDuration(Duration newMinAssetsLockDuration) external { _checkCallerIsDualGovernance(); _escrowState.setMinAssetsLockDuration(newMinAssetsLockDuration); } // --- - // Withdraw logic + // Withdraw Logic // --- + /// @notice Allows the caller (i.e., `msg.sender`) to withdraw all stETH and wstETH they have previously locked + /// into the contract (while it was in the Signalling state) as plain ETH, provided that + /// the Rage Quit process is completed and the Rage Quit Eth Withdrawals Delay has elapsed. function withdrawETH() external { _escrowState.checkRageQuitEscrow(); _escrowState.checkEthWithdrawalsDelayPassed(); @@ -384,6 +487,9 @@ contract Escrow is IEscrow { ethToWithdraw.sendTo(payable(msg.sender)); } + /// @notice Allows the caller (i.e., `msg.sender`) to withdraw the claimed ETH from the specified unstETH NFTs + /// that were locked by the caller in the contract while it was in the Signalling state. + /// @param unstETHIds An array of ids representing the unstETH NFTs from which the caller wants to withdraw ETH. function withdrawETH(uint256[] calldata unstETHIds) external { if (unstETHIds.length == 0) { revert EmptyUnstETHIds(); @@ -398,6 +504,12 @@ contract Escrow is IEscrow { // Getters // --- + /// @notice Returns the total amounts of locked and claimed assets in the Escrow. + /// @return totals A struct containing the total amounts of locked and claimed assets, including: + /// - `stETHClaimedETH`: The total amount of ETH claimed from locked stETH. + /// - `stETHLockedShares`: The total number of stETH shares currently locked in the Escrow. + /// - `unstETHUnfinalizedShares`: The total number of shares from unstETH NFTs that have not yet been finalized. + /// - `unstETHFinalizedETH`: The total amount of ETH from finalized unstETH NFTs. function getLockedAssetsTotals() external view returns (LockedAssetsTotals memory totals) { StETHAccounting memory stETHTotals = _accounting.stETHTotals; totals.stETHClaimedETH = stETHTotals.claimedETH.toUint256(); @@ -408,6 +520,13 @@ contract Escrow is IEscrow { totals.unstETHFinalizedETH = unstETHTotals.finalizedETH.toUint256(); } + /// @notice Returns the state of locked assets for a specific vetoer. + /// @param vetoer The address of the vetoer whose locked asset state is being queried. + /// @return state A struct containing information about the vetoer's locked assets, including: + /// - `stETHLockedShares`: The total number of stETH shares locked by the vetoer. + /// - `unstETHLockedShares`: The total number of unstETH shares locked by the vetoer. + /// - `unstETHIdsCount`: The total number of unstETH NFTs locked by the vetoer. + /// - `lastAssetsLockTimestamp`: The timestamp of the last assets lock by the vetoer. function getVetoerState(address vetoer) external view returns (VetoerState memory state) { HolderAssets storage assets = _accounting.assets[vetoer]; @@ -417,26 +536,41 @@ contract Escrow is IEscrow { state.lastAssetsLockTimestamp = assets.lastAssetsLockTimestamp.toSeconds(); } + /// @notice Returns the total count of unstETH NFTs that have not been claimed yet. + /// @return unclaimedUnstETHIdsCount The total number of unclaimed unstETH NFTs. function getUnclaimedUnstETHIdsCount() external view returns (uint256) { return _batchesQueue.getTotalUnclaimedUnstETHIdsCount(); } + /// @notice Retrieves the unstETH NFT ids of the next batch available for claiming. + /// @param limit The maximum number of unstETH NFTs to return in the batch. + /// @return unstETHIds An array of unstETH NFT IDs available for the next withdrawal batch. function getNextWithdrawalBatch(uint256 limit) external view returns (uint256[] memory unstETHIds) { return _batchesQueue.getNextWithdrawalsBatches(limit); } + /// @notice Returns whether all withdrawal batches have been finalized. + /// @return isWithdrawalsBatchesFinalized A boolean value indicating whether all withdrawal batches have been + /// finalized (`true`) or not (`false`). function isWithdrawalsBatchesFinalized() external view returns (bool) { return _batchesQueue.isClosed(); } + /// @notice Returns whether the Rage Quit Extension Period has started. + /// @return isRageQuitExtensionPeriodStarted A boolean value indicating whether the Rage Quit Extension Period + /// has started (`true`) or not (`false`). function isRageQuitExtensionPeriodStarted() external view returns (bool) { return _escrowState.isRageQuitExtensionPeriodStarted(); } + /// @notice Returns the timestamp when the Rage Quit Extension Period started. + /// @return rageQuitExtensionPeriodStartedAt The timestamp when the Rage Quit Extension Period began. function getRageQuitExtensionPeriodStartedAt() external view returns (Timestamp) { return _escrowState.rageQuitExtensionPeriodStartedAt; } + /// @notice Returns the current Rage Quit support value as a percentage. + /// @return rageQuitSupport The current Rage Quit support as a `PercentD16` value. function getRageQuitSupport() external view returns (PercentD16) { StETHAccounting memory stETHTotals = _accounting.stETHTotals; UnstETHAccounting memory unstETHTotals = _accounting.unstETHTotals; @@ -450,6 +584,8 @@ contract Escrow is IEscrow { }); } + /// @notice Returns whether the Rage Quit process has been finalized. + /// @return A boolean value indicating whether the Rage Quit process has been finalized (`true`) or not (`false`). function isRageQuitFinalized() external view returns (bool) { return _escrowState.isRageQuitEscrow() && _escrowState.isRageQuitExtensionPeriodPassed(); } @@ -458,6 +594,7 @@ contract Escrow is IEscrow { // Receive ETH // --- + /// @notice Accepts ETH payments only from the `WithdrawalQueue` contract. receive() external payable { if (msg.sender != address(WITHDRAWAL_QUEUE)) { revert InvalidETHSender(msg.sender, address(WITHDRAWAL_QUEUE)); @@ -465,7 +602,7 @@ contract Escrow is IEscrow { } // --- - // Internal methods + // Internal Methods // --- function _claimNextWithdrawalsBatch(