# EVM Script Factories For Simple DVT Module The current doc describes the implementation details of EasyTrack EVM factories to manage an instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol). The rights to manage node operators ([clusters](https://hackmd.io/@lido/rJ0zsLo6h#Cluster)) in the Simple DVT will be granted to the Simple DVT committee represented by the gnosis multisig. The high-view overview of the management flow is presented in the below diagram. ![](https://hackmd.io/_uploads/H18nARJXa.png) Before reading the current document, please check out the high-level [Simple DVT module management flow](https://hackmd.io/@lido/rJ0zsLo6h). For consistency, throughout the document, the term **node operator(s)** is used, but by this, we also mean **cluster(s)**. ## Validator Keys Management The management of the validator keys in the instance of the NodeOperatorsRegistry used as a curated staking module happens from the reward address. To add or remove the validator's keys, the node operator sends the transaction from the reward address. ![image](https://hackmd.io/_uploads/rkq2Ehyca.png) Unfortunately, such an approach doesn't apply to the Simple DVT instance because node operators use a dedicated splitter contract as a reward address, which distributes rewards among the cluster participants and doesn't contain logic to manage keys in the NodeOperatorsRegistry. Besides the reward address, rights to add and remove keys might be granted using special MANAGE_SIGNING_KEYS permission. This permission may be parametrized with the ID of the node operator, which may be used to implement unique access to certain node operators from the specific manager address. ![image](https://hackmd.io/_uploads/r1A0Eh15a.png) Aragon's ACL contract provides ample opportunities to implement custom checks using the permissions params, but non-trivial logic may overcomplicate the final solution. To preserve the checks simple, the following constraints apply for manager addresses: - Each node operator **MUST** have a **unique** manager - The same manager address **CAN NOT** be used for different node operators With an introduction of the above invariants, the granular rights might be implemented using only one additional parameter: - `Param(0, uint8(Op.EQ), managedNodeOperatorId)` During the check of MANAGE_SIGNING_KEYS permission with the above permission, the ACL contract validates that the id of the node operator passed via arguments is equal to managedNodeOperatorId, set on the permission granting step. ## Rights & Permissions To operate properly, the introducing EVM script factories require the following [`ACL`](https://github.com/aragon/aragonOS/blob/next/contracts/acl/ACL.sol) permissions granted to EasyTrack's [`EvmScriptExecutor`](https://github.com/lidofinance/easy-track/blob/master/contracts/EVMScriptExecutor.sol) contract on the instance of the [`NodeOperatorsRegistry`]() for Simple DVT: | Permission | EVM Script Factory | Method | |-|-|-| | `STAKING_ROUTER_ROLE` |[UpdateTargetValidatorLimits](#UpdateTargetValidatorLimits) | [`updateTargetValidatorsLimits()`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L584C14-L584C42) | | `MANAGE_NODE_OPERATOR_ROLE` |[AddNodeOperators](#AddNodeOperators)| [`addNodeOperator()`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L287)| | `MANAGE_NODE_OPERATOR_ROLE` |[ActivateNodeOperators](#ActivateNodeOperators)| [`activateNodeOperator()`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L311)| | `MANAGE_NODE_OPERATOR_ROLE` |[DeactivateNodeOperators](#DeactivateNodeOperators)| [`deactivateNodeOperator()`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L327)| | `MANAGE_NODE_OPERATOR_ROLE` |[SetNodeOperatorNames](#SetNodeOperatorNames)| [`setNodeOperatorName()`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L359C14-L359C33)| | `MANAGE_NODE_OPERATOR_ROLE` |[SetNodeOperatorRewardAddresses](#SetNodeOperatorRewardAddresses)| [`setNodeOperatorRewardAddress()`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L372)| | `SET_NODE_OPERATOR_LIMIT_ROLE` |[SetVettedValidatorsLimit](SetVettedValidatorsLimit)|[`setNodeOperatorStakingLimit()`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L388C14-L388C41)| | `SET_NODE_OPERATOR_LIMIT_ROLE` |[IncreaseVettedValidatorsLimit](IncreaseVettedValidatorsLimit)|[`setNodeOperatorStakingLimit()`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L388C14-L388C41)| Besides the granted permissions, the [`EvmScriptExecutor`](https://github.com/lidofinance/easy-track/blob/master/contracts/EVMScriptExecutor.sol) contract **MUST BE** assigned as a unique manager of the `MANAGE_SIGNING_KEYS` permission on the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) instance. It's necessary to allow granting and revoking a parametrized version of the `MANAGE_SIGNING_KEYS` permissions to the node operator's manager when adding, activating, and deactivating the node operator. > The [ACL](https://github.com/aragon/aragonOS/blob/next/contracts/acl/ACL.sol) contract allows setting only one address as the manager for the permission. It means that manager rights of granting and revoking the `MANAGE_SIGNING_KEYS` permission will be exclusively delegated to EasyTrack's [`EvmScriptExecutor`](https://github.com/lidofinance/easy-track/blob/master/contracts/EVMScriptExecutor.sol) contract. In case the DAO needs to make some operation with this role on the side of the `Voting` contract, this role may be taken back, temporarily swapping the `easyTrack` address in the [`EvmScriptExecutor`](https://github.com/lidofinance/easy-track/blob/master/contracts/EVMScriptExecutor.sol) contract and executing EVM script, which calls [`ACL.removePermissionManager()`](https://github.com/aragon/aragonOS/blob/4bbe3e96fc5a3aa6340b11ec67e6550029da7af9/contracts/acl/ACL.sol#L164) or [`ACL.setPermissionManager()`](https://github.com/aragon/aragonOS/blob/4bbe3e96fc5a3aa6340b11ec67e6550029da7af9/contracts/acl/ACL.sol#L152C14-L152C34) method. An example of such voting script creation might be found here: https://github.com/lidofinance/easy-track/blob/98afb4a12755d39a1856c5d111accef36c0688d0/tests/scenario/test_dvt_signing_keys_role.py#L149 ![](https://hackmd.io/_uploads/SyS7mJlQ6.png) ## AddNodeOperators - **inherits**: [TrustedCaller](https://github.com/lidofinance/easy-track/blob/master/specification.md#trustedcaller) - **implements**: [IEVMScriptFactory](https://github.com/lidofinance/easy-track/blob/master/specification.md#ievmscriptfactory****) Allows creation of EVM script to add a set of node operators to the Simple DVT's instance of the [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) and grant parametrized `MANAGE_SIGNING_KEYS` permission to a node operator's manager address. ### Restrictions The current implementation **DOES NOT** allow to addition of multiple batches of node operators in parallel motions. **If two `AddNodeOperators` motions are started simultaneously, only the first executed will be applied successfully, and the second one will fail on the execution attempt**. ### Data Types To simplify the process of preparing data for motion creation, the input data for each newly added node operator is organized in the struct `AddNodeOperatorInput`: ```solidity! struct AddNodeOperatorInput { // the name of the newly added node operator string name; // the reward address of the newly added node operator address rewardAddress; // address to assign a parametrized version of the MANAGE_SIGNING_KEYS permission for the newly added node operator address managerAddress; } ``` ### Immutable Variables - `IACL acl` - address of the Lido's instance of the Aragon's [`ACL`](https://github.com/aragon/aragonOS/blob/next/contracts/acl/ACL.sol) contract - `INodeOperatorsRegistry registry` - address of the instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) ### Methods #### createEVMScript(address,bytes) - **Arguments**: - `address _creator` - the creator of the EVM Script - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(uint256 nodeOperatorsCount, AddNodeOperatorInput[] nodeOperators)` - **Visibility**: `external` - **Mutability**: `view` - **Modifiers**: [onlyTrustedCaller(_creator)](https://github.com/lidofinance/easy-track/blob/master/specification.md#storage-variables-3) - **Returns**: `(bytes memory)` Creates an EVM script to add a list of node operators to the instance of [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol), and for every added node operator, grants parametrized `MANAGE_SIGNING_KEYS` permission to the provided manager address. >Additionally to the array of `AddNodeOperatorInput` instances, the encoded calldata includes the total number of node operators in the registry (`nodeOperatorsCount`). This field is required to check that the manager's rights will be granted to the correct pair of the manager and node operator. > >To grant the `MANAGE_SIGNING_KEYS` permission to the manager address, the id of the added node operator must be known at the moment of the creation of the motion. The current implementation of the [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) allows prediction of the id of the new node operator (https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L292), but as each motion executed with a delay, there is a chance that after the creation of the motion, but before its execution, will be added another node operator and the precalculated ids of the node operators used on motion creation become invalid. To prevent the enactment of such motions, the `_nodeOperatorsCount` argument is added to the calldata of the factory. This parameter is then used to validate that the onchain state of the [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) hasn't changed from the moment of the creation of the motion. To successfully create and enact motion, the following onchain requirements must be met: - The current number of node operators in the registry **MUST** be equal to the `_nodeOperatorsCount` - The total number of node operators in the registry, after adding the new ones, **MUST NOT** exceed `nodeOperatorsRegistry.MAX_NODE_OPERATORS_COUNT()` - Manager addresses **MUST NOT** have duplicates - Manager addresses **MUST NOT** be used as managers for previously added node operators - Reward addresses of newly added node operators **MUST NOT** contain the address of the stETH token - Reward addresses of newly added node operators **MUST NOT** contain zero addresses - The names of newly added node operators **MUST NOT** be an empty string - The name lengths of each newly added node operator **MUST NOT** exceed the `nodeOperatorsRegistry.MAX_NODE_OPERATOR_NAME_LENGTH()` #### decodeEVMScriptCallData(bytes) - **Arguments**: - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(uint256, ActivateNodeOperatorInput[])` - **Visibility**: `external` - **Mutability**: `pure` - **Returns**: `(uint256, ActivateNodeOperatorInput[] memory)` Decodes `_evmScriptCallData` into tuple `(uint256 nodeOperatorsCount, AddNodeOperatorInput[] nodeOperators)`. ## DeactivateNodeOperators - **inherits**: [TrustedCaller](https://github.com/lidofinance/easy-track/blob/master/specification.md#trustedcaller) - **implements**: [IEVMScriptFactory](https://github.com/lidofinance/easy-track/blob/master/specification.md#ievmscriptfactory****) Allows creation of EVM script to deactivate and revoke the MANAGE_SIGNING_KEYS permission from the manager address for the set of node operators. >The `MANANGE_SIGNING_KEYS` permission revoking is needed to prevent uploading and removing validator keys by the managers of the deactivated node operators (See the implementation of the [`NodeOperatorRegistry._onlyNodeOperatorManager()`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol#L1428)). ### Data Types The input data for each node operator is organized in the following struct: ```solidity! struct DectivateNodeOperatorInput { // id of the node operator to deactivate uint256 nodeOperatorId; // address of the node operator manager with granted parameterized version of MANAGE_SIGNING_KEYS permission address managerAddress; } ``` > The current implementation of the [`ACL`](https://github.com/aragon/aragonOS/blob/next/contracts/acl/ACL.sol) contract doesn't allow receiving all holders of the particular permission onchain, so the current address of the manager of the node operator is passed explicitly. ### Immutable Variables - `IACL acl` - address of the Lido's instance of the Aragon's [`ACL`](https://github.com/aragon/aragonOS/blob/next/contracts/acl/ACL.sol) contract - `INodeOperatorsRegistry registry` - address of the instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) ### Methods #### createEVMScript(address,bytes) - **Arguments**: - `address _creator` - the creator of the EVM Script - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(DectivateNodeOperatorInput[])` - **Visibility**: `external` - **Mutability**: `view` - **Modifiers**: [onlyTrustedCaller(_creator)](https://github.com/lidofinance/easy-track/blob/master/specification.md#storage-variables-3) - **Returns**: `(bytes memory)` Creates an EVM script to deactivate and revoke a parameterized version of the `MANAGER_SIGNING_KEYS` permission from the manager address for the set of node operators. To successfully create and enact motion, the following onchain requirements must be met: - The list of `DeactivateNodeOperatorInput` **MUST** be sorted in strictly ascending order by the `nodeOperatorId` key (**duplicates are not allowed**) - Each node operator in the set **MUST** be registered in the registry - Each node operator in the set **MUST** be in the activated state - Each manager address in the set **MUST** be granted with a parametrized version of `MANAGE_SIGNING_KEYS` permission for the corresponding node operator #### decodeEVMScriptCallData(bytes) - **Arguments**: - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(DeactivateNodeOperatorInput[])` - **Visibility**: `external` - **Mutability**: `pure` - **Returns**: `(DeactivateNodeOperatorInput[] memory)` Decodes `_evmScriptCallData` into tuple `(DeactivateNodeOperatorInput[])`. ## ActivateNodeOperators - **inherits**: [TrustedCaller](https://github.com/lidofinance/easy-track/blob/master/specification.md#trustedcaller) - **implements**: [IEVMScriptFactory](https://github.com/lidofinance/easy-track/blob/master/specification.md#ievmscriptfactory****) Allows creation of EVM script to activate and set manager address for the set of previously deactivated node operators. ### Data Types The input data for each activated node operator is organized in the following struct: ```solidity! struct ActivateNodeOperatorInput { // id of the node operator to activate uint256 nodeOperatorId; // address to assign a parametrized version of the MANAGE_SIGNING_KEYS permission for the activated node operator address managerAddress; } ``` >The `managerAddress` is required because the current implementation of the [DeactivateNodeOperators](#DeactivateNodeOperators) EVM Script factory revokes this permission from the manager address. ### Immutable Variables - `IACL immutable acl` - address of the Lido's instance of the Aragon's [`ACL`](https://github.com/aragon/aragonOS/blob/next/contracts/acl/ACL.sol) contract - `INodeOperatorsRegistry immutable registry` - address of the instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) ### Methods #### createEVMScript(address,bytes) - **Arguments**: - `address _creator` - the creator of the EVM Script - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(ActivateNodeOperatorInput[])` - **Visibility**: `external` - **Mutability**: `view` - **Modifiers**: [onlyTrustedCaller(_creator)](https://github.com/lidofinance/easy-track/blob/master/specification.md#storage-variables-3) - **Returns**: `(bytes memory)` Creates an EVM script to activate and grant a parameterized version of the `MANAGER_SIGNING_KEYS` permission to the manager address for the set of node operators. To successfully create and enact motion, the following onchain requirements must be met: - The list of `ActivateNodeOperatorInput` **MUST** be sorted in strictly ascending order by the `nodeOperatorId` key (**duplicates are not allowed**) - Each node operator in the set **MUST** be registered in the registry - Each node operator in the set **MUST** be in the deactivated state - Each manager address in the set **MUST NOT** be granted with `MANAGE_SIGNING_KEYS` permission #### decodeEVMScriptCallData(bytes) - **Arguments**: - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(ActivateNodeOperatorInput[])` - **Visibility**: `external` - **Mutability**: `pure` - **Returns**: `(ActivateNodeOperatorInput[] memory)` Decodes `_evmScriptCallData` into tuple `(ActivateNodeOperatorInput[])`. ## SetNodeOperatorNames - **inherits**: [TrustedCaller](https://github.com/lidofinance/easy-track/blob/master/specification.md#trustedcaller) - **implements**: [IEVMScriptFactory](https://github.com/lidofinance/easy-track/blob/master/specification.md#ievmscriptfactory****) Allows creation of EVM script to set the name for the set of the node operators. ### Data Types The input data for each change of the node operator's name is organized in the following struct: ```solidity! struct SetNameInput { // id of the node operator to set new name uint256 nodeOperatorId; // new name of the node operator string name; } ``` ### Immutable Variables - `INodeOperatorsRegistry immutable registry` - address of the instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) ### Methods #### createEVMScript(address,bytes) - **Arguments**: - `address _creator` - the creator of the EVM Script - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(SetNameInput[])` - **Visibility**: `external` - **Mutability**: `view` - **Modifiers**: [onlyTrustedCaller(_creator)](https://github.com/lidofinance/easy-track/blob/master/specification.md#storage-variables-3) - **Returns**: `(bytes memory)` Returns EVM script to set the name of the node operators with the given IDs. To successfully create and enact motion, the following onchain requirements must be met: - The list of `SetNameInput` **MUST** be sorted in strictly ascending order by the `nodeOperatorId` key (**duplicates are not allowed**) - Each node operator **MUST** be registered in the registry contract - The new names of the node operators **MUST** differ from the current names - The new names of the node operators **MUST NOT** contain empty strings - The lengths of the new names of the node operators don't exceed the `NodeOperatorsRegistry.MAX_NODE_OPERATOR_NAME_LENGTH()` #### decodeEVMScriptCallData(bytes) - **Arguments**: - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(SetNameInput[])` - **Visibility**: `external` - **Mutability**: `pure` - **Returns**: `(SetNameInput[] memory)` Decodes `_evmScriptCallData` into tuple `(SetNameInput[])`. ## SetNodeOperatorRewardAddresses - **inherits**: [TrustedCaller](https://github.com/lidofinance/easy-track/blob/master/specification.md#trustedcaller) - **implements**: [IEVMScriptFactory](https://github.com/lidofinance/easy-track/blob/master/specification.md#ievmscriptfactory****) Allows creation of EVM script to set the reward addresses for the set of the node operators. ### Data Types The input data for each reward address change is organized in the following struct: ```solidity! struct SetRewardAddressInput { // id of the node operator to set new reward address uint256 nodeOperatorId; // new reward address of the node operator address rewardAddress; } ``` ### Immutable Variables - `INodeOperatorsRegistry immutable registry` - address of the instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) ### Methods #### createEVMScript(address,bytes) - **Arguments**: - `address _creator` - the creator of the EVM Script - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(SetRewardAddressInput[])` - **Visibility**: `external` - **Mutability**: `view` - **Modifiers**: [onlyTrustedCaller(_creator)](https://github.com/lidofinance/easy-track/blob/master/specification.md#storage-variables-3) - **Returns**: `(bytes memory)` Returns EVM script to set the reward address of the node operators with the given ids. To successfully create and enact motion, the following onchain requirements must be met: - The list of `SetRewardAddressInput` **MUST** be sorted in strictly ascending order by the `nodeOperatorId` key (**duplicates are not allowed**) - Each node operator in the set **MUST** be registered in the registry contract - Each new reward address **MUST NOT** be equal to the current reward address of the node operator - Each new reward address **MUST NOT** be equal to zero address - Each new reward address **MUST NOT** be equal to the address of the stETH token #### decodeEVMScriptCallData(bytes) - **Arguments**: - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(SetRewardAddressInput[])` - **Visibility**: `external` - **Mutability**: `pure` - **Returns**: `(SetRewardAddressInput[] memory)` Decodes `_evmScriptCallData` into tuple `(SetRewardAddressInput[])`. ## UpdateTargetValidatorLimits - **inherits**: [TrustedCaller](https://github.com/lidofinance/easy-track/blob/master/specification.md#trustedcaller) - **implements**: [IEVMScriptFactory](https://github.com/lidofinance/easy-track/blob/master/specification.md#ievmscriptfactory****) Allows creation of EVM script to update the target validators limits for the set of node operators. ### Data Types The input data for each target validators limit is organized in the following struct: ```solidity! struct TargetValidatorsLimitInput { // id of the node operator to set target validators limit uint256 nodeOperatorId; // whether the target limit is active for the node operator or not bool isTargetLimitActive; // the value of the target limit to set uint256 targetLimit; } ``` ### Immutable Variables - `INodeOperatorsRegistry immutable registry` - address of the instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) ### Methods #### createEVMScript(address,bytes) - **Arguments**: - `address _creator` - the creator of the EVM Script - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(TargetValidatorsLimit[])` - **Visibility**: `external` - **Mutability**: `view` - **Modifiers**: [onlyTrustedCaller(_creator)](https://github.com/lidofinance/easy-track/blob/master/specification.md#storage-variables-3) - **Returns**: `(bytes memory)` Returns EVM script to set the target validator limits for the set of node operators. To successfully create and enact motion the next onchain requirements must be met: - The list of `TargetValidatorsLimit` **MUST** be sorted in strictly ascending order by the `nodeOperatorId` key (**duplicates are not allowed**) - Each node operator in the set **MUST** be registered in the registry contract - The new value of the validator's target limit **MUST NOT** exceed the `UINT64_MAX` value #### decodeEVMScriptCallData(bytes) - **Arguments**: - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(TargetValidatorsLimit[])` - **Visibility**: `external` - **Mutability**: `pure` - **Returns**: `(TargetValidatorsLimit[] memory)` Decodes `_evmScriptCallData` into tuple `(TargetValidatorsLimit[])`. ## ChangeNodeOperatorManagers - **inherits**: [TrustedCaller](https://github.com/lidofinance/easy-track/blob/master/specification.md#trustedcaller) - **implements**: [IEVMScriptFactory](https://github.com/lidofinance/easy-track/blob/master/specification.md#ievmscriptfactory****) Allows creation of EVM Script to revoke the parametrized version of the `MANAGE_SIGNING_KEYS` permission from the current manager address and grant it to the new one for the set of node operators. ### Restrictions **The current design of the permissions system forbids using the same manager address for different node operators.** In other words, to successfully transfer the manager permission to another account via the `SetNodeOperatorManager` motion, the new address of the manager **MUST NOT** be used as a manager in other node operators of the registry. ### Data Types The input data for each manager changer is organized in the following struct: ```solidity struct PermissionInput { // id of the node operator to change the manager address for uint256 nodeOperatorId; // address of the current manager of the node operator address oldManagerAddress; // address of the new manager of the node operator address newManagerAddress; } ``` ### Immutable Variables - `IACL immutable acl` - address of the Lido's instance of the Aragon's [`ACL`](https://github.com/aragon/aragonOS/blob/next/contracts/acl/ACL.sol) contract - `INodeOperatorsRegistry immutable registry` - address of the instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) ### Methods #### createEVMScript(address,bytes) - **Arguments**: - `address _creator` - the creator of the EVM Script - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(PermissionInput[])` - **Visibility**: `external` - **Mutability**: `view` - **Modifiers**: [onlyTrustedCaller(_creator)](https://github.com/lidofinance/easy-track/blob/master/specification.md#storage-variables-3) - **Returns**: `(bytes memory)` Creates EVM script to update the manager of the node operators with the given ids. The resulting EVM script revokes `MANAGE_SIGNING_KEYS` permission from the `oldManagerAddress` and grants it to the `newManagerAddress`. To successfully create and enact motion, the following onchain requirements must be met: - The list of `PermissionInput` **MUST** be sorted in strictly ascending order by the `nodeOperatorId` key (**duplicates are not allowed**) - Each node operator in the set **MUST** be registered in the registry contract - Manager addresses **MUST NOT** have duplicates - `oldManagerAddress` and `newManagerAddress` **MUST NOT** be equal to zero address - `oldManagerAddress` **MUST** have the parametrized `MANAGE_SIGNING_KEYS` permission granted - `newManagerAddress` **MUST NOT** have the parametrized `MANAGE_SIGNING_KEYS` permission granted #### decodeEVMScriptCallData(bytes) - **Arguments**: - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(PermissionInput[])` - **Visibility**: `external` - **Mutability**: `pure` - **Returns**: `(PermissionInput[] memory)` Decodes `_evmScriptCallData` into tuple `(PermissionInput[])`. ## SetVettedValidatorsLimits - **inherits**: [TrustedCaller](https://github.com/lidofinance/easy-track/blob/master/specification.md#trustedcaller) - **implements**: [IEVMScriptFactory](https://github.com/lidofinance/easy-track/blob/master/specification.md#ievmscriptfactory****) Allows creation of EVM script to set the vetted validators limits for the set of node operators. ### Data Types The input data for each vetted validators limit is organized in the following struct: ```solidity struct VettedValidatorsLimit { // id of the node operator to set the limit of the vetted validators uint256 nodeOperatorId; // the new limit of the vetted validators for the node operator uint256 vettedValidatorsLimit; } ``` ### Immutable Variables - `INodeOperatorsRegistry immutable registry` - address of the instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) ### Methods #### createEVMScript(address,bytes) - **Arguments**: - `address _creator` - the creator of the EVM Script - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(VettedValidatorsLimit[])` - **Visibility**: `external` - **Mutability**: `view` - **Modifiers**: [onlyTrustedCaller(_creator)](https://github.com/lidofinance/easy-track/blob/master/specification.md#storage-variables-3) - **Returns**: `(bytes memory)` Returns EVM script to set the vetted validators limits for the set of node operators. To successfully create EVMScript, the following requirements must be met: - The list of `VettedValidatorsLimit` **MUST** be sorted in strictly ascending order by the `nodeOperatorId` key (**duplicates are not allowed**) - Each Node Operator **MUST** be registered in the registry. - Each value of the vetted validators limit **MUST** be less or equal to the number of the total validators of the node operator. - Each Node Operator **MUST** be in an active state. #### decodeEVMScriptCallData(bytes) - **Arguments**: - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(VettedValidatorsLimit[])` - **Visibility**: `external` - **Mutability**: `pure` - **Returns**: `(VettedValidatorsLimit[] memory)` Decodes `_evmScriptCallData` into tuple `(VettedValidatorsLimit[])`. ## IncreaseVettedValidatorsLimit - **implements**: [IEVMScriptFactory](https://github.com/lidofinance/easy-track/blob/master/specification.md#ievmscriptfactory****) Allows creation of EVMScript to increase the vetted validators limit for node operator with the given id. ### Immutable Variables - `IACL immutable acl` - address of the Lido's instance of the Aragon's [`ACL`](https://github.com/aragon/aragonOS/blob/next/contracts/acl/ACL.sol) contract - `INodeOperatorsRegistry immutable registry` - address of the instance of the Simple DVT [`NodeOperatorsRegistry`](https://github.com/lidofinance/lido-dao/blob/cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf/contracts/0.4.24/nos/NodeOperatorsRegistry.sol) ### Methods #### createEVMScript(address,bytes) - **Arguments**: - `address _creator` - the creator of the EVM Script - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(uint256 _nodeOperatorId, uint256 _stakingLimit)`, where - `_nodeOperatorId` - id of node operator to increase the limit for, - `_stakingLimit` - new staking limit - **Visibility**: `external` - **Mutability**: `view` - **Modifiers**: [onlyTrustedCaller(_creator)](https://github.com/lidofinance/easy-track/blob/master/specification.md#storage-variables-3) - **Returns**: `(bytes memory)` Returns EVMScript to increase the vetted validators limit of the node operator with the given ID. To successfully create an EVM script following requirements must be met: - Node operator with the given id **MUST** be registered in the registry contract - Reward address of the node operator **MUST** be equal to the address of the `_creator` or `_creator` **MUST** be set as manager of the node operator - Node Operator **MUST** be activated. - The new staking limit **MUST** be greater than the current staking limit - The new staking limit **MUST** be less or equal to the total number of signing keys #### decodeEVMScriptCallData(bytes) - **Arguments**: - `bytes memory _evmScriptCallData` - an ABI encoded tuple `(uint256 _nodeOperatorId, uint256 _stakingLimit)` - **Visibility**: `external` - **Mutability**: `pure` - **Returns**: `(VettedValidatorsLimit[] memory)` Decodes `_evmScriptCallData` into tuple `(uint256 _nodeOperatorId, uint256 _stakingLimit)`.