-
Notifications
You must be signed in to change notification settings - Fork 19
Vote 2025-01-28: script and tests are ready for review #332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
27822fb
Finish script + basic tests
dd68a7c
Change ipfs description
c107d65
Tests and script are ready
385245f
Fix acceptance/test_csm + regression/test_csm
37812ee
Fix test_vote_2025_01_28.py
c04d56e
Fix acceptance/test_staking_router.py + acceptance/test_csm.py
fd47286
Fix script and test (follow comments from Kate)
11540c0
extended csm regression tests
skhomuti 6995d82
Change the description and follow-up for the comments
348e0c4
Fix the test
ae90792
add tests for uploading keys more than EA limit
skhomuti 90c13fd
Add validation for the events; fix the format of the description
c161123
Remove unnecessary import from utils/staking_module
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 | ||
iamnp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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 hidden or 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 hidden or 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 hidden or 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) | ||
iamnp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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 hidden or 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 hidden or 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 hidden or 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 hidden or 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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.