1010from ape_safe .client .types import OperationType , SafeTxID
1111
1212from .accounts import SafeAccount , get_signatures
13- from .exceptions import UnsupportedChainError , ValueRequired
13+ from .exceptions import UnsupportedChainError
1414from .packages import MANIFESTS_BY_VERSION , PackageType , get_multisend
1515
1616if TYPE_CHECKING :
1717 from ape .api import ReceiptAPI , TransactionAPI
18- from ape .contracts .base import ContractInstance , ContractTransactionHandler
18+ from ape .contracts .base import (
19+ ContractInstance ,
20+ ContractMethodHandler ,
21+ ContractTransactionHandler ,
22+ )
1923 from eip712 .common import SafeTx
2024
2125
@@ -128,35 +132,63 @@ def contract(self) -> "ContractInstance":
128132 def handler (self ) -> "ContractTransactionHandler" :
129133 return self .contract .multiSend
130134
131- def add (
135+ def add_call (
132136 self ,
133- call ,
134- * args ,
137+ target : AddressType | str ,
138+ data : HexBytes = "" ,
135139 value : int = 0 ,
136140 ) -> "MultiSend" :
137141 """
138- Append a call to the MultiSend session object.
142+ Append a raw call to the MultiSend session object.
139143
140144 Raises:
141145 :class:`InvalidOption`: If one of the kwarg modifiers is not able to be used.
142146
143147 Args:
144- call: :class:`ContractMethodHandler` The method to call .
145- *args : The arguments to invoke the method with .
148+ target: The address to send the message to .
149+ data : The data to send to the target. Defaults to empty .
146150 value: int The amount of ether to forward with the call. Defaults to 0.
147151 """
148152 if value < 0 :
149153 raise ValueError ("`value=` must be positive." )
150154
151155 self .calls .append (
152156 {
153- "target" : call . contract . address ,
157+ "target" : self . conversion_manager . convert ( target , AddressType ) ,
154158 "value" : value ,
155- "callData" : call . encode_input ( * args ) ,
159+ "callData" : data ,
156160 }
157161 )
158162 return self
159163
164+ def add (
165+ self ,
166+ call : "ContractMethodHandler" ,
167+ * args ,
168+ value : int = 0 ,
169+ ) -> "MultiSend" :
170+ """
171+ Append a call to the MultiSend session object.
172+
173+ Usage::
174+
175+ batch.add(contract.method1) # Method with no args
176+ batch.add(contract.method2, *args) # Method with args
177+ batch.add(contract.method3, *args, value=...) # Payable method
178+
179+ batch(...)
180+
181+ Raises:
182+ :class:`InvalidOption`: If one of the kwarg modifiers is not able to be used.
183+
184+ Args:
185+ call: :class:`ContractMethodHandler` The method to call.
186+ *args: The arguments to invoke the method with.
187+ value: int The amount of ether to forward with the call. Defaults to 0.
188+ """
189+
190+ return self .add_call (call .contract , data = call .encode_input (* args ), value = value )
191+
160192 def add_from_receipt (self , receipt : "ReceiptAPI" ) -> "MultiSend" :
161193 """
162194 Append a call to the MultiSend session object from a receipt.
@@ -169,24 +201,14 @@ def add_from_receipt(self, receipt: "ReceiptAPI") -> "MultiSend":
169201 assert contract.viewMethod() == ...
170202 batch.add_from_receipt(receipt)
171203
204+ # NOTE: `receipt` is no longer on the chain (only in fork)
172205 batch(...)
173206
174207 Args:
175208 receipt: :class:`~ape.api.ReceiptAPI` The receipt object to pull information from for the call to add.
176209 """
177- self .calls .append (
178- {
179- "target" : receipt .receiver ,
180- "value" : receipt .value ,
181- "callData" : receipt .data ,
182- }
183- )
184- return self
185210
186- def _validate_safe_tx (self , safe_tx : "SafeTx" ) -> None :
187- required_value = sum (call ["value" ] for call in self .calls )
188- if required_value > safe_tx .value :
189- raise ValueRequired (required_value )
211+ return self .add_call (receipt .receiver , data = receipt .data , value = receipt .value )
190212
191213 @property
192214 def encoded_calls (self ):
@@ -227,7 +249,6 @@ def propose(
227249 submitter = safe_tx_kwargs .pop ("submitter" , None )
228250 sigs_by_signer = safe_tx_kwargs .pop ("sigs_by_signer" , None )
229251 safe_tx = self .as_safe_tx (safe , ** safe_tx_kwargs )
230- self ._validate_safe_tx (safe_tx )
231252 return safe .propose_safe_tx (
232253 safe_tx ,
233254 submitter = submitter ,
@@ -302,6 +323,15 @@ def add_from_calldata(self, calldata: bytes) -> "MultiSend":
302323
303324 Args:
304325 calldata: Calldata encoding the ``MultiSend.multiSend`` call.
326+
327+ Usage::
328+
329+ # NOTE: Previously submitted MultiSend SafeTx
330+ receipt = chain.get_receipt("0x...")
331+ batch.add_from_calldata(receipt.data)
332+
333+ # NOTE: `batch` now has all of the same calls in it as the MultiSend in `receipt` did
334+ batch(...)
305335 """
306336 _ , args = self .contract .decode_input (calldata )
307337 buffer = BytesIO (args ["transactions" ])
0 commit comments