Skip to content

Commit

Permalink
Validate transaction function ABIs, and humanize transaction argument…
Browse files Browse the repository at this point in the history
… confirmation messages during deployment.
  • Loading branch information
KPrasch committed Sep 27, 2023
1 parent 1824eda commit f403c5b
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 22 deletions.
8 changes: 8 additions & 0 deletions deployment/confirm.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ def _confirm_deployment(contract_name: str) -> None:
exit(-1)


def _continue() -> None:
"""Asks the user to continue."""
answer = input(f"Continue Y/N? ")
if answer.lower().strip() == "n":
print("Aborting deployment!")
exit(-1)


def _confirm_zero_address() -> None:
answer = input("Zero Address detected for deployment parameter; Continue? Y/N? ")
if answer.lower().strip() == "n":
Expand Down
56 changes: 46 additions & 10 deletions deployment/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,20 @@
from ape import chain, project
from ape.api import AccountAPI, ReceiptAPI
from ape.cli import get_user_selected_account
from ape.contracts.base import ContractContainer, ContractInstance
from ape.contracts.base import (
ContractContainer,
ContractInstance,
ContractTransactionHandler
)
from ape.utils import ZERO_ADDRESS
from deployment.confirm import _confirm_resolution
from eth_typing import ChecksumAddress
from ethpm_types import MethodABI
from web3.auto.gethdev import w3

from deployment.confirm import (
_confirm_resolution,
_continue
)
from deployment.constants import (
BYTES_PREFIX,
DEPLOYER_INDICATOR,
Expand All @@ -18,8 +29,6 @@
SPECIAL_VARIABLE_DELIMITER,
VARIABLE_PREFIX,
)
from eth_typing import ChecksumAddress
from web3.auto.gethdev import w3


def _is_variable(param: Any) -> bool:
Expand Down Expand Up @@ -237,6 +246,27 @@ def get_contract_container(contract: str) -> ContractContainer:
return contract_container


def _get_function_abi(method: ContractTransactionHandler, args) -> MethodABI:
"""Returns the function ABI for a contract function with a given number of arguments."""
for abi in method.abis:
if len(abi.inputs) == len(args):
return abi
else:
raise ValueError(f"Could not find ABI for {method} with {len(args)} args")


def _validate_transaction_args(args: typing.Tuple[Any, ...], abi) -> typing.Dict[str, Any]:
"""Validates the transaction arguments against the function ABI."""
named_args = dict()
for arg, abi_input in zip(args, abi.inputs):
if not w3.is_encodable(abi_input.type, arg):
raise ValueError(
f"Argument '{arg}' of type '{type(arg)}' is not encodable as '{abi_input.type}'"
)
named_args[abi_input.name] = arg
return named_args


def validate_constructor_parameters(config: typing.OrderedDict[str, Any]) -> None:
"""Validates the constructor parameters for all contracts in a single config."""
available_contracts = list(config.keys())
Expand Down Expand Up @@ -323,12 +353,18 @@ def deploy(self, container: ContractContainer) -> ContractInstance:
instance = deployer_account.deploy(*args, **kwargs)
return instance

def transact(self, contract: ContractInstance, method: str, *args) -> ReceiptAPI:
print(
f"Transacting '{method}' on {contract.contract_type.name} "
f"({contract.address}) with args\n\t{args}"
)
result = contract.invoke_transaction(method, *args, sender=self.get_account())
def transact(self, method: ContractTransactionHandler, *args) -> ReceiptAPI:
abi = _get_function_abi(method=method, args=args)
named_args = _validate_transaction_args(args=args, abi=abi)
base_message = f"Transacting {method.contract.contract_type.name}[{method.contract.address[:10]}].{method}"
if named_args:
pretty_args = "\n\t".join(f"{k}={v}" for k, v in named_args.items())
message = f"{base_message} with arguments:\n\t{pretty_args}"
else:
message = f"{base_message} with no arguments"
print(message)
_continue()
result = method(*args, sender=self.get_account())
return result

@staticmethod
Expand Down
5 changes: 3 additions & 2 deletions deployment/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
from typing import Dict, List, NamedTuple, Optional

from ape.contracts import ContractInstance
from deployment.params import get_contract_container
from deployment.utils import check_registry_filepath
from eth_typing import ChecksumAddress
from eth_utils import to_checksum_address

from deployment.params import get_contract_container
from deployment.utils import check_registry_filepath


class RegistryEntry(NamedTuple):
"""Represents a single entry in a nucypher-style contract registry."""
Expand Down
5 changes: 0 additions & 5 deletions deployment/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,13 @@
from typing import List

from ape import networks
from ape.cli import get_user_selected_account
from ape.contracts import ContractInstance
from ape_etherscan.utils import API_KEY_ENV_KEY_MAP

from deployment.constants import (
CURRENT_NETWORK,
LOCAL_BLOCKCHAIN_ENVIRONMENTS
)
from deployment.params import (
Deployer,
ConstructorParameters
)


def check_registry_filepath(registry_filepath: Path) -> None:
Expand Down
5 changes: 3 additions & 2 deletions scripts/lynx/deploy_child.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/python3

from ape import project

from deployment.constants import (
ARTIFACTS_DIR,
CONSTRUCTOR_PARAMS_DIR,
Expand Down Expand Up @@ -43,13 +44,13 @@ def main():
proxy = deployer.deploy(OZ_DEPENDENCY.TransparentUpgradeableProxy)
taco_child_application = deployer.proxy(project.TACoChildApplication, proxy)

deployer.transact(mock_polygon_child, "setChildApplication", taco_child_application.address)
deployer.transact(mock_polygon_child.setChildApplication, taco_child_application.address)

ritual_token = deployer.deploy(project.LynxRitualToken)

coordinator = deployer.deploy(project.Coordinator)

deployer.transact(taco_child_application, "initialize", coordinator.address)
deployer.transact(taco_child_application.initialize, coordinator.address)

global_allow_list = deployer.deploy(project.GlobalAllowList)

Expand Down
7 changes: 4 additions & 3 deletions scripts/lynx/deploy_root.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/python3

from ape import project

from deployment.constants import (
ARTIFACTS_DIR,
CONSTRUCTOR_PARAMS_DIR,
Expand Down Expand Up @@ -44,12 +45,12 @@ def main():
proxy = deployer.deploy(OZ_DEPENDENCY.TransparentUpgradeableProxy)
taco_application = deployer.proxy(project.TACoApplication, proxy)

deployer.transact(mock_threshold_staking, "setApplication", taco_application.address)
deployer.transact(mock_threshold_staking.setApplication, taco_application.address)

deployer.transact(taco_application, "initialize")
deployer.transact(taco_application.initialize)

mock_polygon_root = deployer.deploy(project.MockPolygonRoot)
deployer.transact(taco_application, "setChildApplication", mock_polygon_root.address)
deployer.transact(taco_application.setChildApplication, mock_polygon_root.address)

deployments = [
reward_token,
Expand Down

0 comments on commit f403c5b

Please sign in to comment.