diff --git a/configs/config_hoodi.py b/configs/config_hoodi.py index 151841f6e..e8cd61ba5 100644 --- a/configs/config_hoodi.py +++ b/configs/config_hoodi.py @@ -50,3 +50,4 @@ # StakingRouter STAKING_ROUTER = "0xCc820558B39ee15C7C45B59390B503b83fb499A8" +USDC_TOKEN = "0x97bb030B93faF4684eAC76bA0bf3be5ec7140F36" diff --git a/scripts/vote_2025_05_01_hoodi.py b/scripts/vote_2025_05_01_hoodi.py new file mode 100644 index 000000000..734037d6d --- /dev/null +++ b/scripts/vote_2025_05_01_hoodi.py @@ -0,0 +1,111 @@ +""" +Voting 01/05/2025. Hoodi network. + +I. Deploy sandbox EVM script factories for EasyTrack: + +1. Add `RemoveAllowedRecipients` EVM script factory +2. Add `AddAllowedRecipient` EVM script factory +3. Add `TopUpAllowedRecipient` EVM script factory +4. Add `CREATE_PAYMENTS_ROLE` permission to EasyTrackEVMScriptExecutor +""" + +import time +from typing import Dict +from brownie import interface +from brownie.network.transaction import TransactionReceipt +from utils.permissions import encode_permission_grant + +from utils.agent import agent_forward +from utils.voting import bake_vote_items, confirm_vote_script, create_vote +from utils.ipfs import calculate_vote_ipfs_description, upload_vote_ipfs_description +from utils.config import ( + contracts, + EASYTRACK_EVMSCRIPT_EXECUTOR, + get_deployer_account, + get_is_live, + get_priority_fee, +) +from utils.easy_track import ( + add_evmscript_factory, + create_permissions, +) + +DESCRIPTION = """ +Voting 01/05/2025. Hoodi network. + +I. Deploy sandbox EVM script factories for EasyTrack: + +1. Add `RemoveAllowedRecipients` EVM script factory +2. Add `AddAllowedRecipient` EVM script factory +3. Add `TopUpAllowedRecipient` EVM script factory +4. Add `CREATE_PAYMENTS_ROLE` permission to EasyTrackEVMScriptExecutor +""" + + +def start_vote(tx_params: Dict[str, str], silent: bool) -> bool | list[int | TransactionReceipt | None]: + """Prepare and run voting""" + + # 1. Add `RemoveAllowedRecipients` EVM script factory (sandbox) + remove_allowed_recipient = "0xc84251D2959E976AfE95201E1e2B88dB56Bc0a69" + # 2. Add `AddAllowedRecipient` EVM script factory (sandbox) + add_allowed_recipient = "0x056561d0F1314CB3932180b3f0B3C03174F2642B" + # 3. Add `TopUpAllowedRecipient` EVM script factory (sandbox) + top_up_allowed_recipients = "0x4A7B898981182c42ecC9444Cd40Cf42CEB6b71Ab" + + allowed_recipient_registry = interface.AllowedRecipientRegistry("0xd57FF1ce54F572F4E8DaF0cB7038F1Bd6049cAa8") + + vote_desc_items, call_script_items = zip( + ( + "1) Add `RemoveAllowedRecipients` EVM script factory with address 0xc84251D2959E976AfE95201E1e2B88dB56Bc0a69", + add_evmscript_factory( + factory=remove_allowed_recipient, + permissions=create_permissions(allowed_recipient_registry, "removeRecipient"), + ), + ), + ( + "2) Add `AddAllowedRecipient` EVM script factory with address 0x056561d0F1314CB3932180b3f0B3C03174F2642B", + add_evmscript_factory( + factory=add_allowed_recipient, + permissions=create_permissions(allowed_recipient_registry, "addRecipient"), + ), + ), + ( + "3) Add `TopUpAllowedRecipient` EVM script factory with address 0x4A7B898981182c42ecC9444Cd40Cf42CEB6b71Ab", + add_evmscript_factory( + factory=top_up_allowed_recipients, + permissions=create_permissions(contracts.finance, "newImmediatePayment") + + create_permissions(allowed_recipient_registry, "updateSpentAmount")[2:], + ), + ), + ( + "4) Add CREATE_PAYMENTS_ROLE permission to EasyTrackEVMScriptExecutor", + encode_permission_grant( + target_app=contracts.finance, + permission_name="CREATE_PAYMENTS_ROLE", + grant_to=EASYTRACK_EVMSCRIPT_EXECUTOR, + ), + ), + ) + + 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. diff --git a/tests/test_vote_2025_05_01_hoodi.py b/tests/test_vote_2025_05_01_hoodi.py new file mode 100644 index 000000000..d67ce0c49 --- /dev/null +++ b/tests/test_vote_2025_05_01_hoodi.py @@ -0,0 +1,134 @@ +""" +Tests for voting 01/05/2025. Hoodi network. + +""" + +from brownie import interface, accounts +from scripts.vote_2025_05_01_hoodi import start_vote +from utils.test.tx_tracing_helpers import * +from utils.config import ( + contracts, + LDO_HOLDER_ADDRESS_FOR_TESTS, + EASYTRACK_EVMSCRIPT_EXECUTOR, +) +from configs.config_hoodi import ( + USDC_TOKEN, +) +from utils.test.event_validators.permission import ( + Permission, + validate_permission_grant_event, +) +from utils.test.event_validators.easy_track import ( + validate_evmscript_factory_added_event, + EVMScriptFactoryAdded, +) +from utils.easy_track import create_permissions +from utils.voting import find_metadata_by_vote_id +from utils.test.easy_track_helpers import create_and_enact_payment_motion + + +def test_vote(helpers, accounts, vote_ids_from_env, stranger): + # new code + easy_track = contracts.easy_track + voting = contracts.voting + finance = contracts.finance + + add_allowed_recipient_evm_script_factory = "0x056561d0F1314CB3932180b3f0B3C03174F2642B" + remove_allowed_recipient_evm_script_factory = "0xc84251D2959E976AfE95201E1e2B88dB56Bc0a69" + top_up_allowed_recipient_evm_script_factory = "0x4A7B898981182c42ecC9444Cd40Cf42CEB6b71Ab" + + registry = interface.AllowedRecipientRegistry("0xd57FF1ce54F572F4E8DaF0cB7038F1Bd6049cAa8") + trusted_caller = "0x418B816A7c3ecA151A31d98e30aa7DAa33aBf83A" + + evm_script_factories_before = easy_track.getEVMScriptFactories() + + assert add_allowed_recipient_evm_script_factory not in evm_script_factories_before + assert remove_allowed_recipient_evm_script_factory not in evm_script_factories_before + assert top_up_allowed_recipient_evm_script_factory not in evm_script_factories_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, voting) + print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}") + + # I. EasyTrack factories + evm_script_factories = easy_track.getEVMScriptFactories() + + assert add_allowed_recipient_evm_script_factory in evm_script_factories + assert remove_allowed_recipient_evm_script_factory in evm_script_factories + assert top_up_allowed_recipient_evm_script_factory in evm_script_factories + + removeRecipientsContract = interface.RemoveAllowedRecipient(remove_allowed_recipient_evm_script_factory) + addRecipientsContract = interface.AddAllowedRecipient(add_allowed_recipient_evm_script_factory) + topUpRecipientsContract = interface.TopUpAllowedRecipients(top_up_allowed_recipient_evm_script_factory) + + assert removeRecipientsContract.allowedRecipientsRegistry() == registry + assert removeRecipientsContract.trustedCaller() == trusted_caller + + assert addRecipientsContract.allowedRecipientsRegistry() == registry + assert addRecipientsContract.trustedCaller() == trusted_caller + + assert topUpRecipientsContract.allowedRecipientsRegistry() == registry + assert topUpRecipientsContract.trustedCaller() == trusted_caller + assert topUpRecipientsContract.finance() == contracts.finance + assert topUpRecipientsContract.easyTrack() == easy_track + + # validate vote events + assert count_vote_items_by_events(vote_tx, voting) == 4, "Incorrect voting items count" + metadata = find_metadata_by_vote_id(vote_id) + print("metadata", metadata) + + evs = group_voting_events_from_receipt(vote_tx) + + # Grant permissions to make operational changes to EasyTrack module + validate_evmscript_factory_added_event( + evs[0], + EVMScriptFactoryAdded( + factory_addr=remove_allowed_recipient_evm_script_factory, + permissions=create_permissions(registry, "removeRecipient"), + ), + ) + validate_evmscript_factory_added_event( + evs[1], + EVMScriptFactoryAdded( + factory_addr=add_allowed_recipient_evm_script_factory, + permissions=create_permissions(registry, "addRecipient"), + ), + ) + validate_evmscript_factory_added_event( + evs[2], + EVMScriptFactoryAdded( + factory_addr=top_up_allowed_recipient_evm_script_factory, + permissions=create_permissions(contracts.finance, "newImmediatePayment") + + create_permissions(registry, "updateSpentAmount")[2:], + ), + ) + + permission = Permission( + entity=EASYTRACK_EVMSCRIPT_EXECUTOR, + app=finance, + role="0x5de467a460382d13defdc02aacddc9c7d6605d6d4e0b8bd2f70732cae8ea17bc", + ) # keccak256('CREATE_PAYMENTS_ROLE') + + validate_permission_grant_event(evs[3], permission) + + usdc_transfer_amount = 100 * 10**6 + + agent, usdc = contracts.agent, interface.Usdc(USDC_TOKEN) + print(usdc.balanceOf(agent), usdc_transfer_amount) + + if usdc.balanceOf(agent) >= usdc_transfer_amount: + create_and_enact_payment_motion( + easy_track, + trusted_caller=trusted_caller, + factory=top_up_allowed_recipient_evm_script_factory, + token=interface.Usdc(USDC_TOKEN), + recievers=[accounts.at(trusted_caller, force=True)], + transfer_amounts=[usdc_transfer_amount], + stranger=stranger, + )