-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #332 from lidofinance/vote-2025-01-28
Vote 2025-01-28: script and tests are ready for review
- Loading branch information
Showing
9 changed files
with
333 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
""" | ||
Voting 28/01/2025. | ||
I. CSM: Enable Permissionless Phase and Increase the Share Limit | ||
1. Grant MODULE_MANAGER_ROLE on CS Module to Aragon Agent | ||
2. Activate public release mode on CS Module | ||
3. Increase the stake share limit from 1% to 2% and the priority exit threshold from 1.25% to 2.5% on CS Module | ||
4. Revoke MODULE_MANAGER_ROLE on CS Module from Aragon Agent | ||
II. NO Acquisitions: Bridgetower is now part of Solstice Staking | ||
5. Rename Node Operator ID 17 from BridgeTower to Solstice | ||
""" | ||
|
||
import time | ||
|
||
from typing import Dict, Tuple, Optional, List | ||
|
||
from brownie import interface | ||
from brownie.network.transaction import TransactionReceipt | ||
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.permissions import ( | ||
encode_oz_revoke_role, | ||
encode_oz_grant_role | ||
) | ||
|
||
from utils.node_operators import encode_set_node_operator_name | ||
|
||
from utils.config import ( | ||
get_deployer_account, | ||
contracts, | ||
get_is_live, | ||
get_priority_fee, | ||
) | ||
|
||
from utils.csm import activate_public_release | ||
|
||
from utils.agent import agent_forward | ||
|
||
description = """ | ||
1. **Transition Community Staking Module to Permissionless Phase** by activating public release and **increasing the share limit** from 1% to 2%, as [approved on Snapshot](https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7cbd5e9cb95bda9581831daf8b0e72d1ad0b068d2cbd3bda2a2f6ae378464f26). Alongside the share limit, [it is proposed](https://research.lido.fi/t/community-staking-module/5917/86) to **raise the priority exit share threshold **from 1.25% to 2.5% to maintain parameter ratios. Items 1-4. | ||
2. **Rename Node Operator ID 17 from BridgeTower to Solstice** as [requested on the forum](https://research.lido.fi/t/node-operator-registry-name-reward-address-change/4170/41). Item 5. | ||
""" | ||
|
||
def start_vote(tx_params: Dict[str, str], silent: bool) -> bool | list[int | TransactionReceipt | None]: | ||
"""Prepare and run voting.""" | ||
voting: interface.Voting = contracts.voting | ||
csm: interface.CSModule = contracts.csm | ||
staking_router: interface.StakingRouter = contracts.staking_router | ||
csm_module_id = 3 | ||
new_stake_share_limit = 200 #2% | ||
new_priority_exit_share_threshold = 250 #2.5% | ||
old_staking_module_fee = 600 | ||
old_treasury_fee = 400 | ||
old_max_deposits_per_block = 30 | ||
old_min_deposit_block_distance = 25 | ||
|
||
vote_desc_items, call_script_items = zip( | ||
# | ||
# I. CSM: Enable Permissionless Phase and Increase the Share Limit | ||
# | ||
( | ||
"1. Grant MODULE_MANAGER_ROLE on CS Module to Aragon Agent", | ||
agent_forward( | ||
[ | ||
encode_oz_grant_role(csm, "MODULE_MANAGER_ROLE", contracts.agent) | ||
] | ||
), | ||
), | ||
( | ||
"2. Activate public release mode on CS Module", | ||
agent_forward( | ||
[ | ||
activate_public_release(csm.address) | ||
] | ||
), | ||
), | ||
( | ||
"3. Increase the stake share limit from 1% to 2% and the priority exit threshold from 1.25% to 2.5% on CS Module", | ||
agent_forward( | ||
[ | ||
update_staking_module(csm_module_id, new_stake_share_limit, new_priority_exit_share_threshold, | ||
old_staking_module_fee, old_treasury_fee, old_max_deposits_per_block, | ||
old_min_deposit_block_distance) | ||
] | ||
), | ||
), | ||
( | ||
"4. Revoke MODULE_MANAGER_ROLE on CS Module from Aragon Agent", | ||
agent_forward( | ||
[ | ||
encode_oz_revoke_role(csm, "MODULE_MANAGER_ROLE", revoke_from=contracts.agent) | ||
] | ||
), | ||
), | ||
# | ||
# II. NO Acquisitions: Bridgetower is now part of Solstice Staking | ||
# | ||
( | ||
"5. Rename Node Operator ID 17 from BridgeTower to Solstice", | ||
agent_forward( | ||
[ | ||
encode_set_node_operator_name( | ||
id=17, name="Solstice", registry=contracts.node_operators_registry | ||
), | ||
] | ||
), | ||
), | ||
) | ||
|
||
vote_items = bake_vote_items(list(vote_desc_items), list(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. | ||
|
||
def update_staking_module(staking_module_id, stake_share_limit, | ||
priority_exit_share_threshold, staking_module_fee, | ||
treasury_fee, max_deposits_per_block, | ||
min_deposit_block_distance) -> Tuple[str, str]: | ||
return (contracts.staking_router.address, contracts.staking_router.updateStakingModule.encode_input( | ||
staking_module_id, stake_share_limit, priority_exit_share_threshold, staking_module_fee, | ||
treasury_fee, max_deposits_per_block, min_deposit_block_distance | ||
)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
""" | ||
Tests for voting 28/01/2025. | ||
""" | ||
|
||
from typing import Dict, Tuple, List, NamedTuple | ||
from scripts.vote_2025_01_28 import start_vote | ||
from brownie import interface | ||
from utils.test.tx_tracing_helpers import * | ||
from utils.config import contracts, LDO_HOLDER_ADDRESS_FOR_TESTS | ||
from utils.voting import find_metadata_by_vote_id | ||
from utils.ipfs import get_lido_vote_cid_from_str | ||
from utils.test.event_validators.csm import validate_public_release_event | ||
from utils.test.event_validators.staking_router import validate_staking_module_update_event, StakingModuleItem | ||
from utils.test.event_validators.node_operators_registry import validate_node_operator_name_set_event, NodeOperatorNameSetItem | ||
from utils.test.event_validators.permission import validate_grant_role_event, validate_revoke_role_event | ||
|
||
def test_vote(helpers, accounts, vote_ids_from_env, stranger): | ||
|
||
csm = interface.CSModule("0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F") | ||
staking_router = interface.StakingRouter("0xFdDf38947aFB03C621C71b06C9C70bce73f12999") | ||
node_operators_registry = interface.NodeOperatorsRegistry("0x55032650b14df07b85bF18A3a3eC8E0Af2e028d5") | ||
agent = interface.Agent("0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c") | ||
module_manager_role = "0x79dfcec784e591aafcf60db7db7b029a5c8b12aac4afd4e8c4eb740430405fa6" | ||
csm_module_id = 3 | ||
new_stake_share_limit = 200 #2% | ||
new_priority_exit_share_threshold = 250 | ||
new_name = "Solstice" | ||
old_name = "BridgeTower" | ||
old_stake_share_limit = 100 #1% | ||
old_priority_exit_share_threshold = 125 | ||
old_staking_module_fee = 600 | ||
old_treasury_fee = 400 | ||
old_max_deposits_per_block = 30 | ||
old_min_deposit_block_distance = 25 | ||
|
||
# Agent doesn't have MODULE_MANAGER_ROLE | ||
assert csm.hasRole(module_manager_role, agent) is False | ||
|
||
# Public release mode is not active | ||
assert csm.publicRelease() is False | ||
|
||
# Check old data | ||
assert staking_router.getStakingModule(csm_module_id)["stakeShareLimit"] == old_stake_share_limit | ||
assert staking_router.getStakingModule(csm_module_id)["priorityExitShareThreshold"] == old_priority_exit_share_threshold | ||
assert staking_router.getStakingModule(csm_module_id)["stakingModuleFee"] == old_staking_module_fee | ||
assert staking_router.getStakingModule(csm_module_id)["treasuryFee"] == old_treasury_fee | ||
assert staking_router.getStakingModule(csm_module_id)["maxDepositsPerBlock"] == old_max_deposits_per_block | ||
assert staking_router.getStakingModule(csm_module_id)["minDepositBlockDistance"] == old_min_deposit_block_distance | ||
|
||
# Check old name | ||
assert node_operators_registry.getNodeOperator(17, True)["name"] == old_name | ||
|
||
# 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}") | ||
|
||
# | ||
# I. CSM: Enable Permissionless Phase and Increase the Share Limit | ||
# | ||
# 2. Activate public release mode on CS Module | ||
assert csm.publicRelease() is True | ||
|
||
# 3. Increase stake share limit from 1% to 2% on CS Module | ||
assert staking_router.getStakingModule(csm_module_id)["stakeShareLimit"] == new_stake_share_limit | ||
assert staking_router.getStakingModule(csm_module_id)["priorityExitShareThreshold"] == new_priority_exit_share_threshold | ||
assert staking_router.getStakingModule(csm_module_id)["stakingModuleFee"] == old_staking_module_fee | ||
assert staking_router.getStakingModule(csm_module_id)["treasuryFee"] == old_treasury_fee | ||
assert staking_router.getStakingModule(csm_module_id)["maxDepositsPerBlock"] == old_max_deposits_per_block | ||
assert staking_router.getStakingModule(csm_module_id)["minDepositBlockDistance"] == old_min_deposit_block_distance | ||
|
||
# 4. Revoke MODULE_MANAGER_ROLE on CS Module from Aragon Agent | ||
assert csm.hasRole(module_manager_role, agent) is False | ||
|
||
# | ||
# II. NO Acquisitions: Bridgetower is now part of Solstice Staking | ||
# | ||
# 5. Rename Node Operator ID 17 from BridgeTower to Solstice | ||
assert node_operators_registry.getNodeOperator(17, True)["name"] == new_name | ||
|
||
# events | ||
display_voting_events(vote_tx) | ||
evs = group_voting_events(vote_tx) | ||
|
||
metadata = find_metadata_by_vote_id(vote_id) | ||
assert get_lido_vote_cid_from_str(metadata) == "bafkreierrixpk7pszth7pkgau7iyhb4mxolskst62oyfat3ltfrnh355ty" | ||
|
||
assert count_vote_items_by_events(vote_tx, contracts.voting) == 5, "Incorrect voting items count" | ||
|
||
# validate events | ||
validate_grant_role_event(evs[0], module_manager_role, agent.address, agent.address) | ||
|
||
validate_public_release_event(evs[1]) | ||
|
||
expected_staking_module_item = StakingModuleItem( | ||
id=csm_module_id, | ||
name="Community Staking", | ||
address=None, | ||
target_share=new_stake_share_limit, | ||
module_fee=old_staking_module_fee, | ||
treasury_fee=old_treasury_fee, | ||
) | ||
|
||
validate_staking_module_update_event(evs[2], expected_staking_module_item) | ||
|
||
validate_revoke_role_event(evs[3], module_manager_role, agent.address, agent.address) | ||
|
||
expected_node_operator_item = NodeOperatorNameSetItem( | ||
nodeOperatorId=17, | ||
name="Solstice", | ||
) | ||
validate_node_operator_name_set_event(evs[4], expected_node_operator_item) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from typing import Tuple | ||
from brownie import interface | ||
|
||
from utils.config import contracts | ||
|
||
def activate_public_release(csm_address: str) -> Tuple[str, str]: | ||
csm = interface.CSModule(csm_address) | ||
return (csm.address, csm.activatePublicRelease.encode_input()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from brownie.network.event import EventDict | ||
from .common import validate_events_chain | ||
|
||
def validate_public_release_event(event: EventDict): | ||
_events_chain = ['LogScriptCall', 'LogScriptCall', 'PublicRelease', 'ScriptResult'] | ||
validate_events_chain([e.name for e in event], _events_chain) | ||
assert event.count("PublicRelease") == 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters