diff --git a/archive/scripts/vote_2023_10_31.py b/archive/scripts/vote_2023_10_31.py new file mode 100644 index 00000000..39df96ff --- /dev/null +++ b/archive/scripts/vote_2023_10_31.py @@ -0,0 +1,109 @@ +""" +Voting 31/10/2023. + +I. stETH transfers to RCC PML ATC +1. Transfer 279 stETH to RCC 0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437 +2. Transfer 447 stETH to PML 0x17F6b2C738a63a8D3A113a228cfd0b373244633D +3. Transfer 391 stETH to ATC 0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956 + +II. Change the on-chain name of node operator with id 27 from 'Prysmatic Labs' to 'Prysm Team at Offchain Labs' +4. Change node operator name from Prysmatic Labs to Prysm Team at Offchain Labs + +The vote REJECTED. +""" + +import time + +from typing import Dict +from brownie import interface +from brownie.network.transaction import TransactionReceipt +from utils.agent import agent_forward +from utils.voting import bake_vote_items, confirm_vote_script, create_vote +from utils.ipfs import upload_vote_ipfs_description, calculate_vote_ipfs_description +from utils.node_operators import encode_set_node_operator_name +from utils.finance import make_steth_payout +from utils.config import ( + contracts, + get_deployer_account, + get_is_live, + get_priority_fee, +) + +description = """ +### Omnibus on-chain vote contains: + +1. stETH transfer to the [Lido Contributors Group multisigs](https://research.lido.fi/t/ref-introducing-the-lido-contributors-group-including-pool-maintenance-labs-and-argo-technology-consulting/3069) ([RCC](https://app.safe.global/settings/setup?safe=eth:0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437), [PML](https://app.safe.global/settings/setup?safe=eth:0x17F6b2C738a63a8D3A113a228cfd0b373244633D), and [ATC](https://app.safe.global/settings/setup?safe=eth:0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956)), as previously [requested on the forum](https://research.lido.fi/t/lido-v2-may-1-2023-december-31-2023-lido-ongoing-grant-request/4476/11). Items 1-3. +2. Changing the Node Operator's (#id - 27) name, as [requested on the forum](https://research.lido.fi/t/node-operator-registry-name-reward-address-change/4170/16). Item 4. +""" + +def start_vote(tx_params: Dict[str, str], silent: bool) -> bool | list[int | TransactionReceipt | None]: + """Prepare and run voting.""" + + rcc_multisig_address = "0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437" + pml_multisig_address = "0x17F6b2C738a63a8D3A113a228cfd0b373244633D" + atc_multisig_address = "0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956" + + NO_registry = interface.NodeOperatorsRegistry(contracts.node_operators_registry) + prysmatic_labs_node_id = 27 + prysmatic_labs_node_new_name = "Prysm Team at Offchain Labs" + + call_script_items = [ + # I. stETH transfers to RCC PML ATC + # 1. Transfer 279 stETH to RCC 0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437 + make_steth_payout( + target_address=rcc_multisig_address, + steth_in_wei=279 * (10**18), + reference="Fund RCC multisig" + ), + # 2. Transfer 447 stETH to PML 0x17F6b2C738a63a8D3A113a228cfd0b373244633D + make_steth_payout( + target_address=pml_multisig_address, + steth_in_wei=447 * (10**18), + reference="Fund PML multisig" + ), + # 3. Transfer 391 stETH to ATC 0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956 + make_steth_payout( + target_address=atc_multisig_address, + steth_in_wei=391 * (10**18), + reference="Fund ATC multisig" + ), + # II. Change the on-chain name of node operator with id 27 from 'Prysmatic Labs' to 'Prysm Team at Offchain Labs' + # 4. Change node operator #27 name from `Prysmatic Labs` to `Prysm Team at Offchain Labs` + agent_forward([ + encode_set_node_operator_name( + prysmatic_labs_node_id, + prysmatic_labs_node_new_name, + NO_registry + ) + ]) + ] + + vote_desc_items = [ + f"1) Transfer 279 stETH to RCC 0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437", + f"2) Transfer 447 stETH to PML 0x17F6b2C738a63a8D3A113a228cfd0b373244633D", + f"3) Transfer 391 stETH to ATC 0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956", + f"4) Change the on-chain name of node operator with id 27 from 'Prysmatic Labs' to 'Prysm Team at Offchain Labs'", + ] + + vote_items = bake_vote_items(vote_desc_items, call_script_items) + + if silent: + desc_ipfs = calculate_vote_ipfs_description(description) + else: + desc_ipfs = upload_vote_ipfs_description(description) + + return confirm_vote_script(vote_items, silent, desc_ipfs) and list( + create_vote(vote_items, tx_params, desc_ipfs=desc_ipfs) + ) + + +def main(): + tx_params = {"from": get_deployer_account()} + if get_is_live(): + tx_params["priority_fee"] = get_priority_fee() + + vote_id, _ = start_vote(tx_params=tx_params, silent=False) + + vote_id >= 0 and print(f"Vote created: {vote_id}.") + + time.sleep(5) # hack for waiting thread #2. diff --git a/archive/scripts/vote_2023_11_07.py b/archive/scripts/vote_2023_11_07.py new file mode 100644 index 00000000..a37b29db --- /dev/null +++ b/archive/scripts/vote_2023_11_07.py @@ -0,0 +1,111 @@ +""" +Voting 07/11/2023. + +I. stETH transfers to RCC PML ATC +1. Transfer 272 stETH to RCC 0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437 +2. Transfer 434 stETH to PML 0x17F6b2C738a63a8D3A113a228cfd0b373244633D +3. Transfer 380 stETH to ATC 0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956 + +II. Change the on-chain name of node operator with id 27 from 'Prysmatic Labs' to 'Prysm Team at Offchain Labs' +4. Change node operator name from Prysmatic Labs to Prysm Team at Offchain Labs + +Vote passed & executed on Nov-10-2023 02:43:23 PM +UTC, block 18542216 +""" + +import time + +from typing import Dict +from brownie import interface +from brownie.network.transaction import TransactionReceipt +from utils.agent import agent_forward +from utils.voting import bake_vote_items, confirm_vote_script, create_vote +from utils.ipfs import upload_vote_ipfs_description, calculate_vote_ipfs_description +from utils.node_operators import encode_set_node_operator_name +from utils.finance import make_steth_payout +from utils.config import ( + contracts, + get_deployer_account, + get_is_live, + get_priority_fee, +) + +description = """ +### Omnibus on-chain vote contains: + +1. stETH transfer to the [Lido Contributors Group multisigs](https://research.lido.fi/t/ref-introducing-the-lido-contributors-group-including-pool-maintenance-labs-and-argo-technology-consulting/3069) ([RCC](https://app.safe.global/settings/setup?safe=eth:0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437), [PML](https://app.safe.global/settings/setup?safe=eth:0x17F6b2C738a63a8D3A113a228cfd0b373244633D), and [ATC](https://app.safe.global/settings/setup?safe=eth:0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956)), as previously [requested on the forum](https://research.lido.fi/t/lido-v2-may-1-2023-december-31-2023-lido-ongoing-grant-request/4476/11). Items 1-3. +2. Changing the Node Operator's (#id - 27) name, as [requested on the forum](https://research.lido.fi/t/node-operator-registry-name-reward-address-change/4170/16). Item 4. + +That's a rerun of [vote #166](https://vote.lido.fi/vote/166). +""" + +def start_vote(tx_params: Dict[str, str], silent: bool) -> bool | list[int | TransactionReceipt | None]: + """Prepare and run voting.""" + + rcc_multisig_address = "0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437" + pml_multisig_address = "0x17F6b2C738a63a8D3A113a228cfd0b373244633D" + atc_multisig_address = "0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956" + + NO_registry = interface.NodeOperatorsRegistry(contracts.node_operators_registry) + prysmatic_labs_node_id = 27 + prysmatic_labs_node_new_name = "Prysm Team at Offchain Labs" + + call_script_items = [ + # I. stETH transfers to RCC PML ATC + # 1. Transfer 272 stETH to RCC 0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437 + make_steth_payout( + target_address=rcc_multisig_address, + steth_in_wei=272 * (10**18), + reference="Fund RCC multisig" + ), + # 2. Transfer 434 stETH to PML 0x17F6b2C738a63a8D3A113a228cfd0b373244633D + make_steth_payout( + target_address=pml_multisig_address, + steth_in_wei=434 * (10**18), + reference="Fund PML multisig" + ), + # 3. Transfer 380 stETH to ATC 0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956 + make_steth_payout( + target_address=atc_multisig_address, + steth_in_wei=380 * (10**18), + reference="Fund ATC multisig" + ), + # II. Change the on-chain name of node operator with id 27 from 'Prysmatic Labs' to 'Prysm Team at Offchain Labs' + # 4. Change node operator #27 name from `Prysmatic Labs` to `Prysm Team at Offchain Labs` + agent_forward([ + encode_set_node_operator_name( + prysmatic_labs_node_id, + prysmatic_labs_node_new_name, + NO_registry + ) + ]) + ] + + vote_desc_items = [ + f"1) Transfer 272 stETH to RCC 0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437", + f"2) Transfer 434 stETH to PML 0x17F6b2C738a63a8D3A113a228cfd0b373244633D", + f"3) Transfer 380 stETH to ATC 0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956", + f"4) Change the on-chain name of node operator with id 27 from 'Prysmatic Labs' to 'Prysm Team at Offchain Labs'", + ] + + vote_items = bake_vote_items(vote_desc_items, call_script_items) + + if silent: + desc_ipfs = calculate_vote_ipfs_description(description) + else: + desc_ipfs = upload_vote_ipfs_description(description) + + return confirm_vote_script(vote_items, silent, desc_ipfs) and list( + create_vote(vote_items, tx_params, desc_ipfs=desc_ipfs) + ) + + +def main(): + tx_params = {"from": get_deployer_account()} + if get_is_live(): + tx_params["priority_fee"] = get_priority_fee() + + vote_id, _ = start_vote(tx_params=tx_params, silent=False) + + vote_id >= 0 and print(f"Vote created: {vote_id}.") + + time.sleep(5) # hack for waiting thread #2. diff --git a/archive/tests/test_2023_10_31.py b/archive/tests/test_2023_10_31.py new file mode 100644 index 00000000..a6d50fa1 --- /dev/null +++ b/archive/tests/test_2023_10_31.py @@ -0,0 +1,100 @@ +""" +Tests for voting 31/10/2023 + +""" + +from scripts.vote_2023_10_31 import start_vote +from brownie import interface +from utils.test.tx_tracing_helpers import * +from utils.test.event_validators.payout import ( + Payout, + validate_token_payout_event +) +from utils.test.event_validators.permission import Permission +from utils.test.event_validators.node_operators_registry import ( + validate_node_operator_name_set_event, + NodeOperatorNameSetItem, +) +from utils.config import ( + contracts, + LDO_HOLDER_ADDRESS_FOR_TESTS, + LIDO, + AGENT +) + +def test_vote( + helpers, + accounts, + vote_ids_from_env +): + rcc_multisig_address = "0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437" + pml_multisig_address = "0x17F6b2C738a63a8D3A113a228cfd0b373244633D" + atc_multisig_address = "0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956" + + rcc_multisig_balance_before = contracts.lido.balanceOf(rcc_multisig_address) + pml_multisig_balance_before = contracts.lido.balanceOf(pml_multisig_address) + atc_multisig_balance_before = contracts.lido.balanceOf(atc_multisig_address) + dao_balance_before = contracts.lido.balanceOf(AGENT) + + NO_registry = interface.NodeOperatorsRegistry(contracts.node_operators_registry) + prysmatic_labs_node_id = 27 + prysmatic_labs_node_old_name = "Prysmatic Labs" + prysmatic_labs_node_new_name = "Prysm Team at Offchain Labs" + prysmatic_labs_node_data_before_voting = NO_registry.getNodeOperator(prysmatic_labs_node_id, True) + + # Check node operator name before + assert prysmatic_labs_node_data_before_voting["name"] == prysmatic_labs_node_old_name, "Incorrect NO#27 name before" + + # START VOTE + if len(vote_ids_from_env) > 0: + (vote_id,) = vote_ids_from_env + else: + tx_params = {"from": LDO_HOLDER_ADDRESS_FOR_TESTS} + vote_id, _ = start_vote(tx_params, silent=True) + + vote_tx = helpers.execute_vote(accounts, vote_id, contracts.voting) + + print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}") + + rcc_multisig_balance_after = contracts.lido.balanceOf(rcc_multisig_address) + pml_multisig_balance_after = contracts.lido.balanceOf(pml_multisig_address) + atc_multisig_balance_after = contracts.lido.balanceOf(atc_multisig_address) + dao_balance_after = contracts.lido.balanceOf(AGENT) + + rcc_fund_payout = Payout(token_addr=LIDO, from_addr=contracts.agent, to_addr=rcc_multisig_address, amount=279 * (10**18)) + pml_fund_payout = Payout(token_addr=LIDO, from_addr=contracts.agent, to_addr=pml_multisig_address, amount=447 * (10**18)) + atc_fund_payout = Payout(token_addr=LIDO, from_addr=contracts.agent, to_addr=atc_multisig_address, amount=391 * (10**18)) + + steth_balance_checker(rcc_multisig_balance_after - rcc_multisig_balance_before, rcc_fund_payout.amount) + steth_balance_checker(pml_multisig_balance_after - pml_multisig_balance_before, pml_fund_payout.amount) + steth_balance_checker(atc_multisig_balance_after - atc_multisig_balance_before, atc_fund_payout.amount) + steth_balance_checker(dao_balance_before - dao_balance_after, rcc_fund_payout.amount + pml_fund_payout.amount + atc_fund_payout.amount) + + # node operator name + prysmatic_labs_node_data_after_voting = NO_registry.getNodeOperator(prysmatic_labs_node_id, True) + + assert prysmatic_labs_node_data_before_voting["active"] == prysmatic_labs_node_data_after_voting["active"] + assert prysmatic_labs_node_data_after_voting["name"] == prysmatic_labs_node_new_name, "Incorrect NO#27 name after" + assert prysmatic_labs_node_data_before_voting["rewardAddress"] == prysmatic_labs_node_data_after_voting["rewardAddress"] + compare_NO_validators_data(prysmatic_labs_node_data_before_voting, prysmatic_labs_node_data_after_voting) + + # validate vote events + assert count_vote_items_by_events(vote_tx, contracts.voting) == 4, "Incorrect voting items count" + + display_voting_events(vote_tx) + + evs = group_voting_events(vote_tx) + + validate_token_payout_event(evs[0], rcc_fund_payout, True) + validate_token_payout_event(evs[1], pml_fund_payout, True) + validate_token_payout_event(evs[2], atc_fund_payout, True) + validate_node_operator_name_set_event(evs[3], NodeOperatorNameSetItem(nodeOperatorId=prysmatic_labs_node_id, name=prysmatic_labs_node_new_name)) + +def steth_balance_checker(lhs_value: int, rhs_value: int): + assert (lhs_value + 5) // 10 == (rhs_value + 5) // 10 + +def compare_NO_validators_data(data_before, data_after): + assert data_before["totalVettedValidators"] == data_after["totalVettedValidators"] + assert data_before["totalExitedValidators"] == data_after["totalExitedValidators"] + assert data_before["totalAddedValidators"] == data_after["totalAddedValidators"] + assert data_before["totalDepositedValidators"] == data_after["totalDepositedValidators"] \ No newline at end of file diff --git a/archive/tests/test_2023_11_07.py b/archive/tests/test_2023_11_07.py new file mode 100644 index 00000000..762d7975 --- /dev/null +++ b/archive/tests/test_2023_11_07.py @@ -0,0 +1,100 @@ +""" +Tests for voting 07/11/2023 + +""" + +from scripts.vote_2023_11_07 import start_vote +from brownie import interface +from utils.test.tx_tracing_helpers import * +from utils.test.event_validators.payout import ( + Payout, + validate_token_payout_event +) +from utils.test.event_validators.permission import Permission +from utils.test.event_validators.node_operators_registry import ( + validate_node_operator_name_set_event, + NodeOperatorNameSetItem, +) +from utils.config import ( + contracts, + LDO_HOLDER_ADDRESS_FOR_TESTS, + LIDO, + AGENT +) + +def test_vote( + helpers, + accounts, + vote_ids_from_env +): + rcc_multisig_address = "0xDE06d17Db9295Fa8c4082D4f73Ff81592A3aC437" + pml_multisig_address = "0x17F6b2C738a63a8D3A113a228cfd0b373244633D" + atc_multisig_address = "0x9B1cebF7616f2BC73b47D226f90b01a7c9F86956" + + rcc_multisig_balance_before = contracts.lido.balanceOf(rcc_multisig_address) + pml_multisig_balance_before = contracts.lido.balanceOf(pml_multisig_address) + atc_multisig_balance_before = contracts.lido.balanceOf(atc_multisig_address) + dao_balance_before = contracts.lido.balanceOf(AGENT) + + NO_registry = interface.NodeOperatorsRegistry(contracts.node_operators_registry) + prysmatic_labs_node_id = 27 + prysmatic_labs_node_old_name = "Prysmatic Labs" + prysmatic_labs_node_new_name = "Prysm Team at Offchain Labs" + prysmatic_labs_node_data_before_voting = NO_registry.getNodeOperator(prysmatic_labs_node_id, True) + + # Check node operator name before + assert prysmatic_labs_node_data_before_voting["name"] == prysmatic_labs_node_old_name, "Incorrect NO#27 name before" + + # START VOTE + if len(vote_ids_from_env) > 0: + (vote_id,) = vote_ids_from_env + else: + tx_params = {"from": LDO_HOLDER_ADDRESS_FOR_TESTS} + vote_id, _ = start_vote(tx_params, silent=True) + + vote_tx = helpers.execute_vote(accounts, vote_id, contracts.voting) + + print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}") + + rcc_multisig_balance_after = contracts.lido.balanceOf(rcc_multisig_address) + pml_multisig_balance_after = contracts.lido.balanceOf(pml_multisig_address) + atc_multisig_balance_after = contracts.lido.balanceOf(atc_multisig_address) + dao_balance_after = contracts.lido.balanceOf(AGENT) + + rcc_fund_payout = Payout(token_addr=LIDO, from_addr=contracts.agent, to_addr=rcc_multisig_address, amount=272 * (10**18)) + pml_fund_payout = Payout(token_addr=LIDO, from_addr=contracts.agent, to_addr=pml_multisig_address, amount=434 * (10**18)) + atc_fund_payout = Payout(token_addr=LIDO, from_addr=contracts.agent, to_addr=atc_multisig_address, amount=380 * (10**18)) + + steth_balance_checker(rcc_multisig_balance_after - rcc_multisig_balance_before, rcc_fund_payout.amount) + steth_balance_checker(pml_multisig_balance_after - pml_multisig_balance_before, pml_fund_payout.amount) + steth_balance_checker(atc_multisig_balance_after - atc_multisig_balance_before, atc_fund_payout.amount) + steth_balance_checker(dao_balance_before - dao_balance_after, rcc_fund_payout.amount + pml_fund_payout.amount + atc_fund_payout.amount) + + # node operator name + prysmatic_labs_node_data_after_voting = NO_registry.getNodeOperator(prysmatic_labs_node_id, True) + + assert prysmatic_labs_node_data_before_voting["active"] == prysmatic_labs_node_data_after_voting["active"] + assert prysmatic_labs_node_data_after_voting["name"] == prysmatic_labs_node_new_name, "Incorrect NO#27 name after" + assert prysmatic_labs_node_data_before_voting["rewardAddress"] == prysmatic_labs_node_data_after_voting["rewardAddress"] + compare_NO_validators_data(prysmatic_labs_node_data_before_voting, prysmatic_labs_node_data_after_voting) + + # validate vote events + assert count_vote_items_by_events(vote_tx, contracts.voting) == 4, "Incorrect voting items count" + + display_voting_events(vote_tx) + + evs = group_voting_events(vote_tx) + + validate_token_payout_event(evs[0], rcc_fund_payout, True) + validate_token_payout_event(evs[1], pml_fund_payout, True) + validate_token_payout_event(evs[2], atc_fund_payout, True) + validate_node_operator_name_set_event(evs[3], NodeOperatorNameSetItem(nodeOperatorId=prysmatic_labs_node_id, name=prysmatic_labs_node_new_name)) + +def steth_balance_checker(lhs_value: int, rhs_value: int): + assert (lhs_value + 5) // 10 == (rhs_value + 5) // 10 + +def compare_NO_validators_data(data_before, data_after): + assert data_before["totalVettedValidators"] == data_after["totalVettedValidators"] + assert data_before["totalExitedValidators"] == data_after["totalExitedValidators"] + assert data_before["totalAddedValidators"] == data_after["totalAddedValidators"] + assert data_before["totalDepositedValidators"] == data_after["totalDepositedValidators"] \ No newline at end of file diff --git a/configs/config_mainnet.py b/configs/config_mainnet.py index e02936df..bf30d49c 100644 --- a/configs/config_mainnet.py +++ b/configs/config_mainnet.py @@ -75,6 +75,8 @@ ] # General network addresses DAI_TOKEN = "0x6b175474e89094c44da98b954eedeac495271d0f" +USDT_TOKEN = "0xdac17f958d2ee523a2206206994597c13d831ec7" +USDC_TOKEN = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" WETH_TOKEN = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" # diff --git a/contracts/EtherFunder.vy b/contracts/EtherFunder.vy index 4febb6b8..cc8b3e60 100644 --- a/contracts/EtherFunder.vy +++ b/contracts/EtherFunder.vy @@ -1,4 +1,4 @@ -# @version 0.3.1 +# @version 0.3.7 # @author psirex # @licence MIT diff --git a/contracts/MockCallTarget.vy b/contracts/MockCallTarget.vy index bee1c4c3..1dd30b36 100644 --- a/contracts/MockCallTarget.vy +++ b/contracts/MockCallTarget.vy @@ -1,4 +1,4 @@ -# @version 0.2.15 +# @version 0.3.7 called: public(bool) diff --git a/contracts/OnchainMetrics.vy b/contracts/OnchainMetrics.vy index 9d359bb0..d70bba3d 100644 --- a/contracts/OnchainMetrics.vy +++ b/contracts/OnchainMetrics.vy @@ -1,4 +1,4 @@ -# @version 0.2.15 +# @version 0.3.7 # @author skozin # @licence MIT diff --git a/contracts/RewardsManagerTokensRecoverer.vy b/contracts/RewardsManagerTokensRecoverer.vy index 9bd5d4fa..acaabc52 100644 --- a/contracts/RewardsManagerTokensRecoverer.vy +++ b/contracts/RewardsManagerTokensRecoverer.vy @@ -1,4 +1,4 @@ -# @version 0.3.1 +# @version 0.3.7 # @notice A contract to recover tokens from RewardsManager contract # @license MIT diff --git a/interfaces/TopUpAllowedRecipients.json b/interfaces/TopUpAllowedRecipients.json index db2756e9..45e69579 100644 --- a/interfaces/TopUpAllowedRecipients.json +++ b/interfaces/TopUpAllowedRecipients.json @@ -13,12 +13,12 @@ }, { "internalType": "address", - "name": "_finance", + "name": "_allowedTokensRegistry", "type": "address" }, { "internalType": "address", - "name": "_token", + "name": "_finance", "type": "address" }, { @@ -35,7 +35,20 @@ "name": "allowedRecipientsRegistry", "outputs": [ { - "internalType": "contract AllowedRecipientsRegistry", + "internalType": "contract IAllowedRecipientsRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "allowedTokensRegistry", + "outputs": [ + { + "internalType": "contract IAllowedTokensRegistry", "name": "", "type": "address" } @@ -77,6 +90,11 @@ ], "name": "decodeEVMScriptCallData", "outputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, { "internalType": "address[]", "name": "recipients", @@ -96,7 +114,7 @@ "name": "easyTrack", "outputs": [ { - "internalType": "contract EasyTrack", + "internalType": "contract IEasyTrack", "name": "", "type": "address" } @@ -117,19 +135,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "token", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "trustedCaller", diff --git a/network-config.yaml b/network-config.yaml index 86250b3b..a57a33a3 100644 --- a/network-config.yaml +++ b/network-config.yaml @@ -3,13 +3,13 @@ development: cmd_settings: accounts: 10 fork: mainnet - gas_limit: 12000000 + gas_limit: 30000000 mnemonic: brownie port: 8545 host: http://127.0.0.1 id: mainnet-fork name: Ganache-CLI (Mainnet Fork) - timeout: 180 + timeout: 360 # https://github.com/mds1/multicall#multicall2-contract-addresses multicall2: "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696" - cmd: ./ganache.sh @@ -17,25 +17,25 @@ development: accounts: 10 chain_id: 5 fork: goerli - gas_limit: 12000000 + gas_limit: 30000000 mnemonic: brownie port: 8545 host: http://127.0.0.1 id: goerli-fork name: goerli-fork - timeout: 180 + timeout: 360 - cmd: ./ganache.sh cmd_settings: accounts: 10 chain_id: 1337 fork: http://127.0.0.1:7777 - gas_limit: 12000000 + gas_limit: 30000000 mnemonic: brownie port: 8545 host: http://127.0.0.1 id: local-fork name: local-fork explorer: https://api.etherscan.io/api - timeout: 180 + timeout: 360 # https://github.com/mds1/multicall#multicall2-contract-addresses multicall2: "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696" diff --git a/tests/acceptance/test_accounting_oracle_negative.py b/tests/acceptance/test_accounting_oracle_negative.py index 0412fbaa..8e5241f4 100644 --- a/tests/acceptance/test_accounting_oracle_negative.py +++ b/tests/acceptance/test_accounting_oracle_negative.py @@ -179,8 +179,8 @@ class TestSubmitReportExtraDataList: def test_too_short_extra_data_item(self): extra_data = b"".join( ( - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [2]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [1], [2])[:36], + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [2]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [2], [2])[:36], ) ) @@ -189,8 +189,8 @@ def test_too_short_extra_data_item(self): extra_data = b"".join( ( - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1, 2, 3, 4], [2]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [1], [2]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2, 3, 4, 5], [2]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [2], [2]), ) ) @@ -200,7 +200,7 @@ def test_too_short_extra_data_item(self): def test_nos_count_zero(self): extra_data = b"".join( ( - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [2]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [2]), build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [], [1]), ) ) @@ -211,8 +211,8 @@ def test_nos_count_zero(self): def test_module_id_zero(self): extra_data = b"".join( ( - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [2]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 0, [1], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [2]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 0, [2], [1]), ) ) @@ -220,11 +220,10 @@ def test_module_id_zero(self): self.report(extra_data) def test_unexpected_extra_data_index(self): - extra_data = b"".join( ( - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [1]), - build_extra_data_item(2, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [1], [1]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), + build_extra_data_item(2, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [2], [1]), ) ) @@ -233,8 +232,8 @@ def test_unexpected_extra_data_index(self): extra_data = b"".join( ( - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [1]), - build_extra_data_item(3, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), + build_extra_data_item(3, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), ) ) @@ -243,8 +242,8 @@ def test_unexpected_extra_data_index(self): extra_data = b"".join( ( - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [1]), - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), ) ) @@ -265,8 +264,8 @@ def test_unsupported_extra_data_type(self): def test_invalid_extra_data_sort_order(self): extra_data = b"".join( ( - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [1]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [1], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), ) ) @@ -280,8 +279,8 @@ def test_invalid_extra_data_sort_order(self): extra_data = b"".join( ( - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [1], [1]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [1], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [38], [1]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [38], [1]), ) ) @@ -295,8 +294,8 @@ def test_invalid_extra_data_sort_order(self): def test_unexpected_extra_data_item(self, extra_data_service: ExtraDataService) -> None: extra_data = extra_data_service.collect( - {(1, 1): 1}, - {(1, 1): 1}, + {(1, 38): 1}, + {(1, 38): 1}, MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT, 1, ) @@ -322,8 +321,8 @@ def test_already_processed( extra_data_service: ExtraDataService, ): extra_data = extra_data_service.collect( - {(1, 1): 1}, - {(1, 1): 1}, + {(1, 38): 1}, + {(1, 38): 1}, MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT, 1, ) diff --git a/tests/acceptance/test_lido.py b/tests/acceptance/test_lido.py index c06bd63a..001d7e35 100644 --- a/tests/acceptance/test_lido.py +++ b/tests/acceptance/test_lido.py @@ -86,6 +86,8 @@ def test_steth(contract): def test_lido_state(contract): stake_limit = contract.getStakeLimitFullInfo() + (total_exited_validators, _, _) = contracts.staking_router.getStakingModuleSummary(1) + assert stake_limit["isStakingPaused"] == False assert stake_limit["isStakingLimitSet"] == True assert stake_limit["maxStakeLimit"] == LIDO_MAX_STAKE_LIMIT_ETH * ONE_ETH @@ -97,7 +99,7 @@ def test_lido_state(contract): assert beacon_stat["beaconValidators"] >= last_seen_beacon_validators # might break once enough exited validators registered # they are not excluded from the 'beaconValidators' counter even though have zero balance - assert beacon_stat["beaconBalance"] >= 31 * 1e18 * beacon_stat["beaconValidators"], "no full withdrawals happened" + assert beacon_stat["beaconBalance"] >= 32 * 1e18 * (beacon_stat["beaconValidators"] - total_exited_validators), "no full withdrawals happened" assert beacon_stat["depositedValidators"] >= beacon_stat["beaconValidators"] assert contract.getTotalELRewardsCollected() >= last_seen_total_rewards_collected diff --git a/tests/acceptance/test_veb_negative.py b/tests/acceptance/test_veb_negative.py index a5cad6ba..19356e2b 100644 --- a/tests/acceptance/test_veb_negative.py +++ b/tests/acceptance/test_veb_negative.py @@ -221,7 +221,7 @@ def test_handle_consensus_report_data_wrong_module_id(contract, ref_slot): def test_handle_consensus_report_data_second_exit(contract, ref_slot): - no_global_index = (module_id, no_id) = (1, 1) + no_global_index = (module_id, no_id) = (1, 38) validator_id = 1 validator_key = contracts.node_operators_registry.getSigningKey(no_id, validator_id)[0] validator = LidoValidator(validator_id, validator_key) @@ -287,7 +287,7 @@ def test_handle_consensus_report_data_second_exit(contract, ref_slot): def test_handle_consensus_report_data_invalid_request_order(contract, ref_slot): - no_global_index = (_, no_id) = (1, 1) + no_global_index = (_, no_id) = (1, 38) validator_id = 1 validator_key = contracts.node_operators_registry.getSigningKey(no_id, validator_id)[0] validator = LidoValidator(validator_id, validator_key) diff --git a/tests/regression/test_accounting_oracle_extra_data.py b/tests/regression/test_accounting_oracle_extra_data.py index c9a24e21..13b991cd 100644 --- a/tests/regression/test_accounting_oracle_extra_data.py +++ b/tests/regression/test_accounting_oracle_extra_data.py @@ -21,8 +21,8 @@ def test_accounting_oracle_too_node_ops_per_extra_data_item(extra_data_service): item_count = MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT extra_data = extra_data_service.collect( - {(1, i): i for i in range(nos_per_item_count)}, - {(1, i): get_exited_count(i) for i in range(nos_per_item_count)}, + {(1, i): i for i in range(20, 20 + nos_per_item_count)}, + {(1, i): get_exited_count(i) for i in range(20, 20 + nos_per_item_count)}, item_count, nos_per_item_count, ) diff --git a/tests/regression/test_node-operators-registry-happy-path.py b/tests/regression/test_node-operators-registry-happy-path.py index c5557587..9eeb3277 100644 --- a/tests/regression/test_node-operators-registry-happy-path.py +++ b/tests/regression/test_node-operators-registry-happy-path.py @@ -1,6 +1,7 @@ import pytest from web3 import Web3 -from brownie import chain, ZERO_ADDRESS +import eth_abi +from brownie import chain, ZERO_ADDRESS, web3 from utils.test.extra_data import ( ExtraDataService, @@ -276,17 +277,23 @@ def test_node_operators(nor, extra_data_service, impersonated_voting, eth_whale) assert nor.isOperatorPenalized(base_no_id) == False # Events - assert extra_report_tx.events["ExitedSigningKeysCountChanged"][0]["nodeOperatorId"] == tested_no_id_first - assert extra_report_tx.events["ExitedSigningKeysCountChanged"][0]["exitedValidatorsCount"] == 5 - - assert extra_report_tx.events["ExitedSigningKeysCountChanged"][1]["nodeOperatorId"] == tested_no_id_second - assert extra_report_tx.events["ExitedSigningKeysCountChanged"][1]["exitedValidatorsCount"] == 5 + exited_signing_keys_count_events = parse_exited_signing_keys_count_changed_logs( + filter_transfer_logs(extra_report_tx.logs, web3.keccak(text="ExitedSigningKeysCountChanged(uint256,uint256)")) + ) + assert exited_signing_keys_count_events[0]["nodeOperatorId"] == tested_no_id_first + assert exited_signing_keys_count_events[0]["exitedValidatorsCount"] == 5 - assert extra_report_tx.events["StuckPenaltyStateChanged"][0]["nodeOperatorId"] == tested_no_id_first - assert extra_report_tx.events["StuckPenaltyStateChanged"][0]["stuckValidatorsCount"] == 2 + assert exited_signing_keys_count_events[1]["nodeOperatorId"] == tested_no_id_second + assert exited_signing_keys_count_events[1]["exitedValidatorsCount"] == 5 + + stuck_penalty_state_changed_events = parse_stuck_penalty_state_changed_logs( + filter_transfer_logs(extra_report_tx.logs, web3.keccak(text="StuckPenaltyStateChanged(uint256,uint256,uint256,uint256)")) + ) + assert stuck_penalty_state_changed_events[0]["nodeOperatorId"] == tested_no_id_first + assert stuck_penalty_state_changed_events[0]["stuckValidatorsCount"] == 2 - assert extra_report_tx.events["StuckPenaltyStateChanged"][1]["nodeOperatorId"] == tested_no_id_second - assert extra_report_tx.events["StuckPenaltyStateChanged"][1]["stuckValidatorsCount"] == 2 + assert stuck_penalty_state_changed_events[1]["nodeOperatorId"] == tested_no_id_second + assert stuck_penalty_state_changed_events[1]["stuckValidatorsCount"] == 2 # Deposit keys ( @@ -406,11 +413,17 @@ def test_node_operators(nor, extra_data_service, impersonated_voting, eth_whale) assert nor.isOperatorPenalized(base_no_id) == False # events - assert extra_report_tx.events["ExitedSigningKeysCountChanged"][0]["nodeOperatorId"] == tested_no_id_first - assert extra_report_tx.events["ExitedSigningKeysCountChanged"][0]["exitedValidatorsCount"] == 7 + exited_signing_keys_count_events = parse_exited_signing_keys_count_changed_logs( + filter_transfer_logs(extra_report_tx.logs, web3.keccak(text="ExitedSigningKeysCountChanged(uint256,uint256)")) + ) + assert exited_signing_keys_count_events[0]["nodeOperatorId"] == tested_no_id_first + assert exited_signing_keys_count_events[0]["exitedValidatorsCount"] == 7 - assert extra_report_tx.events["StuckPenaltyStateChanged"][0]["nodeOperatorId"] == tested_no_id_first - assert extra_report_tx.events["StuckPenaltyStateChanged"][0]["stuckValidatorsCount"] == 0 + stuck_penalty_state_changed_events = parse_stuck_penalty_state_changed_logs( + filter_transfer_logs(extra_report_tx.logs, web3.keccak(text="StuckPenaltyStateChanged(uint256,uint256,uint256,uint256)")) + ) + assert stuck_penalty_state_changed_events[0]["nodeOperatorId"] == tested_no_id_first + assert stuck_penalty_state_changed_events[0]["stuckValidatorsCount"] == 0 # Case 3 # -- PENALTY_DELAY time passes @@ -730,8 +743,11 @@ def test_node_operators(nor, extra_data_service, impersonated_voting, eth_whale) target_limit_tx = nor.updateTargetValidatorsLimits(tested_no_id_first, True, 0, {"from": STAKING_ROUTER}) - assert target_limit_tx.events["TargetValidatorsCountChanged"][0]["nodeOperatorId"] == tested_no_id_first - assert target_limit_tx.events["TargetValidatorsCountChanged"][0]["targetValidatorsCount"] == 0 + target_validators_count_changed_events = parse_target_validators_count_changed( + filter_transfer_logs(target_limit_tx.logs, web3.keccak(text="TargetValidatorsCountChanged(uint256,uint256)")) + ) + assert target_validators_count_changed_events[0]["nodeOperatorId"] == tested_no_id_first + assert target_validators_count_changed_events[0]["targetValidatorsCount"] == 0 first_no_summary_after = nor.getNodeOperatorSummary(tested_no_id_first) @@ -755,8 +771,10 @@ def test_node_operators(nor, extra_data_service, impersonated_voting, eth_whale) # Disable target limit target_limit_tx = nor.updateTargetValidatorsLimits(tested_no_id_first, False, 0, {"from": STAKING_ROUTER}) - - assert target_limit_tx.events["TargetValidatorsCountChanged"][0]["nodeOperatorId"] == tested_no_id_first + target_validators_count_changed_events = parse_target_validators_count_changed( + filter_transfer_logs(target_limit_tx.logs, web3.keccak(text="TargetValidatorsCountChanged(uint256,uint256)")) + ) + assert target_validators_count_changed_events[0]["nodeOperatorId"] == tested_no_id_first first_no_summary_after = nor.getNodeOperatorSummary(tested_no_id_first) @@ -777,3 +795,46 @@ def test_node_operators(nor, extra_data_service, impersonated_voting, eth_whale) assert deposited_keys_first_before != deposited_keys_first_after assert deposited_keys_second_before != deposited_keys_second_after assert deposited_keys_base_before != deposited_keys_base_after + + +def filter_transfer_logs(logs, transfer_topic): + return list(filter(lambda l: l["topics"][0] == transfer_topic, logs)) + + +def parse_exited_signing_keys_count_changed_logs(logs): + res = [] + for l in logs: + res.append( + { + "nodeOperatorId": eth_abi.decode_abi(["uint256"], l["topics"][1])[0], + "exitedValidatorsCount": eth_abi.decode_single("uint256", bytes.fromhex(l["data"][2:])), + } + ) + return res + + +def parse_stuck_penalty_state_changed_logs(logs): + res = [] + for l in logs: + data = eth_abi.decode(["uint256","uint256","uint256"], bytes.fromhex(l["data"][2:])) + res.append( + { + "nodeOperatorId": eth_abi.decode_abi(["uint256"], l["topics"][1])[0], + "stuckValidatorsCount": data[0], + "refundedValidatorsCount": data[1], + "stuckPenaltyEndTimestamp": data[2], + } + ) + return res + +def parse_target_validators_count_changed(logs): + res = [] + for l in logs: + res.append( + { + "nodeOperatorId": eth_abi.decode_abi(["uint256"], l["topics"][1])[0], + "targetValidatorsCount": eth_abi.decode_single("uint256", bytes.fromhex(l["data"][2:])), + } + ) + return res + diff --git a/tests/regression/test_validator_exit_bus_happy_path.py b/tests/regression/test_validator_exit_bus_happy_path.py index 109928ae..6053274d 100644 --- a/tests/regression/test_validator_exit_bus_happy_path.py +++ b/tests/regression/test_validator_exit_bus_happy_path.py @@ -74,7 +74,7 @@ def test_send_zero_validators_to_exit(helpers): def test_send_validator_to_exit(helpers, web3): - no_global_index = (module_id, no_id) = (1, 1) + no_global_index = (module_id, no_id) = (1, 38) validator_id = 1 validator_key = contracts.node_operators_registry.getSigningKey(no_id, validator_id)[0] validator = LidoValidator(validator_id, validator_key) @@ -134,8 +134,8 @@ def test_send_multiple_validators_to_exit(helpers, web3): """ The same as test above but with multiple validators on different node operators """ - first_no_global_index = (first_module_id, first_no_id) = (1, 9) - second_no_global_index = (second_module_id, second_no_id) = (1, 10) + first_no_global_index = (first_module_id, first_no_id) = (1, 37) + second_no_global_index = (second_module_id, second_no_id) = (1, 38) first_validator_id = 2 second_validator_id = 3 first_validator_key = contracts.node_operators_registry.getSigningKey(first_no_id, first_validator_id)[0] diff --git a/utils/config.py b/utils/config.py index 54ebab3e..4a7c3593 100644 --- a/utils/config.py +++ b/utils/config.py @@ -224,6 +224,14 @@ def relay_allowed_list(self) -> interface.MEVBoostRelayAllowedList: def dai_token(self) -> interface.ERC20: return interface.ERC20(DAI_TOKEN) + @property + def usdt_token(self) -> interface.ERC20: + return interface.ERC20(USDT_TOKEN) + + @property + def usdc_token(self) -> interface.ERC20: + return interface.ERC20(USDC_TOKEN) + @property def weth_token(self) -> interface.WethToken: return interface.WethToken(WETH_TOKEN) diff --git a/utils/test/easy_track_helpers.py b/utils/test/easy_track_helpers.py index 4951a433..27a0a2fe 100644 --- a/utils/test/easy_track_helpers.py +++ b/utils/test/easy_track_helpers.py @@ -29,7 +29,7 @@ def create_and_enact_payment_motion( recievers_addresses = [reciever.address for reciever in recievers] - calldata = _encode_calldata("(address[],uint256[])", [recievers_addresses, transfer_amounts]) + calldata = _encode_calldata("(address,address[],uint256[])", [token.address, recievers_addresses, transfer_amounts]) tx = easy_track.createMotion(factory, calldata, {"from": trusted_caller}) diff --git a/utils/test/event_validators/node_operators_registry.py b/utils/test/event_validators/node_operators_registry.py index b303c744..6a2ae793 100644 --- a/utils/test/event_validators/node_operators_registry.py +++ b/utils/test/event_validators/node_operators_registry.py @@ -60,7 +60,7 @@ def validate_node_operator_staking_limit_set_event( def validate_node_operator_name_set_event( event: EventDict, node_operator_name_item: NodeOperatorNameSetItem ): - _events_chain = ["LogScriptCall", "KeysOpIndexSet", "NodeOperatorNameSet"] + _events_chain = ["LogScriptCall", "LogScriptCall", "NodeOperatorNameSet", "ScriptResult"] validate_events_chain([e.name for e in event], _events_chain)