From 9f6de48ba1d417ac750f80b7f6afd797ebb5cb5f Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Wed, 20 Dec 2023 22:53:02 +0400 Subject: [PATCH 1/4] Add scripts to deploy/test allowed recipients setup with single token manually --- ...ceptance_test_manual_setup_single_token.py | 174 ++++++++++++++++++ ..._manually_recipients_single_token_setup.py | 84 +++++++++ utils/deployment.py | 4 + 3 files changed, 262 insertions(+) create mode 100644 scripts/acceptance_test_manual_setup_single_token.py create mode 100644 scripts/create_manually_recipients_single_token_setup.py diff --git a/scripts/acceptance_test_manual_setup_single_token.py b/scripts/acceptance_test_manual_setup_single_token.py new file mode 100644 index 00000000..10160b11 --- /dev/null +++ b/scripts/acceptance_test_manual_setup_single_token.py @@ -0,0 +1,174 @@ +from hexbytes import HexBytes +from brownie import chain, network, AllowedRecipientsRegistry, TopUpAllowedRecipients + +from utils import lido, deployed_easy_track, log, deployment + +ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE = ( + "0xec20c52871c824e5437859e75ac830e83aaaaeb7b0ffd850de830ddd3e385276" +) +REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE = ( + "0x491d7752c25cfca0f73715cde1130022a9b815373f91a996bbb1ba8943efc99b" +) +SET_PARAMETERS_ROLE = ( + "0x260b83d52a26066d8e9db550fa70395df5f3f064b50ff9d8a94267d9f1fe1967" +) +UPDATE_SPENT_AMOUNT_ROLE = ( + "0xc5260260446719a726d11a6faece21d19daa48b4cbcca118345832d4cb71df99" +) +DEFAULT_ADMIN_ROLE = ( + "0x0000000000000000000000000000000000000000000000000000000000000000" +) + +GRANT_ROLE_EVENT = "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d" +REVOKE_ROLE_EVENT = "0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b" + +deploy_config = deployment.AllowedRecipientsManualSetupDeployConfig( + token="", + limit=0, + period=1, + spent_amount=0, + trusted_caller="", + titles=[], + recipients=[], + grant_rights_to_executor=False, +) + +registry_deploy_tx_hash = "" +top_up_deploy_tx_hash = "" + + +def main(): + network_name = network.show_active() + + if network_name is None: + raise Exception("network_name is None") + + contracts = lido.contracts(network=network_name) + et_contracts = deployed_easy_track.contracts(network=network_name) + + evm_script_executor = et_contracts.evm_script_executor + + registry_deploy_tx = chain.get_transaction(registry_deploy_tx_hash) + registry_address = registry_deploy_tx.events["AllowedRecipientsRegistryDeployed"][ + "allowedRecipientsRegistry" + ] + + top_up_deploy_tx = chain.get_transaction(top_up_deploy_tx_hash) + top_up_address = top_up_deploy_tx.events["TopUpAllowedRecipientsDeployed"][ + "topUpAllowedRecipients" + ] + + log.br() + + log.nb("Agent", contracts.aragon.agent) + log.nb("Easy Track EVM Script Executor", evm_script_executor) + + log.br() + + log.nb("recipients", deploy_config.recipients) + log.nb("trusted_caller", deploy_config.trusted_caller) + log.nb("limit", deploy_config.limit) + log.nb("period", deploy_config.period) + log.nb("spent_amount", deploy_config.spent_amount) + log.nb("grant_rights_to_executor", deploy_config.grant_rights_to_executor) + + log.br() + + log.nb("AllowedRecipientsRegistryDeployed", registry_address) + log.nb("TopUpAllowedRecipientsDeployed", top_up_address) + + log.br() + + registry = AllowedRecipientsRegistry.at(registry_address) + top_up_allowed_recipients = TopUpAllowedRecipients.at(top_up_address) + + assert top_up_allowed_recipients.token() == deploy_config.token + assert top_up_allowed_recipients.allowedRecipientsRegistry() == registry + assert top_up_allowed_recipients.trustedCaller() == deploy_config.trusted_caller + + assert len(registry.getAllowedRecipients()) == len(deploy_config.recipients) + for recipient in deploy_config.recipients: + assert registry.isRecipientAllowed(recipient) + + registryLimit, registryPeriodDuration = registry.getLimitParameters() + assert registryLimit == deploy_config.limit + assert registryPeriodDuration == deploy_config.period + + assert ( + registry.spendableBalance() == deploy_config.limit - deploy_config.spent_amount + ) + + assert registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, contracts.aragon.agent) + assert registry.hasRole( + REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, contracts.aragon.agent + ) + assert registry.hasRole(SET_PARAMETERS_ROLE, contracts.aragon.agent) + assert registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, contracts.aragon.agent) + assert registry.hasRole(DEFAULT_ADMIN_ROLE, contracts.aragon.agent) + + if deploy_config.grant_rights_to_executor: + assert registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, evm_script_executor) + assert registry.hasRole( + REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, evm_script_executor + ) + assert registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, evm_script_executor) + assert not registry.hasRole(SET_PARAMETERS_ROLE, evm_script_executor) + assert not registry.hasRole(DEFAULT_ADMIN_ROLE, evm_script_executor) + + assert not registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, registry_address) + assert not registry.hasRole( + REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, registry_address + ) + assert not registry.hasRole(SET_PARAMETERS_ROLE, registry_address) + assert not registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, registry_address) + assert not registry.hasRole(DEFAULT_ADMIN_ROLE, registry_address) + + registry_roles_holders = { + ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE: [], + REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE: [], + SET_PARAMETERS_ROLE: [], + UPDATE_SPENT_AMOUNT_ROLE: [], + DEFAULT_ADMIN_ROLE: [], + } + + if registry_deploy_tx.logs is None: + raise Exception("Can't validate logs. The logs is None.") + + for event in registry_deploy_tx.logs or []: + if event["topics"][0] == HexBytes(GRANT_ROLE_EVENT): + registry_roles_holders[event["topics"][1].hex()].append( + "0x" + event["topics"][2].hex()[26:] + ) + elif event["topics"][0] == HexBytes(REVOKE_ROLE_EVENT): + registry_roles_holders[event["topics"][1].hex()].remove( + "0x" + event["topics"][2].hex()[26:] + ) + + log.br() + + log.nb("Roles holders from tx events") + + log.br() + + log.nb( + "ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE role holders", + registry_roles_holders[ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE], + ) + log.nb( + "REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE role holders", + registry_roles_holders[REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE], + ) + log.nb( + "SET_PARAMETERS_ROLE role holders", + registry_roles_holders[SET_PARAMETERS_ROLE], + ) + log.nb( + "UPDATE_SPENT_AMOUNT_ROLE role holders", + registry_roles_holders[UPDATE_SPENT_AMOUNT_ROLE], + ) + log.nb( + "DEFAULT_ADMIN_ROLE role holders", + registry_roles_holders[DEFAULT_ADMIN_ROLE], + ) + + log.br() diff --git a/scripts/create_manually_recipients_single_token_setup.py b/scripts/create_manually_recipients_single_token_setup.py new file mode 100644 index 00000000..3c451c94 --- /dev/null +++ b/scripts/create_manually_recipients_single_token_setup.py @@ -0,0 +1,84 @@ +from brownie import chain, network + +from utils import log, lido, deployment +from utils.config import get_is_live, get_deployer_account, prompt_bool + + +deploy_config = deployment.AllowedRecipientsManualSetupDeployConfig( + token="", + limit=0, + period=1, + spent_amount=0, + trusted_caller="", + titles=[], + recipients=[], + grant_rights_to_executor=False, +) + + +def main(): + network_name = network.show_active() + deployer = get_deployer_account(get_is_live(), network=network_name) + allowed_recipients_builder = lido.allowed_recipients_builder(network=network_name) + + log.br() + + log.nb("Current network", network_name, color_hl=log.color_magenta) + log.nb("Using deployed addresses for", network_name, color_hl=log.color_yellow) + log.ok("chain id", chain.id) + log.ok("Deployer", deployer) + + log.ok("Token", deploy_config.token) + log.ok("Limit", deploy_config.limit) + log.ok("Period", deploy_config.period) + log.ok("Spent amount", deploy_config.spent_amount) + log.ok("Trusted caller", deploy_config.trusted_caller) + log.ok("Titles", deploy_config.titles) + log.ok("Recipients", deploy_config.recipients) + log.ok( + "Grant manager rights to EVMScriptExecutor", + deploy_config.grant_rights_to_executor, + ) + + log.br() + + print("Proceed? [yes/no]: ") + + if not prompt_bool(): + log.nb("Aborting") + return + + tx_params = {"from": deployer, "priority_fee": "2 gwei", "max_fee": "50 gwei"} + + tx = allowed_recipients_builder.deployAllowedRecipientsRegistry( + deploy_config.limit, + deploy_config.period, + deploy_config.recipients, + deploy_config.titles, + deploy_config.spent_amount, + deploy_config.grant_rights_to_executor, + tx_params, + ) + + allowed_recipients_registry_address = tx.events[ + "AllowedRecipientsRegistryDeployed" + ]["allowedRecipientsRegistry"] + + log.ok( + f"AllowedRecipientsRegistry was deployed on address {allowed_recipients_registry_address}\n" + ) + + tx = allowed_recipients_builder.deployTopUpAllowedRecipients( + deploy_config.trusted_caller, + allowed_recipients_registry_address, + deploy_config.token, + tx_params, + ) + + top_up_allowed_recipients_address = tx.events["TopUpAllowedRecipientsDeployed"][ + "topUpAllowedRecipients" + ] + + log.ok( + f"TopUpAllowedRecipients EVM script factory was deployed on address {top_up_allowed_recipients_address}\n" + ) diff --git a/utils/deployment.py b/utils/deployment.py index 35a684b3..1a0ee284 100644 --- a/utils/deployment.py +++ b/utils/deployment.py @@ -31,6 +31,10 @@ class AllowedRecipientsFullSetupDeployConfig(AllowedRecipientsDeployConfig): titles: [str] recipients: [str] +@dataclass +class AllowedRecipientsManualSetupDeployConfig(AllowedRecipientsFullSetupDeployConfig): + grant_rights_to_executor: bool + def deploy_easy_track( admin, governance_token, From fe46f7964d1b45597a8ca9b86c966558c70cd610 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Thu, 21 Dec 2023 00:04:23 +0400 Subject: [PATCH 2/4] Add scripts for setups with multiple tokens --- ...llowedRecipientsBuilderMultipleTokens.json | 251 ++++++++++++++++++ .../TopUpAllowedRecipientsMultipleTokens.json | 93 +++++++ ...tance_test_manual_setup_multiple_tokens.py | 187 +++++++++++++ ...create_recipients_multiple_tokens_setup.py | 85 ++++++ utils/deployment.py | 12 + utils/lido.py | 12 +- 6 files changed, 639 insertions(+), 1 deletion(-) create mode 100644 interfaces/AllowedRecipientsBuilderMultipleTokens.json create mode 100644 interfaces/TopUpAllowedRecipientsMultipleTokens.json create mode 100644 scripts/acceptance_test_manual_setup_multiple_tokens.py create mode 100644 scripts/create_recipients_multiple_tokens_setup.py diff --git a/interfaces/AllowedRecipientsBuilderMultipleTokens.json b/interfaces/AllowedRecipientsBuilderMultipleTokens.json new file mode 100644 index 00000000..5c62d995 --- /dev/null +++ b/interfaces/AllowedRecipientsBuilderMultipleTokens.json @@ -0,0 +1,251 @@ +[ + { + "inputs": [ + { + "internalType": "contract IAllowedRecipientsFactory", + "name": "_factory", + "type": "address" + }, + { "internalType": "address", "name": "_admin", "type": "address" }, + { + "internalType": "contract IEasyTrack", + "name": "_easytrack", + "type": "address" + }, + { "internalType": "address", "name": "_finance", "type": "address" }, + { + "internalType": "address", + "name": "_bokkyPooBahsDateTimeContract", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ADD_TOKEN_TO_ALLOWED_LIST_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SET_PARAMETERS_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UPDATE_SPENT_AMOUNT_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "admin", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bokkyPooBahsDateTimeContract", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_trustedCaller", "type": "address" }, + { + "internalType": "address", + "name": "_allowedRecipientsRegistry", + "type": "address" + } + ], + "name": "deployAddAllowedRecipient", + "outputs": [ + { + "internalType": "contract IAddAllowedRecipient", + "name": "addAllowedRecipient", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_limit", "type": "uint256" }, + { "internalType": "uint256", "name": "_periodDurationMonths", "type": "uint256" }, + { "internalType": "address[]", "name": "_recipients", "type": "address[]" }, + { "internalType": "string[]", "name": "_titles", "type": "string[]" }, + { "internalType": "uint256", "name": "_spentAmount", "type": "uint256" }, + { + "internalType": "bool", + "name": "_grantRightsToEVMScriptExecutor", + "type": "bool" + } + ], + "name": "deployAllowedRecipientsRegistry", + "outputs": [ + { + "internalType": "contract IAllowedRecipientsRegistry", + "name": "registry", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address[]", "name": "_tokens", "type": "address[]" }], + "name": "deployAllowedTokensRegistry", + "outputs": [ + { + "internalType": "contract IAllowedTokensRegistry", + "name": "registry", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_trustedCaller", "type": "address" }, + { "internalType": "uint256", "name": "_limit", "type": "uint256" }, + { "internalType": "uint256", "name": "_periodDurationMonths", "type": "uint256" }, + { "internalType": "address[]", "name": "_tokens", "type": "address[]" }, + { "internalType": "address[]", "name": "_recipients", "type": "address[]" }, + { "internalType": "string[]", "name": "_titles", "type": "string[]" }, + { "internalType": "uint256", "name": "_spentAmount", "type": "uint256" } + ], + "name": "deployFullSetup", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_trustedCaller", "type": "address" }, + { + "internalType": "address", + "name": "_allowedRecipientsRegistry", + "type": "address" + } + ], + "name": "deployRemoveAllowedRecipient", + "outputs": [ + { + "internalType": "contract IRemoveAllowedRecipient", + "name": "removeAllowedRecipient", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_recipient", "type": "address" }, + { "internalType": "string", "name": "_title", "type": "string" }, + { "internalType": "address[]", "name": "_tokens", "type": "address[]" }, + { "internalType": "uint256", "name": "_limit", "type": "uint256" }, + { "internalType": "uint256", "name": "_periodDurationMonths", "type": "uint256" }, + { "internalType": "uint256", "name": "_spentAmount", "type": "uint256" } + ], + "name": "deploySingleRecipientTopUpOnlySetup", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_trustedCaller", "type": "address" }, + { + "internalType": "address", + "name": "_allowedRecipientsRegistry", + "type": "address" + }, + { "internalType": "address", "name": "_allowedTokensRegistry", "type": "address" } + ], + "name": "deployTopUpAllowedRecipients", + "outputs": [ + { + "internalType": "contract ITopUpAllowedRecipients", + "name": "topUpAllowedRecipients", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "easyTrack", + "outputs": [ + { "internalType": "contract IEasyTrack", "name": "", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "evmScriptExecutor", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "contract IAllowedRecipientsFactory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finance", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/interfaces/TopUpAllowedRecipientsMultipleTokens.json b/interfaces/TopUpAllowedRecipientsMultipleTokens.json new file mode 100644 index 00000000..fdc456c1 --- /dev/null +++ b/interfaces/TopUpAllowedRecipientsMultipleTokens.json @@ -0,0 +1,93 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "_trustedCaller", "type": "address" }, + { + "internalType": "address", + "name": "_allowedRecipientsRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "_allowedTokensRegistry", + "type": "address" + }, + { "internalType": "address", "name": "_finance", "type": "address" }, + { "internalType": "address", "name": "_easyTrack", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "allowedRecipientsRegistry", + "outputs": [ + { + "internalType": "contract IAllowedRecipientsRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "allowedTokensRegistry", + "outputs": [ + { + "internalType": "contract IAllowedTokensRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_creator", "type": "address" }, + { "internalType": "bytes", "name": "_evmScriptCallData", "type": "bytes" } + ], + "name": "createEVMScript", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes", "name": "_evmScriptCallData", "type": "bytes" } + ], + "name": "decodeEVMScriptCallData", + "outputs": [ + { "internalType": "address", "name": "token", "type": "address" }, + { "internalType": "address[]", "name": "recipients", "type": "address[]" }, + { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "easyTrack", + "outputs": [ + { "internalType": "contract IEasyTrack", "name": "", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finance", + "outputs": [{ "internalType": "contract IFinance", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "trustedCaller", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/scripts/acceptance_test_manual_setup_multiple_tokens.py b/scripts/acceptance_test_manual_setup_multiple_tokens.py new file mode 100644 index 00000000..cf230428 --- /dev/null +++ b/scripts/acceptance_test_manual_setup_multiple_tokens.py @@ -0,0 +1,187 @@ +from hexbytes import HexBytes +from brownie import interface, chain, network, AllowedRecipientsRegistry + +from utils import lido, deployed_easy_track, log, deployment + + +ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE = ( + "0xec20c52871c824e5437859e75ac830e83aaaaeb7b0ffd850de830ddd3e385276" +) +REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE = ( + "0x491d7752c25cfca0f73715cde1130022a9b815373f91a996bbb1ba8943efc99b" +) +SET_PARAMETERS_ROLE = ( + "0x260b83d52a26066d8e9db550fa70395df5f3f064b50ff9d8a94267d9f1fe1967" +) +UPDATE_SPENT_AMOUNT_ROLE = ( + "0xc5260260446719a726d11a6faece21d19daa48b4cbcca118345832d4cb71df99" +) +DEFAULT_ADMIN_ROLE = ( + "0x0000000000000000000000000000000000000000000000000000000000000000" +) + +GRANT_ROLE_EVENT = "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d" +REVOKE_ROLE_EVENT = "0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b" + +deploy_config = deployment.AllowedRecipientsMultipleTokensManualSetupDeployConfig( + tokens_registry="", + limit=0, + period=1, + spent_amount=0, + trusted_caller="", + titles=[], + recipients=[], + grant_rights_to_executor=False, +) + +registry_deploy_tx_hash = "" +top_up_deploy_tx_hash = "" + +registry_deploy_tx_hash = ( + "0x0d89ea3a7c0883d52574a409668858fb17877f221b539cc30a705fcd4471ede4" +) +top_up_deploy_tx_hash = ( + "0x5ccf460ca3c87b327f0667f18872d0f4def4717a0128e541d2c30ee618225495" +) + + +def main(): + network_name = network.show_active() + + if network_name is None: + raise Exception("network_name is None") + + contracts = lido.contracts(network=network_name) + et_contracts = deployed_easy_track.contracts(network=network_name) + + evm_script_executor = et_contracts.evm_script_executor + + registry_deploy_tx = chain.get_transaction(registry_deploy_tx_hash) + registry_address = registry_deploy_tx.events["AllowedRecipientsRegistryDeployed"][ + "allowedRecipientsRegistry" + ] + + top_up_deploy_tx = chain.get_transaction(top_up_deploy_tx_hash) + top_up_address = top_up_deploy_tx.events["TopUpAllowedRecipientsDeployed"][ + "topUpAllowedRecipients" + ] + + log.br() + + log.nb("Agent", contracts.aragon.agent) + log.nb("Easy Track EVM Script Executor", evm_script_executor) + + log.br() + + log.nb("recipients", deploy_config.recipients) + log.nb("trusted_caller", deploy_config.trusted_caller) + log.nb("limit", deploy_config.limit) + log.nb("period", deploy_config.period) + log.nb("spent_amount", deploy_config.spent_amount) + log.nb("grant_rights_to_executor", deploy_config.grant_rights_to_executor) + + log.br() + + log.nb("AllowedRecipientsRegistryDeployed", registry_address) + log.nb("TopUpAllowedRecipientsDeployed", top_up_address) + + log.br() + + registry = AllowedRecipientsRegistry.at(registry_address) + top_up_allowed_recipients = interface.TopUpAllowedRecipientsMultipleTokens( + top_up_address + ) + + assert ( + top_up_allowed_recipients.allowedTokensRegistry() + == deploy_config.tokens_registry + ) + assert top_up_allowed_recipients.allowedRecipientsRegistry() == registry + assert top_up_allowed_recipients.trustedCaller() == deploy_config.trusted_caller + + assert len(registry.getAllowedRecipients()) == len(deploy_config.recipients) + for recipient in deploy_config.recipients: + assert registry.isRecipientAllowed(recipient) + + registryLimit, registryPeriodDuration = registry.getLimitParameters() + assert registryLimit == deploy_config.limit + assert registryPeriodDuration == deploy_config.period + + assert ( + registry.spendableBalance() == deploy_config.limit - deploy_config.spent_amount + ) + + assert registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, contracts.aragon.agent) + assert registry.hasRole( + REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, contracts.aragon.agent + ) + assert registry.hasRole(SET_PARAMETERS_ROLE, contracts.aragon.agent) + assert registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, contracts.aragon.agent) + assert registry.hasRole(DEFAULT_ADMIN_ROLE, contracts.aragon.agent) + + if deploy_config.grant_rights_to_executor: + assert registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, evm_script_executor) + assert registry.hasRole( + REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, evm_script_executor + ) + assert registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, evm_script_executor) + assert not registry.hasRole(SET_PARAMETERS_ROLE, evm_script_executor) + assert not registry.hasRole(DEFAULT_ADMIN_ROLE, evm_script_executor) + + assert not registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, registry_address) + assert not registry.hasRole( + REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, registry_address + ) + assert not registry.hasRole(SET_PARAMETERS_ROLE, registry_address) + assert not registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, registry_address) + assert not registry.hasRole(DEFAULT_ADMIN_ROLE, registry_address) + + registry_roles_holders = { + ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE: [], + REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE: [], + SET_PARAMETERS_ROLE: [], + UPDATE_SPENT_AMOUNT_ROLE: [], + DEFAULT_ADMIN_ROLE: [], + } + + if registry_deploy_tx.logs is None: + raise Exception("Can't validate logs. The logs is None.") + + for event in registry_deploy_tx.logs or []: + if event["topics"][0] == HexBytes(GRANT_ROLE_EVENT): + registry_roles_holders[event["topics"][1].hex()].append( + "0x" + event["topics"][2].hex()[26:] + ) + elif event["topics"][0] == HexBytes(REVOKE_ROLE_EVENT): + registry_roles_holders[event["topics"][1].hex()].remove( + "0x" + event["topics"][2].hex()[26:] + ) + + log.br() + + log.nb("Roles holders from tx events") + + log.br() + + log.nb( + "ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE role holders", + registry_roles_holders[ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE], + ) + log.nb( + "REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE role holders", + registry_roles_holders[REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE], + ) + log.nb( + "SET_PARAMETERS_ROLE role holders", + registry_roles_holders[SET_PARAMETERS_ROLE], + ) + log.nb( + "UPDATE_SPENT_AMOUNT_ROLE role holders", + registry_roles_holders[UPDATE_SPENT_AMOUNT_ROLE], + ) + log.nb( + "DEFAULT_ADMIN_ROLE role holders", + registry_roles_holders[DEFAULT_ADMIN_ROLE], + ) + + log.br() diff --git a/scripts/create_recipients_multiple_tokens_setup.py b/scripts/create_recipients_multiple_tokens_setup.py new file mode 100644 index 00000000..56e92927 --- /dev/null +++ b/scripts/create_recipients_multiple_tokens_setup.py @@ -0,0 +1,85 @@ +from brownie import chain, network + +from utils import log, lido, deployment +from utils.config import get_is_live, get_deployer_account, prompt_bool + +deploy_config = deployment.AllowedRecipientsMultipleTokensManualSetupDeployConfig( + tokens_registry="", + limit=0, + period=1, + spent_amount=0, + trusted_caller="", + titles=[], + recipients=[], + grant_rights_to_executor=False, +) + + +def main(): + network_name = network.show_active() + deployer = get_deployer_account(get_is_live(), network=network_name) + allowed_recipients_builder = lido.allowed_recipients_builder_many_tokens( + network=network_name + ) + + log.br() + + log.nb("Current network", network_name, color_hl=log.color_magenta) + log.nb("Using deployed addresses for", network_name, color_hl=log.color_yellow) + log.ok("chain id", chain.id) + log.ok("Deployer", deployer) + + log.ok("Limit", deploy_config.limit) + log.ok("Period", deploy_config.period) + log.ok("Spent amount", deploy_config.spent_amount) + log.ok("Trusted caller", deploy_config.trusted_caller) + log.ok("Tokens Registry", deploy_config.tokens_registry) + log.ok("Titles", deploy_config.titles) + log.ok("Recipients", deploy_config.recipients) + log.ok( + "Grant manager rights to EVMScriptExecutor", + deploy_config.grant_rights_to_executor, + ) + + log.br() + + print("Proceed? [yes/no]: ") + + if not prompt_bool(): + log.nb("Aborting") + return + + tx_params = {"from": deployer, "priority_fee": "2 gwei", "max_fee": "50 gwei"} + + tx = allowed_recipients_builder.deployAllowedRecipientsRegistry( + deploy_config.limit, + deploy_config.period, + deploy_config.recipients, + deploy_config.titles, + deploy_config.spent_amount, + deploy_config.grant_rights_to_executor, + tx_params, + ) + + allowed_recipients_registry_address = tx.events[ + "AllowedRecipientsRegistryDeployed" + ]["allowedRecipientsRegistry"] + + log.ok( + f"AllowedRecipientsRegistry was deployed on address {allowed_recipients_registry_address}\n" + ) + + tx = allowed_recipients_builder.deployTopUpAllowedRecipients( + deploy_config.trusted_caller, + allowed_recipients_registry_address, + deploy_config.tokens_registry, + tx_params, + ) + + top_up_allowed_recipients_address = tx.events["TopUpAllowedRecipientsDeployed"][ + "topUpAllowedRecipients" + ] + + log.ok( + f"TopUpAllowedRecipients EVM script factory was deployed on address {top_up_allowed_recipients_address}\n" + ) diff --git a/utils/deployment.py b/utils/deployment.py index 1a0ee284..729aee17 100644 --- a/utils/deployment.py +++ b/utils/deployment.py @@ -35,6 +35,18 @@ class AllowedRecipientsFullSetupDeployConfig(AllowedRecipientsDeployConfig): class AllowedRecipientsManualSetupDeployConfig(AllowedRecipientsFullSetupDeployConfig): grant_rights_to_executor: bool +@dataclass +class AllowedRecipientsMultipleTokensManualSetupDeployConfig: + limit: int + period: int + titles: [str] + recipients: [str] + spent_amount: int + trusted_caller: str + tokens_registry: str + grant_rights_to_executor: bool + + def deploy_easy_track( admin, governance_token, diff --git a/utils/lido.py b/utils/lido.py index 55f4fe64..818a6948 100644 --- a/utils/lido.py +++ b/utils/lido.py @@ -55,6 +55,16 @@ def allowed_recipients_builder(network=DEFAULT_NETWORK): ) +def allowed_recipients_builder_many_tokens(network=DEFAULT_NETWORK): + if network == "mainnet" or network == "mainnet-fork": + return brownie.interface.AllowedRecipientsBuilderMultipleTokens( + "0x334D6eDc13F63728b39e6A6D04A7Bbd5D6A9B9FF" + ) + raise NameError( + f"""Unknown network "{network}". Supported networks: mainnet, mainnet-fork""" + ) + + class LidoContractsSetup: def __init__(self, interface, lido_addresses): self.lido_addresses = lido_addresses @@ -192,6 +202,7 @@ def __init__(self, lido_app): self.STAKING_PAUSE_ROLE = Permission(lido_app, "STAKING_PAUSE_ROLE") self.STAKING_CONTROL_ROLE = Permission(lido_app, "STAKING_CONTROL_ROLE") + class NodeOperatorsRegistryPermissions: def __init__(self, node_operators_registry_app): self.STAKING_ROUTER_ROLE = Permission( @@ -208,7 +219,6 @@ def __init__(self, node_operators_registry_app): ) - class TokenManagerPermissions: def __init__(self, token_manager_app): self.ISSUE_ROLE = Permission(token_manager_app, "ISSUE_ROLE") From d6809ff403fc8081a0d87bc77f9457c7425c561d Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Thu, 21 Dec 2023 00:09:10 +0400 Subject: [PATCH 3/4] Follow identical naming convention for new scripts --- ...tokens.py => acceptance_test_crafted_setup_multiple_tokens.py} | 0 ...gle_token.py => acceptance_test_crafted_setup_single_token.py} | 0 ..._tokens_setup.py => craft_recipients_multiple_tokens_setup.py} | 0 ...ngle_token_setup.py => craft_recipients_single_token_setup.py} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename scripts/{acceptance_test_manual_setup_multiple_tokens.py => acceptance_test_crafted_setup_multiple_tokens.py} (100%) rename scripts/{acceptance_test_manual_setup_single_token.py => acceptance_test_crafted_setup_single_token.py} (100%) rename scripts/{create_recipients_multiple_tokens_setup.py => craft_recipients_multiple_tokens_setup.py} (100%) rename scripts/{create_manually_recipients_single_token_setup.py => craft_recipients_single_token_setup.py} (100%) diff --git a/scripts/acceptance_test_manual_setup_multiple_tokens.py b/scripts/acceptance_test_crafted_setup_multiple_tokens.py similarity index 100% rename from scripts/acceptance_test_manual_setup_multiple_tokens.py rename to scripts/acceptance_test_crafted_setup_multiple_tokens.py diff --git a/scripts/acceptance_test_manual_setup_single_token.py b/scripts/acceptance_test_crafted_setup_single_token.py similarity index 100% rename from scripts/acceptance_test_manual_setup_single_token.py rename to scripts/acceptance_test_crafted_setup_single_token.py diff --git a/scripts/create_recipients_multiple_tokens_setup.py b/scripts/craft_recipients_multiple_tokens_setup.py similarity index 100% rename from scripts/create_recipients_multiple_tokens_setup.py rename to scripts/craft_recipients_multiple_tokens_setup.py diff --git a/scripts/create_manually_recipients_single_token_setup.py b/scripts/craft_recipients_single_token_setup.py similarity index 100% rename from scripts/create_manually_recipients_single_token_setup.py rename to scripts/craft_recipients_single_token_setup.py From 05085586ff90fffa670407cd22a5a56a6f0c2929 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Thu, 21 Dec 2023 00:48:23 +0400 Subject: [PATCH 4/4] Use empty strings for default tx hashes in script --- scripts/acceptance_test_crafted_setup_multiple_tokens.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/acceptance_test_crafted_setup_multiple_tokens.py b/scripts/acceptance_test_crafted_setup_multiple_tokens.py index cf230428..cc9f612c 100644 --- a/scripts/acceptance_test_crafted_setup_multiple_tokens.py +++ b/scripts/acceptance_test_crafted_setup_multiple_tokens.py @@ -37,13 +37,6 @@ registry_deploy_tx_hash = "" top_up_deploy_tx_hash = "" -registry_deploy_tx_hash = ( - "0x0d89ea3a7c0883d52574a409668858fb17877f221b539cc30a705fcd4471ede4" -) -top_up_deploy_tx_hash = ( - "0x5ccf460ca3c87b327f0667f18872d0f4def4717a0128e541d2c30ee618225495" -) - def main(): network_name = network.show_active()