|
| 1 | +from brownie import interface, web3, reverts |
| 2 | +from brownie.network.transaction import TransactionReceipt |
| 3 | +from utils.evm_script import encode_call_script |
| 4 | +from utils.ipfs import get_lido_vote_cid_from_str |
| 5 | +from utils.permission_parameters import Param, Op, ArgumentValue |
| 6 | +from utils.test.event_validators.permission import Permission, validate_permission_grantp_event |
| 7 | +from utils.test.keys_helpers import random_pubkeys_batch, random_signatures_batch |
| 8 | +from utils.test.tx_tracing_helpers import ( |
| 9 | + count_vote_items_by_events, |
| 10 | + display_voting_events, |
| 11 | + group_voting_events_from_receipt, |
| 12 | +) |
| 13 | +from utils.balance import set_balance |
| 14 | +from utils.voting import find_metadata_by_vote_id |
| 15 | + |
| 16 | +from archive.scripts.vote_2026_01_26_hoodi import ( |
| 17 | + start_vote, |
| 18 | + get_vote_items, |
| 19 | +) |
| 20 | + |
| 21 | + |
| 22 | +VOTING = "0x49B3512c44891bef83F8967d075121Bd1b07a01B" |
| 23 | +TARGET_NO_REGISTRY = "0x682E94d2630846a503BDeE8b6810DF71C9806891" |
| 24 | +ACL = "0x78780e70Eae33e2935814a327f7dB6c01136cc62" |
| 25 | +NEW_MANAGER_ADDRESS = "0xc8195bb2851d7129D9100af9d65Bd448A6dE11eF" |
| 26 | +MANAGE_SIGNING_KEYS = web3.keccak(text="MANAGE_SIGNING_KEYS").hex() |
| 27 | +OPERATOR_ID = 1 |
| 28 | +EXPECTED_REWARD_ADDRESS = "0x031624fAD4E9BFC2524e7a87336C4b190E70BCA8" |
| 29 | + |
| 30 | +EXPECTED_VOTE_ID = 56 |
| 31 | +EXPECTED_VOTE_EVENTS_COUNT = 1 |
| 32 | +IPFS_DESCRIPTION_HASH = "bafkreibcmwxupju2hx54awwjh7fpbybkmcxban5v36go4nsnrem2fwipgq" |
| 33 | + |
| 34 | + |
| 35 | +def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env): |
| 36 | + voting = interface.Voting(VOTING) |
| 37 | + no = interface.NodeOperatorsRegistry(TARGET_NO_REGISTRY) |
| 38 | + perm_param = Param(0, Op.EQ, ArgumentValue(OPERATOR_ID)) |
| 39 | + perm_param_uint = perm_param.to_uint256() |
| 40 | + |
| 41 | + # ========================================================================= |
| 42 | + # ======================== Identify or Create vote ======================== |
| 43 | + # ========================================================================= |
| 44 | + if vote_ids_from_env: |
| 45 | + vote_id = vote_ids_from_env[0] |
| 46 | + assert vote_id == EXPECTED_VOTE_ID |
| 47 | + elif voting.votesLength() > EXPECTED_VOTE_ID: |
| 48 | + vote_id = EXPECTED_VOTE_ID |
| 49 | + else: |
| 50 | + vote_id, _ = start_vote({"from": ldo_holder}, silent=True) |
| 51 | + |
| 52 | + _, call_script_items = get_vote_items() |
| 53 | + onchain_script = voting.getVote(vote_id)["script"] |
| 54 | + assert str(onchain_script).lower() == encode_call_script(call_script_items).lower() |
| 55 | + |
| 56 | + # ========================================================================= |
| 57 | + # ============================= Execute Vote ============================== |
| 58 | + # ========================================================================= |
| 59 | + is_executed = voting.getVote(vote_id)["executed"] |
| 60 | + if not is_executed: |
| 61 | + # ===================================================================== |
| 62 | + # ========================= Before voting checks ====================== |
| 63 | + # ===================================================================== |
| 64 | + |
| 65 | + # Item 1 |
| 66 | + assert no.getNodeOperator(OPERATOR_ID, True)["rewardAddress"] == EXPECTED_REWARD_ADDRESS |
| 67 | + assert not no.canPerform(NEW_MANAGER_ADDRESS, MANAGE_SIGNING_KEYS, [perm_param_uint]) |
| 68 | + # scenario test |
| 69 | + add_signing_keys_fails_before_vote(accounts) |
| 70 | + |
| 71 | + assert get_lido_vote_cid_from_str(find_metadata_by_vote_id(vote_id)) == IPFS_DESCRIPTION_HASH |
| 72 | + |
| 73 | + vote_tx: TransactionReceipt = helpers.execute_vote(vote_id=vote_id, accounts=accounts, dao_voting=voting) |
| 74 | + display_voting_events(vote_tx) |
| 75 | + vote_events = group_voting_events_from_receipt(vote_tx) |
| 76 | + |
| 77 | + # ===================================================================== |
| 78 | + # ========================= After voting checks ======================= |
| 79 | + # ===================================================================== |
| 80 | + |
| 81 | + # Item 1 |
| 82 | + assert no.canPerform(NEW_MANAGER_ADDRESS, MANAGE_SIGNING_KEYS, [perm_param_uint]) |
| 83 | + |
| 84 | + assert len(vote_events) == EXPECTED_VOTE_EVENTS_COUNT |
| 85 | + assert count_vote_items_by_events(vote_tx, voting.address) == EXPECTED_VOTE_EVENTS_COUNT |
| 86 | + |
| 87 | + # events check |
| 88 | + permission = Permission(entity=NEW_MANAGER_ADDRESS, app=no, role=MANAGE_SIGNING_KEYS) |
| 89 | + validate_permission_grantp_event(vote_events[0], permission, [perm_param], emitted_by=ACL) |
| 90 | + |
| 91 | + # scenario tests |
| 92 | + manager_adds_signing_keys(accounts) |
| 93 | + add_signing_keys_to_notallowed_operator_fails(accounts) |
| 94 | + |
| 95 | + |
| 96 | +def add_signing_keys_fails_before_vote(accounts): |
| 97 | + no = interface.SimpleDVT(TARGET_NO_REGISTRY) |
| 98 | + |
| 99 | + manager = accounts.at(NEW_MANAGER_ADDRESS, force=True) |
| 100 | + set_balance(manager, 10) |
| 101 | + |
| 102 | + pubkeys = random_pubkeys_batch(1) |
| 103 | + signatures = random_signatures_batch(1) |
| 104 | + |
| 105 | + with reverts(): |
| 106 | + no.addSigningKeys( |
| 107 | + OPERATOR_ID, |
| 108 | + 1, |
| 109 | + pubkeys, |
| 110 | + signatures, |
| 111 | + {"from": manager}, |
| 112 | + ) |
| 113 | + |
| 114 | + |
| 115 | +def manager_adds_signing_keys(accounts): |
| 116 | + no = interface.SimpleDVT(TARGET_NO_REGISTRY) |
| 117 | + |
| 118 | + manager = accounts.at(NEW_MANAGER_ADDRESS, force=True) |
| 119 | + set_balance(manager, 10) |
| 120 | + |
| 121 | + total_keys_before = no.getTotalSigningKeyCount(OPERATOR_ID) |
| 122 | + pubkeys = random_pubkeys_batch(1) |
| 123 | + signatures = random_signatures_batch(1) |
| 124 | + |
| 125 | + no.addSigningKeys( |
| 126 | + OPERATOR_ID, |
| 127 | + 1, |
| 128 | + pubkeys, |
| 129 | + signatures, |
| 130 | + {"from": manager}, |
| 131 | + ) |
| 132 | + |
| 133 | + total_keys_after = no.getTotalSigningKeyCount(OPERATOR_ID) |
| 134 | + assert total_keys_after == total_keys_before + 1 |
| 135 | + |
| 136 | + |
| 137 | +def add_signing_keys_to_notallowed_operator_fails(accounts): |
| 138 | + no = interface.SimpleDVT(TARGET_NO_REGISTRY) |
| 139 | + |
| 140 | + manager = accounts.at(NEW_MANAGER_ADDRESS, force=True) |
| 141 | + set_balance(manager, 10) |
| 142 | + |
| 143 | + pubkeys = random_pubkeys_batch(1) |
| 144 | + signatures = random_signatures_batch(1) |
| 145 | + |
| 146 | + with reverts(): |
| 147 | + no.addSigningKeys( |
| 148 | + 2, # NO id 2 - not allowed |
| 149 | + 1, |
| 150 | + pubkeys, |
| 151 | + signatures, |
| 152 | + {"from": manager}, |
| 153 | + ) |
0 commit comments