Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/core_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ on:
- "feat/rc2"
- "feat/rc1"
- "feat/next-vote"
- "feat/v3-phase-2"
schedule:
- cron: "0 0 * * TUE"

Expand Down
1 change: 0 additions & 1 deletion .github/workflows/dual_governance_regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ on:
- "feat/rc2"
- "feat/rc1"
- "feat/next-vote"
- "feat/v3-phase-2"
workflow_dispatch:

jobs:
Expand Down
2 changes: 1 addition & 1 deletion brownie-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ networks:
live:
priority_fee: auto

autofetch_sources: false
autofetch_sources: true

hypothesis:
max_examples: 10
122 changes: 81 additions & 41 deletions scripts/_vote_2025_MM_DD.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""
# TODO Vote 2025_<MM>_<DD>
TODO Vote 2026_MM_DD

# TODO <a list of vote items synced with Notion Omnibus checklist>
TODO <list of items synced with Notion>

# TODO (after vote) Vote #{vote number} passed & executed on ${date+time}, block ${blockNumber}.
TODO (after vote) Vote #{vote number} passed & executed on {date+time}, block {blockNumber}.
"""

from brownie import interface
from typing import Dict, List, Tuple

from utils.voting import bake_vote_items, confirm_vote_script, create_vote
Expand All @@ -14,19 +15,42 @@
from utils.mainnet_fork import pass_and_exec_dao_vote
from utils.dual_governance import submit_proposals

from utils.agent import agent_forward

# ============================== Addresses ===================================
# TODO <a list of addresses that should be used in the voting>

# ============================== Constants ===================================
# TODO list of constants

# ============================= Description ==================================
# TODO <a description for IPFS (will appear in the voting description on vote.lido.fi)>
IPFS_DESCRIPTION = ""

# ============================= IPFS Description ==================================
# TODO IPFS description text
IPFS_DESCRIPTION = """
"""


# ================================ Main ======================================
def get_dg_items() -> List[Tuple[str, str]]:
# TODO set up interface objects

return [
# TODO 1.1. item description
agent_forward([
(
<ADDRESS>,
<METHOD>.encode_input(<PARAMS>)
)
]),

# TODO 1.2. item description
agent_forward([
<UTILS_METHOD>(<PARAMS>)
]),
]


def get_vote_items() -> Tuple[List[str], List[Tuple[str, str]]]:

# TODO set up interface objects

# TODO in case of using smart-contract based omnibus, retrieve vote items from omnibus contract
# voting_items = brownie.interface.SmartContractOmnibus(omnibus_contract).getVoteItems()
Expand All @@ -35,42 +59,58 @@ def get_vote_items() -> Tuple[List[str], List[Tuple[str, str]]]:
# for desc, call_script in voting_items:
# vote_desc_items.append(desc)
# call_script_items.append((call_script[0], call_script[1].hex()))


# TODO in case of using script based omnibus, write vote items manually
# dg_items = [
# # TODO 1.1. DG voting item 1 description
# agent_forward([
# (dg_item_address_1, dg_item_encoded_input_1)
# ]),
# # TODO 1.2. DG voting item 2 description
# agent_forward([
# (dg_item_address_2, dg_item_encoded_input_2)
# ]),
# ]
# return vote_desc_items, call_script_items
#
# OR
#
# vote_desc_items = []
# call_script_items = []
# # 1. receive DG vote items from omnibus contract
# contract_dg_items = interface.V3LaunchOmnibus(OMNIBUS_CONTRACT).getVoteItems()
# dg_items = []
# for _, call_script in contract_dg_items:
# dg_items.append((call_script[0], call_script[1].hex()))
# dg_call_script = submit_proposals([
# (dg_items, "TODO DG proposal description")
# (dg_items, DG_PROPOSAL_DESCRIPTION)
# ])
#
# vote_desc_items, call_script_items = zip(
# (
# "TODO 1. DG submission description",
# dg_call_script[0]
# ),
# (
# "TODO 2. Voting item 2 description",
# calldata_2,
# ),
# (
# "TODO 3. Voting item 3 description",
# calldata_3,
# ),
# )


# TODO return vote_desc_items, call_script_items
pass
# vote_desc_items.append(DG_SUBMISSION_DESCRIPTION)
# call_script_items.append(dg_call_script[0])
# # 2. receive non-DG vote items from omnibus contract
# voting_items = interface.V3LaunchOmnibus(OMNIBUS_CONTRACT).getVotingVoteItems()
# for desc, call_script in voting_items:
# vote_desc_items.append(desc)
# call_script_items.append((call_script[0], call_script[1].hex()))
# return vote_desc_items, call_script_items

dg_items = get_dg_items()

dg_call_script = submit_proposals([
# TODO DG proposal description
(dg_items, "DG proposal description")
])

vote_desc_items, call_script_items = zip(
(
# TODO DG proposal description
"1. DG proposal submition description",
dg_call_script[0]
),
(
# TODO item description
"2. Item description",
(
<ADDRESS>,
<METHOD>.encode_input(<PARAMS>)
)
),
(
# TODO item description
"3. Item description",
<UTILS_METHOD>(<PARAMS>)
),
)

return vote_desc_items, call_script_items


def start_vote(tx_params: Dict[str, str], silent: bool = False):
Expand Down
89 changes: 52 additions & 37 deletions tests/_test_2025_MM_DD.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from brownie import chain, interface
from brownie import chain, interface, web3, accounts, ZERO_ADDRESS, reverts
from brownie.network.transaction import TransactionReceipt
import pytest

Expand All @@ -10,52 +10,51 @@
display_dg_events
)
from utils.evm_script import encode_call_script
from utils.voting import find_metadata_by_vote_id
from utils.ipfs import get_lido_vote_cid_from_str
from utils.dual_governance import PROPOSAL_STATUS
from utils.test.event_validators.dual_governance import validate_dual_governance_submit_event

from utils.voting import find_metadata_by_vote_id
from utils.ipfs import get_lido_vote_cid_from_str


# ============================================================================
# ============================== Import vote =================================
# ============================================================================
# TODO import voting script
# from scripts.vote_* import start_vote, get_vote_items
# TODO set <VOTE_FILE>
from archive.scripts.<VOTE_FILE> import (
start_vote,
get_vote_items,
get_dg_items,
)


# ============================================================================
# ============================== Constants ===================================
# ============================================================================
# TODO list all contract addresses used in tests - do not use imports from config!
# NOTE: these addresses might have a different value on other chains

VOTING = "0x2e59A20f205bB85a89C53f1936454680651E618e"
AGENT = "0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c"
EMERGENCY_PROTECTED_TIMELOCK = "0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316"
DUAL_GOVERNANCE = "0xC1db28B3301331277e307FDCfF8DE28242A4486E"
DUAL_GOVERNANCE_ADMIN_EXECUTOR = "0x23E0B465633FF5178808F4A75186E2F2F9537021"
# TODO list of constants


# TODO Set variable to None if item is not presented
# ============================================================================
# ============================= Test params ==================================
# ============================================================================
# TODO list of test params
EXPECTED_VOTE_ID = 1
EXPECTED_DG_PROPOSAL_ID = 1
EXPECTED_VOTE_EVENTS_COUNT = 1
EXPECTED_DG_EVENTS_FROM_AGENT = 1
EXPECTED_DG_EVENTS_COUNT = 1
IPFS_DESCRIPTION_HASH = ""
DG_PROPOSAL_METADATA = ""


@pytest.fixture(scope="module")
def dual_governance_proposal_calls():
# TODO Create all the dual governance calls that match the voting script
dg_items = [
# # TODO 1.1. DG voting item 1 description
# agent_forward([
# (dg_item_address_1, dg_item_encoded_input_1)
# ]),
# # TODO 1.2. DG voting item 2 description
# agent_forward([
# (dg_item_address_2, dg_item_encoded_input_2)
# ]),
]
dg_items = get_dg_items()

# Convert each dg_item to the expected format
proposal_calls = []
Expand Down Expand Up @@ -95,7 +94,7 @@ def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_g

_, call_script_items = get_vote_items()
onchain_script = voting.getVote(vote_id)["script"]
assert onchain_script == encode_call_script(call_script_items)
assert str(onchain_script).lower() == encode_call_script(call_script_items).lower()


# =========================================================================
Expand All @@ -106,7 +105,10 @@ def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_g
# =======================================================================
# ========================= Before voting checks ========================
# =======================================================================
# TODO add before voting checks

# TODO Acceptance tests (before voting state)

# TODO Scenario tests (before voting state)


assert get_lido_vote_cid_from_str(find_metadata_by_vote_id(vote_id)) == IPFS_DESCRIPTION_HASH
Expand All @@ -119,35 +121,43 @@ def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_g
# =======================================================================
# ========================= After voting checks =========================
# =======================================================================
# TODO add after voting tests

# TODO Acceptance tests (after voting state)

# TODO Scenario tests (after voting state)


assert len(vote_events) == EXPECTED_VOTE_EVENTS_COUNT
assert count_vote_items_by_events(vote_tx, voting.address) == EXPECTED_VOTE_EVENTS_COUNT

if EXPECTED_DG_PROPOSAL_ID is not None:
assert EXPECTED_DG_PROPOSAL_ID == timelock.getProposalsCount()

# TODO Validate DG Proposal Submit event
# validate_dual_governance_submit_event(
# vote_events[0],
# proposal_id=EXPECTED_DG_PROPOSAL_ID,
# proposer=VOTING,
# executor=DUAL_GOVERNANCE_ADMIN_EXECUTOR,
# metadata="TODO DG proposal description",
# proposal_calls=dual_governance_proposal_calls,
# emitted_by=[EMERGENCY_PROTECTED_TIMELOCK, DUAL_GOVERNANCE],
# )
validate_dual_governance_submit_event(
vote_events[0],
proposal_id=EXPECTED_DG_PROPOSAL_ID,
proposer=VOTING,
executor=DUAL_GOVERNANCE_ADMIN_EXECUTOR,
metadata=DG_PROPOSAL_METADATA,
proposal_calls=dual_governance_proposal_calls,
)

# TODO validate all other voting events
# TODO validate all remaining voting events


# =========================================================================
# ======================= Execute DG Proposal =============================
# =========================================================================
if EXPECTED_DG_PROPOSAL_ID is not None:
details = timelock.getProposalDetails(EXPECTED_DG_PROPOSAL_ID)
if details["status"] != PROPOSAL_STATUS["executed"]:
# =========================================================================
# ================== DG before proposal executed checks ===================
# =========================================================================
# TODO add DG before proposal executed checks

# TODO Acceptance tests (before DG state)

# TODO Scenario tests (before DG state)


if details["status"] == PROPOSAL_STATUS["submitted"]:
Expand All @@ -156,20 +166,25 @@ def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_g

if timelock.getProposalDetails(EXPECTED_DG_PROPOSAL_ID)["status"] == PROPOSAL_STATUS["scheduled"]:
chain.sleep(timelock.getAfterScheduleDelay() + 1)

dg_tx: TransactionReceipt = timelock.execute(EXPECTED_DG_PROPOSAL_ID, {"from": stranger})
display_dg_events(dg_tx)
dg_events = group_dg_events_from_receipt(
dg_tx,
timelock=EMERGENCY_PROTECTED_TIMELOCK,
admin_executor=DUAL_GOVERNANCE_ADMIN_EXECUTOR,
)
assert count_vote_items_by_events(dg_tx, agent.address) == EXPECTED_DG_EVENTS_COUNT
assert count_vote_items_by_events(dg_tx, agent.address) == EXPECTED_DG_EVENTS_FROM_AGENT
assert len(dg_events) == EXPECTED_DG_EVENTS_COUNT


# TODO validate all DG events


# =========================================================================
# ==================== After DG proposal executed checks ==================
# =========================================================================
# TODO add DG after proposal executed checks

# TODO Acceptance tests (after DG state)

# TODO Scenario tests (after DG state)
Loading