# [WIP] Forced Target Limit ### TL;DR As mentioned in [VEBO 2.0 ADR](https://hackmd.io/LaKOVqg2QQKgZn6JxlUNuQ#Forced-Target-Limit), in the current implementation of Lido protocol, the process of validator withdrawal is strictly governed by the withdrawal queue, limiting the system's flexibility. This constraint means that validators cannot be withdrawn independently of the queue, even in urgent situations where quick adjustments are necessary. To overcome this limitation and enhance the system's responsiveness, a new mechanism is proposed. This mechanism would enable the forceful and immediate withdrawal of validators, regardless of the withdrowal queue, allowing for more agile and efficient protocol management, especially in emergency scenarios. ### Motivation To complement the existing target limit feature, a new concept, the "Forced Target Limit," is being introduced. This innovation is designed to augment the current system by providing an additional layer of control, enabling node operators to forcibly adjust the number of active validators in critical situations. While the traditional target limit is bound by the withdrawal queue, the Forced Target Limit will empower operators to make necessary adjustments promptly. It is suggested that the ability to set the forced application of the active validators limit at the operator should be available to DAOs and the module itself. Managing this limit of the number of active validators within the module is not mandatory but can be necessary in certain scenarios, such as in the CSM module for forcibly removing operators with poor performance or insufficient collateral/bond. ### Proposed solution Based on the current implementation of `StakingRouter` and modules, the following approach is proposed to introduce the new functionality with maximum backward compatibility: 1. Replace the internal interpretation of the `bool isTargetLimitActive` parameter with `uint targetLimitMode`, which will allow multiple values for this flag in bitwise represenation: * 1st bit - target limit activity flag * 2nd bit - forced target limit activity flag i.e.: * `b00` - means target limit is disabled * `bx1` - target limit is enabled in normal mode (see [link_TBA]()) * `b1x` - forced target limit is enabled, regardless of whether target limnit is enabled, i.e. the value of the first bit is ignored. (see [link_TBA]()) 2. Additionally, introduce the `forcedTargetLimitCount` internal variable, which will be changed by a separate method with its own access rights. A new method for reading the parameter will also be added. This will allow turning on/off the forced limit mode without changing the rest of the current protocol logic, and will provide additional flexibility in access rights to this mechanism. ### Specification 1. Change the module interface flag type isTargetLimitActive from bool to uint (keep the parameter name the same for compatibility), while the limit returned in targetValidatorsCount will indicate the required number of active validators to be reached, but considering the logic described below. ```solidity! function getNodeOperatorSummary(uint256 _nodeOperatorId) external view returns ( uint256 isTargetLimitActive, uint256 targetValidatorsCount, uint256 stuckValidatorsCount, uint256 refundedValidatorsCount, uint256 stuckPenaltyEndTimestamp, uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount ); ``` 2. For values returned by the `getNodeOperatorSummary` getter method, the following logic will be applied in cases where the operator has no set `target limit` but has a `forced target limit` set, or the `target limit` values differ (changes in the VEBO code will be required to follow the new logic): ```solidity! /// @notice assuming the existence of forcedTargetLimitCount and targetLimitCount vars /// @notice the code is not optimized and is presented for ease of understanding isTargetLimitActive = targetLimitMode; // since now the return parameter type is uint if (targetLimitMode > 2) { // i.e. =3 (b11), both target limit and forced target limit are enabled targetValidatorsCount = min(forcedTargetLimitCount, targetLimitCount); } else if (targetLimitMode > 1) { // i.e. =2 (b10), only forced target limit is enabled targetValidatorsCount = forcedTargetLimitCount; } else if (targetLimitMode > 0) { // i.e. =1 (b01), only target limit is enabled targetValidatorsCount = targetLimitCount; } else { // no limits are enabled targetValidatorsCount = 0; } /// @notice it is possible to require that when some limit is disabled, the correspondign values of targetLimitCount and forcedTargetLimitCount are also set to 0, then the logic can be simplified ``` 3. Additionally, introduce methods for reading and changing `targetLimitMode` and `forcedTargetLimitCount` values, with separate access rights (similarly to `updateTargetValidatorsLimits` method). ```solidity! function updateForcedTargetValidatorsLimits( uint256 _nodeOperatorId, bool _isForcedTargetLimitActive, uint256 _forcedTargetLimit ) external; function getForcedTargetValidatorsLimits( uint256 _nodeOperatorId ) external returns( bool isForcedTargetLimitActive, uint256 forcedTargetValidatorsCount ); /// @notice due to the getNodeOperatorSummary method now returning only the aggregate value, this method is added to directly read target limit values function getTargetValidatorsLimits( uint256 _nodeOperatorId ) external returns( bool isTargetLimitActive, uint256 targetValidatorsCount ); ``` ### Conclusions This proposed approach will maximize backward compatibility of contract methods and enable the implementation of a mechanism in VEBO for prioritizing the exit of validators assigned to a specific operator. Having a separate method for setting forced limits allows DAO participants to manage this parameter in emergency cases, as well as the module itself to implement internal mechanisms. Moreover, the proposed approach will allow avoiding additional operational load when disabling the forced target limit and restoring the target limit values if they were set before, and the forced target limit was enabled for some time.