From c169c9dedcbe0d4e686484c2b90e6f04ed63e447 Mon Sep 17 00:00:00 2001 From: El De-dog-lo <3859395+fubuloubu@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:24:00 -0400 Subject: [PATCH] feat(ethereum): add builder pattern support to eth multicall (#1948) * feat(ethereum): add builder pattern support to eth multicall * docs: apply suggestions from code review --- src/ape_ethereum/multicall/handlers.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/ape_ethereum/multicall/handlers.py b/src/ape_ethereum/multicall/handlers.py index 60c6cf8918..1a2f00f7fb 100644 --- a/src/ape_ethereum/multicall/handlers.py +++ b/src/ape_ethereum/multicall/handlers.py @@ -99,7 +99,7 @@ def add( *args, allowFailure: bool = False, value: int = 0, - ): + ) -> "BaseMulticall": """ Adds a call to the Multicall session object. @@ -113,6 +113,10 @@ def add( *args: The arguments to invoke the method with. allowFailure (bool): Whether the call is allowed to fail. value (int): The amount of ether to forward with the call. + + Returns: + :class:`~ape_ethereum.multicall.handlers.BaseMulticall`: returns itself + to emulate a builder pattern. """ # Append call dict to the list @@ -126,6 +130,7 @@ def add( "callData": call.encode_input(*args), } ) + return self class Call(BaseMulticall): @@ -142,6 +147,13 @@ class Call(BaseMulticall): ... # Add as many calls as desired call.add(contract.myMethod, *call_args) a, b, ..., z = call() # Performs multicall + # or, using a builder pattern: + call = multicall.Call() + .add(contract.myMethod, *call_args) + .add(contract.myMethod, *call_args) + ... # Add as many calls as desired + .add(contract.myMethod, *call_args) + a, b, ..., z = call() # Performs multicall """ def __init__( @@ -165,9 +177,11 @@ def add(self, call: ContractMethodHandler, *args, **kwargs): super().add(call, *args, **kwargs) self.abis.append(_select_method_abi(call.abis, args)) + return self @property def returnData(self) -> List[HexBytes]: + # NOTE: this property is kept camelCase to align with the raw EVM struct result = self._result # Declare for typing reasons. if not result: raise NotExecutedError() @@ -253,7 +267,14 @@ class Transaction(BaseMulticall): txn.add(contract.myMethod, *call_args) ... # Add as many calls as desired to execute txn.add(contract.myMethod, *call_args) - a, b, ..., z = txn(sender=my_signer) # Sends the multicall transaction + a, b, ..., z = txn(sender=my_signer).return_data # Sends the multicall transaction + # or, using a builder pattern: + txn = Transaction() + .add(contract.myMethod, *call_args) + .add(contract.myMethod, *call_args) + ... # Add as many calls as desired to execute + .add(contract.myMethod, *call_args) + a, b, ..., z = txn(sender=my_signer).return_data # Sends the multicall transaction """ def _validate_calls(self, **txn_kwargs) -> None: