From 2aacab5a3c24b8aee8215ee971008438cc0a83c3 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Wed, 31 Jan 2024 16:22:24 +0100 Subject: [PATCH] fix: ET for simple dvt + helpers --- configs/config_mainnet.py | 9 + interfaces/ActivateNodeOperators.json | 1 + interfaces/AddNodeOperators.json | 1 + interfaces/ChangeNodeOperatorManagers.json | 1 + interfaces/DeactivateNodeOperators.json | 1 + interfaces/SetNodeOperatorNames.json | 1 + .../SetNodeOperatorRewardAddresses.json | 1 + interfaces/SetVettedValidatorsLimits.json | 1 + interfaces/SimpleDVT.json | 1 + interfaces/UpdateTargetValidatorLimits.json | 1 + tests/acceptance/conftest.py | 8 +- tests/conftest.py | 1 + tests/regression/conftest.py | 9 +- tests/regression/test_easy_track.py | 101 +++++++++++- utils/test/simple_dvt_helpers.py | 154 ++++++++++++++++++ 15 files changed, 283 insertions(+), 8 deletions(-) create mode 100644 interfaces/ActivateNodeOperators.json create mode 100644 interfaces/AddNodeOperators.json create mode 100644 interfaces/ChangeNodeOperatorManagers.json create mode 100644 interfaces/DeactivateNodeOperators.json create mode 100644 interfaces/SetNodeOperatorNames.json create mode 100644 interfaces/SetNodeOperatorRewardAddresses.json create mode 100644 interfaces/SetVettedValidatorsLimits.json create mode 100644 interfaces/SimpleDVT.json create mode 100644 interfaces/UpdateTargetValidatorLimits.json create mode 100644 utils/test/simple_dvt_helpers.py diff --git a/configs/config_mainnet.py b/configs/config_mainnet.py index 51028add..efbddf2c 100644 --- a/configs/config_mainnet.py +++ b/configs/config_mainnet.py @@ -57,6 +57,15 @@ EASYTRACK_EVMSCRIPT_EXECUTOR = "0xFE5986E06210aC1eCC1aDCafc0cc7f8D63B3F977" EASYTRACK_INCREASE_NOP_STAKING_LIMIT_FACTORY = "0xFeBd8FAC16De88206d4b18764e826AF38546AfE0" +EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER = "0x08637515E85A4633E23dfc7861e2A9f53af640f7" +EASYTRACK_SIMPLE_DVT_ADD_NODE_OPERATORS_FACTORY = "0xcAa3AF7460E83E665EEFeC73a7a542E5005C9639" +EASYTRACK_SIMPLE_DVT_ACTIVATE_NODE_OPERATORS_FACTORY = "0xCBb418F6f9BFd3525CE6aADe8F74ECFEfe2DB5C8" +EASYTRACK_SIMPLE_DVT_DEACTIVATE_NODE_OPERATORS_FACTORY = "0x8B82C1546D47330335a48406cc3a50Da732672E7" +EASYTRACK_SIMPLE_DVT_SET_VETTED_VALIDATORS_LIMITS_FACTORY = "0xD75778b855886Fc5e1eA7D6bFADA9EB68b35C19D" +EASYTRACK_SIMPLE_DVT_SET_NODE_OPERATOR_NAMES_FACTORY = "0x7d509BFF310d9460b1F613e4e40d342201a83Ae4" +EASYTRACK_SIMPLE_DVT_SET_NODE_OPERATOR_REWARD_ADDRESSES_FACTORY = "0x589e298964b9181D9938B84bB034C3BB9024E2C0" +EASYTRACK_SIMPLE_DVT_UPDATE_TARGET_VALIDATOR_LIMITS_FACTORY = "0x41CF3DbDc939c5115823Fba1432c4EC5E7bD226C" +EASYTRACK_SIMPLE_DVT_CHANGE_NODE_OPERATOR_MANAGERS_FACTORY = "0xE31A0599A6772BCf9b2bFc9e25cf941e793c9a7D" # Multisigs FINANCE_MULTISIG = "0x48F300bD3C52c7dA6aAbDE4B683dEB27d38B9ABb" diff --git a/interfaces/ActivateNodeOperators.json b/interfaces/ActivateNodeOperators.json new file mode 100644 index 00000000..2aab8904 --- /dev/null +++ b/interfaces/ActivateNodeOperators.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_nodeOperatorsRegistry","type":"address"},{"internalType":"address","name":"_acl","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"acl","outputs":[{"internalType":"contract IACL","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"address","name":"managerAddress","type":"address"}],"internalType":"struct ActivateNodeOperators.ActivateNodeOperatorInput[]","name":"","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nodeOperatorsRegistry","outputs":[{"internalType":"contract INodeOperatorsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] diff --git a/interfaces/AddNodeOperators.json b/interfaces/AddNodeOperators.json new file mode 100644 index 00000000..1b9274dc --- /dev/null +++ b/interfaces/AddNodeOperators.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_nodeOperatorsRegistry","type":"address"},{"internalType":"address","name":"_acl","type":"address"},{"internalType":"address","name":"_lido","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"acl","outputs":[{"internalType":"contract IACL","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"address","name":"managerAddress","type":"address"}],"internalType":"struct AddNodeOperators.AddNodeOperatorInput[]","name":"nodeOperators","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"lido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeOperatorsRegistry","outputs":[{"internalType":"contract INodeOperatorsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] diff --git a/interfaces/ChangeNodeOperatorManagers.json b/interfaces/ChangeNodeOperatorManagers.json new file mode 100644 index 00000000..838bf063 --- /dev/null +++ b/interfaces/ChangeNodeOperatorManagers.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_nodeOperatorsRegistry","type":"address"},{"internalType":"address","name":"_acl","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"acl","outputs":[{"internalType":"contract IACL","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"address","name":"oldManagerAddress","type":"address"},{"internalType":"address","name":"newManagerAddress","type":"address"}],"internalType":"struct ChangeNodeOperatorManagers.ChangeNodeOperatorManagersInput[]","name":"","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nodeOperatorsRegistry","outputs":[{"internalType":"contract INodeOperatorsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] diff --git a/interfaces/DeactivateNodeOperators.json b/interfaces/DeactivateNodeOperators.json new file mode 100644 index 00000000..518a2e7f --- /dev/null +++ b/interfaces/DeactivateNodeOperators.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_nodeOperatorsRegistry","type":"address"},{"internalType":"address","name":"_acl","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"acl","outputs":[{"internalType":"contract IACL","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"address","name":"managerAddress","type":"address"}],"internalType":"struct DeactivateNodeOperators.DeactivateNodeOperatorInput[]","name":"","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nodeOperatorsRegistry","outputs":[{"internalType":"contract INodeOperatorsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] diff --git a/interfaces/SetNodeOperatorNames.json b/interfaces/SetNodeOperatorNames.json new file mode 100644 index 00000000..9e299d48 --- /dev/null +++ b/interfaces/SetNodeOperatorNames.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_nodeOperatorsRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct SetNodeOperatorNames.SetNameInput[]","name":"","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nodeOperatorsRegistry","outputs":[{"internalType":"contract INodeOperatorsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] diff --git a/interfaces/SetNodeOperatorRewardAddresses.json b/interfaces/SetNodeOperatorRewardAddresses.json new file mode 100644 index 00000000..62d1c0fe --- /dev/null +++ b/interfaces/SetNodeOperatorRewardAddresses.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_nodeOperatorsRegistry","type":"address"},{"internalType":"address","name":"_lido","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"address","name":"rewardAddress","type":"address"}],"internalType":"struct SetNodeOperatorRewardAddresses.SetRewardAddressInput[]","name":"","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"lido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeOperatorsRegistry","outputs":[{"internalType":"contract INodeOperatorsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] diff --git a/interfaces/SetVettedValidatorsLimits.json b/interfaces/SetVettedValidatorsLimits.json new file mode 100644 index 00000000..1b839938 --- /dev/null +++ b/interfaces/SetVettedValidatorsLimits.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_nodeOperatorsRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"stakingLimit","type":"uint256"}],"internalType":"struct SetVettedValidatorsLimits.VettedValidatorsLimitInput[]","name":"","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nodeOperatorsRegistry","outputs":[{"internalType":"contract INodeOperatorsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] diff --git a/interfaces/SimpleDVT.json b/interfaces/SimpleDVT.json new file mode 100644 index 00000000..63223133 --- /dev/null +++ b/interfaces/SimpleDVT.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"onRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"totalVettedValidators","type":"uint64"},{"name":"totalExitedValidators","type":"uint64"},{"name":"totalAddedValidators","type":"uint64"},{"name":"totalDepositedValidators","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint256"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_STUCK_PENALTY_DELAY","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onExitedAndStuckValidatorsCountsUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file diff --git a/interfaces/UpdateTargetValidatorLimits.json b/interfaces/UpdateTargetValidatorLimits.json new file mode 100644 index 00000000..7260ce4e --- /dev/null +++ b/interfaces/UpdateTargetValidatorLimits.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_nodeOperatorsRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"internalType":"uint256","name":"targetLimit","type":"uint256"}],"internalType":"struct UpdateTargetValidatorLimits.TargetValidatorsLimit[]","name":"","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nodeOperatorsRegistry","outputs":[{"internalType":"contract INodeOperatorsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] diff --git a/tests/acceptance/conftest.py b/tests/acceptance/conftest.py index 4e7f1405..4e8d9c43 100644 --- a/tests/acceptance/conftest.py +++ b/tests/acceptance/conftest.py @@ -6,16 +6,22 @@ from utils.test.helpers import ETH from utils.test.oracle_report_helpers import oracle_report +from utils.test.simple_dvt_helpers import fill_simple_dvt_ops_vetted_keys from brownie import chain ENV_REPORT_AFTER_VOTE = "REPORT_AFTER_VOTE" +ENV_FILL_SIMPLE_DVT = "FILL_SIMPLE_DVT" + @pytest.fixture(scope="function", autouse=is_there_any_vote_scripts() or is_there_any_upgrade_scripts()) -def autoexecute_vote(helpers, vote_ids_from_env, accounts): +def autoexecute_vote(helpers, vote_ids_from_env, accounts, stranger): if vote_ids_from_env: helpers.execute_votes(accounts, vote_ids_from_env, contracts.voting, topup="0.5 ether") else: start_and_execute_votes(contracts.voting, helpers) + if os.getenv(ENV_FILL_SIMPLE_DVT): + print(f"Prefilling SimpleDVT...") + fill_simple_dvt_ops_vetted_keys(stranger) if os.getenv(ENV_REPORT_AFTER_VOTE): oracle_report(cl_diff=ETH(523), exclude_vaults_balances=False) diff --git a/tests/conftest.py b/tests/conftest.py index fe73d266..6aea0c93 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -213,6 +213,7 @@ def parse_events_from_local_abi(): "LidoExecutionLayerRewardsVault": [EXECUTION_LAYER_REWARDS_VAULT], "Kernel": [ARAGON_KERNEL_IMPL], "NodeOperatorsRegistry": [NODE_OPERATORS_REGISTRY, NODE_OPERATORS_REGISTRY_IMPL], + "SimpleDVT": [SIMPLE_DVT, SIMPLE_DVT_IMPL], "OracleDaemonConfig": [ORACLE_DAEMON_CONFIG], "OracleReportSanityChecker": [ORACLE_REPORT_SANITY_CHECKER], "Repo": [ARAGON_COMMON_REPO_IMPL], diff --git a/tests/regression/conftest.py b/tests/regression/conftest.py index 4e7f1405..dbaac6d4 100644 --- a/tests/regression/conftest.py +++ b/tests/regression/conftest.py @@ -6,16 +6,23 @@ from utils.test.helpers import ETH from utils.test.oracle_report_helpers import oracle_report +from utils.test.simple_dvt_helpers import fill_simple_dvt_ops_vetted_keys from brownie import chain ENV_REPORT_AFTER_VOTE = "REPORT_AFTER_VOTE" +ENV_FILL_SIMPLE_DVT = "FILL_SIMPLE_DVT" + @pytest.fixture(scope="function", autouse=is_there_any_vote_scripts() or is_there_any_upgrade_scripts()) -def autoexecute_vote(helpers, vote_ids_from_env, accounts): +def autoexecute_vote(helpers, vote_ids_from_env, accounts, stranger): if vote_ids_from_env: helpers.execute_votes(accounts, vote_ids_from_env, contracts.voting, topup="0.5 ether") else: start_and_execute_votes(contracts.voting, helpers) + if os.getenv(ENV_FILL_SIMPLE_DVT): + print(f"Prefilling SimpleDVT...") + fill_simple_dvt_ops_vetted_keys(stranger) + if os.getenv(ENV_REPORT_AFTER_VOTE): oracle_report(cl_diff=ETH(523), exclude_vaults_balances=False) diff --git a/tests/regression/test_easy_track.py b/tests/regression/test_easy_track.py index e7439efc..88d13836 100644 --- a/tests/regression/test_easy_track.py +++ b/tests/regression/test_easy_track.py @@ -1,14 +1,18 @@ from eth_abi.abi import encode_single -from brownie import accounts, chain, interface # type: ignore -from utils.config import contracts, EASYTRACK_INCREASE_NOP_STAKING_LIMIT_FACTORY +from brownie import accounts, chain, interface +from utils.config import ( + contracts, + EASYTRACK_INCREASE_NOP_STAKING_LIMIT_FACTORY, + EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER, + EASYTRACK_SIMPLE_DVT_ADD_NODE_OPERATORS_FACTORY, + EASYTRACK_SIMPLE_DVT_SET_VETTED_VALIDATORS_LIMITS_FACTORY, +) +from utils.test.simple_dvt_helpers import simple_dvt_add_keys, simple_dvt_add_node_operators +from utils.test.easy_track_helpers import _encode_calldata NODE_OPERATOR_ID = 0 -def _encode_calldata(signature, values): - return "0x" + encode_single(signature, values).hex() - - def test_increase_nop_staking_limit( stranger, ): @@ -48,3 +52,88 @@ def test_increase_nop_staking_limit( updated_node_operator = contracts.node_operators_registry.getNodeOperator(NODE_OPERATOR_ID, False) assert updated_node_operator["totalVettedValidators"] == new_staking_limit + + +def test_simple_dvt_add_node_operators( + stranger, +): + NEW_OPERATOR_NAMES = [ + "New Name 1", + "New Name 2", + ] + + NEW_REWARD_ADDRESSES = [ + "0x1110000000000000000000000000000000001111", + "0x1110000000000000000000000000000000002222", + ] + + NEW_MANAGERS = [ + "0x1110000000000000000000000000000011111111", + "0x1110000000000000000000000000000022222222", + ] + + input_params = [ + (NEW_OPERATOR_NAMES[0], NEW_REWARD_ADDRESSES[0], NEW_MANAGERS[0]), + (NEW_OPERATOR_NAMES[1], NEW_REWARD_ADDRESSES[1], NEW_MANAGERS[1]), + ] + (node_operators_count_before, node_operator_count_after) = simple_dvt_add_node_operators( + contracts.simple_dvt, stranger, input_params + ) + + assert node_operator_count_after == node_operators_count_before + len(input_params) + + +def test_simple_dvt_set_vetted_validators_limits( + stranger, +): + NEW_OPERATOR_NAMES = [ + "New Name 1", + ] + + NEW_REWARD_ADDRESSES = [ + "0x1110000000000000000000000000000000001111", + ] + + NEW_MANAGERS = [ + "0x1110000000000000000000000000000011111111", + ] + + input_params = [ + (NEW_OPERATOR_NAMES[0], NEW_REWARD_ADDRESSES[0], NEW_MANAGERS[0]), + ] + + (_, node_operator_count_after) = simple_dvt_add_node_operators(contracts.simple_dvt, stranger, input_params) + + no_id = node_operator_count_after - 1 + + factory = interface.SetVettedValidatorsLimits(EASYTRACK_SIMPLE_DVT_SET_VETTED_VALIDATORS_LIMITS_FACTORY) + trusted_caller = accounts.at(EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER, force=True) + + node_operator = contracts.simple_dvt.getNodeOperator(no_id, False) + new_staking_limit = node_operator["totalVettedValidators"] + 1 + + if node_operator["totalAddedValidators"] < new_staking_limit: + simple_dvt_add_keys(contracts.simple_dvt, no_id, 1) + + calldata = _encode_calldata("((uint256,uint256)[])", [[(no_id, new_staking_limit)]]) + + motions_before = contracts.easy_track.getMotions() + + tx = contracts.easy_track.createMotion(factory, calldata, {"from": trusted_caller}) + + assert len(contracts.easy_track.getMotions()) == len(motions_before) + 1 + + chain.sleep(60 * 60 * 24 * 3) + chain.mine() + + motions = contracts.easy_track.getMotions() + + contracts.easy_track.enactMotion( + motions[-1][0], + tx.events["MotionCreated"]["_evmScriptCallData"], + {"from": stranger}, + ) + + updated_node_operator = contracts.simple_dvt.getNodeOperator(no_id, False) + + assert updated_node_operator["totalVettedValidators"] == new_staking_limit diff --git a/utils/test/simple_dvt_helpers.py b/utils/test/simple_dvt_helpers.py new file mode 100644 index 00000000..8d4a2b18 --- /dev/null +++ b/utils/test/simple_dvt_helpers.py @@ -0,0 +1,154 @@ +from brownie import chain, accounts, interface +from tests.regression.test_node_operators_flow import random_pubkeys_batch, random_signatures_batch # type: ignore +from utils.config import ( + contracts, + EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER, + EASYTRACK_SIMPLE_DVT_ADD_NODE_OPERATORS_FACTORY, + EASYTRACK_SIMPLE_DVT_SET_VETTED_VALIDATORS_LIMITS_FACTORY, +) +from utils.test.easy_track_helpers import _encode_calldata + + +MIN_OP_KEYS_CNT = 10 +MIN_OPS_CNT = 3 + +OPERATOR_NAMES = [ + "Name 1", + "Name 2", + "Name 3", +] + +REWARD_ADDRESSES = [ + "0x0000000000000000000000000000000000001111", + "0x0000000000000000000000000000000000002222", + "0x0000000000000000000000000000000000003333", +] + +MANAGERS = [ + "0x0000000000000000000000000000000011111111", + "0x0000000000000000000000000000000022222222", + "0x0000000000000000000000000000000033333333", +] + + +def fill_simple_dvt_ops(stranger, min_ops_cnt=MIN_OPS_CNT): + node_operators_count_before = contracts.simple_dvt.getNodeOperatorsCount() + cnt = 0 + input_params = [] + while node_operators_count_before + cnt < min_ops_cnt: + input_params.append((OPERATOR_NAMES[cnt], REWARD_ADDRESSES[cnt], MANAGERS[cnt])) + cnt += 1 + + (node_operators_count_before, node_operator_count_after) = simple_dvt_add_node_operators( + contracts.simple_dvt, stranger, input_params + ) + assert node_operator_count_after == node_operators_count_before + cnt + assert contracts.simple_dvt.getNodeOperatorsCount() >= min_ops_cnt + + +def fill_simple_dvt_ops_keys(stranger, min_ops_cnt=MIN_OPS_CNT, min_keys_cnt=MIN_OP_KEYS_CNT): + fill_simple_dvt_ops(stranger, min_ops_cnt) + for no_id in range(0, min_ops_cnt): + unused_keys_count = contracts.simple_dvt.getUnusedSigningKeyCount(no_id) + + if unused_keys_count < min_keys_cnt: + simple_dvt_add_keys(contracts.simple_dvt, no_id, min_keys_cnt - unused_keys_count) + + assert contracts.simple_dvt.getUnusedSigningKeyCount(no_id) >= min_keys_cnt + + +def fill_simple_dvt_ops_vetted_keys(stranger, min_ops_cnt=MIN_OPS_CNT, min_keys_cnt=MIN_OP_KEYS_CNT): + fill_simple_dvt_ops_keys(stranger, min_ops_cnt, min_keys_cnt) + factory = interface.SetVettedValidatorsLimits(EASYTRACK_SIMPLE_DVT_SET_VETTED_VALIDATORS_LIMITS_FACTORY) + trusted_caller = accounts.at(EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER, force=True) + + input_params = [] + for no_id in range(0, min_ops_cnt): + no = contracts.simple_dvt.getNodeOperator(no_id, False) + + if no["totalVettedValidators"] < no["totalAddedValidators"]: + input_params.append((no_id, no["totalAddedValidators"])) + + if len(input_params) > 0: + calldata = _encode_calldata("((uint256,uint256)[])", [input_params]) + + motions_before = contracts.easy_track.getMotions() + + tx = contracts.easy_track.createMotion(factory, calldata, {"from": trusted_caller}) + motions = contracts.easy_track.getMotions() + + assert len(motions) == len(motions_before) + 1 + + chain.sleep(60 * 60 * 24 * 3) + chain.mine() + + contracts.easy_track.enactMotion( + motions[-1][0], + tx.events["MotionCreated"]["_evmScriptCallData"], + {"from": stranger}, + ) + + for no_id in range(0, min_ops_cnt): + no = contracts.simple_dvt.getNodeOperator(no_id, False) + + assert no["totalVettedValidators"] == no["totalAddedValidators"] + + +def simple_dvt_add_node_operators(simple_dvt, stranger, input_params=[]): + factory = interface.AddNodeOperators(EASYTRACK_SIMPLE_DVT_ADD_NODE_OPERATORS_FACTORY) + trusted_caller = accounts.at(EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER, force=True) + + node_operators_count_before = simple_dvt.getNodeOperatorsCount() + + # input_params = [ + # (OPERATOR_NAMES[0], REWARD_ADDRESSES[0], MANAGERS[0]), + # (OPERATOR_NAMES[1], REWARD_ADDRESSES[1], MANAGERS[1]), + # ] + if len(input_params) > 0: + calldata = _encode_calldata( + "(uint256,(string,address,address)[])", + [ + node_operators_count_before, + input_params, + ], + ) + motions_before = contracts.easy_track.getMotions() + + tx = contracts.easy_track.createMotion(factory, calldata, {"from": trusted_caller}) + + motions = contracts.easy_track.getMotions() + assert len(motions) == len(motions_before) + 1 + + chain.sleep(60 * 60 * 24 * 3) + chain.mine() + + contracts.easy_track.enactMotion( + motions[-1][0], + tx.events["MotionCreated"]["_evmScriptCallData"], + {"from": stranger}, + ) + + return (node_operators_count_before, simple_dvt.getNodeOperatorsCount()) + + +def simple_dvt_add_keys(simple_dvt, node_operator_id, keys_count=1): + pubkeys_batch = random_pubkeys_batch(keys_count) + signatures_batch = random_signatures_batch(keys_count) + + total_signing_keys_count_before = simple_dvt.getTotalSigningKeyCount(node_operator_id) + unused_signing_keys_count_before = simple_dvt.getUnusedSigningKeyCount(node_operator_id) + node_operator_before = simple_dvt.getNodeOperator(node_operator_id, True) + + tx = simple_dvt.addSigningKeys( + node_operator_id, + keys_count, + pubkeys_batch, + signatures_batch, + {"from": node_operator_before["rewardAddress"]}, + ) + + total_signing_keys_count_after = simple_dvt.getTotalSigningKeyCount(node_operator_id) + unused_signing_keys_count_after = simple_dvt.getUnusedSigningKeyCount(node_operator_id) + + assert total_signing_keys_count_after == total_signing_keys_count_before + keys_count + assert unused_signing_keys_count_after == unused_signing_keys_count_before + keys_count