def update_version(self) -> Optional[bool]: """ Update Safe Master Copy and Fallback handler to the last version :return: """ if self.is_version_updated(): raise SafeAlreadyUpdatedException() multisend = MultiSend(LAST_MULTISEND_CONTRACT, self.ethereum_client) tx_params = {'from': self.address, 'gas': 0, 'gasPrice': 0} multisend_txs = [ MultiSendTx(MultiSendOperation.CALL, self.address, 0, data) for data in (self.safe_contract.functions.changeMasterCopy( LAST_SAFE_CONTRACT).buildTransaction(tx_params)['data'], self.safe_contract.functions.setFallbackHandler( LAST_DEFAULT_CALLBACK_HANDLER).buildTransaction( tx_params)['data']) ] multisend_data = multisend.build_tx_data(multisend_txs) if self.execute_safe_transaction( multisend.address, 0, multisend_data, operation=SafeOperation.DELEGATE_CALL): self.safe_cli_info.master_copy = LAST_SAFE_CONTRACT self.safe_cli_info.fallback_handler = LAST_DEFAULT_CALLBACK_HANDLER self.safe_cli_info.version = self.safe.retrieve_version()
def batch_txs(self, safe_nonce: int, safe_tx_hashes: Sequence[bytes]) -> bool: """ Submit signatures to the tx service. It's recommended to be on Safe v1.3.0 to prevent issues with `safeTxGas` and gas estimation. :return: """ if not self.ethereum_client.is_contract( LAST_MULTISEND_CALL_ONLY_CONTRACT): print_formatted_text( HTML( f"<ansired>Multisend call only contract {LAST_MULTISEND_CALL_ONLY_CONTRACT} " f"is not deployed on this network and it's required for batching txs</ansired>" )) multisend_txs = [] for safe_tx_hash in safe_tx_hashes: safe_tx, _ = self.safe_tx_service.get_safe_transaction( safe_tx_hash) # Check if call is already a Multisend call inner_txs = MultiSend.from_transaction_data(safe_tx.data) if inner_txs: multisend_txs.extend(inner_txs) else: multisend_txs.append( MultiSendTx(MultiSendOperation.CALL, safe_tx.to, safe_tx.value, safe_tx.data)) if len(multisend_txs) > 1: multisend = MultiSend(LAST_MULTISEND_CALL_ONLY_CONTRACT, self.ethereum_client) safe_tx = SafeTx( self.ethereum_client, self.address, LAST_MULTISEND_CALL_ONLY_CONTRACT, 0, multisend.build_tx_data(multisend_txs), SafeOperation.DELEGATE_CALL.value, 0, 0, 0, None, None, safe_nonce=safe_nonce, ) else: safe_tx.safe_tx_gas = 0 safe_tx.base_gas = 0 safe_tx.gas_price = 0 safe_tx.signatures = b"" safe_tx.safe_nonce = safe_nonce # Resend single transaction safe_tx = self.sign_transaction(safe_tx) if not safe_tx.signatures: print_formatted_text( HTML("<ansired>At least one owner must be loaded</ansired>")) return False else: return self.post_transaction_to_tx_service(safe_tx)
def multisend_from_receipts(self, receipts: List[TransactionReceipt] = None, safe_nonce: int = None) -> SafeTx: """ Convert multiple Brownie transaction receipts (or history) to a multisend Safe transaction. """ if receipts is None: receipts = history.from_sender(self.address) if safe_nonce is None: safe_nonce = self.pending_nonce() txs = [MultiSendTx(MultiSendOperation.CALL, tx.receiver, tx.value, tx.input) for tx in receipts] data = MultiSend(self.multisend, self.ethereum_client).build_tx_data(txs) return self.build_multisig_tx(self.multisend, 0, data, SafeOperation.DELEGATE_CALL.value, safe_nonce=safe_nonce)
def update_version(self) -> Optional[bool]: """ Update Safe Master Copy and Fallback handler to the last version :return: """ if self.is_version_updated(): raise SafeAlreadyUpdatedException() addresses = (LAST_SAFE_CONTRACT, LAST_DEFAULT_CALLBACK_HANDLER) if not all( self.ethereum_client.is_contract(contract) for contract in addresses): raise UpdateAddressesNotValid("Not valid addresses to update Safe", *addresses) multisend = MultiSend(LAST_MULTISEND_CONTRACT, self.ethereum_client) tx_params = {"from": self.address, "gas": 0, "gasPrice": 0} multisend_txs = [ MultiSendTx(MultiSendOperation.CALL, self.address, 0, data) for data in ( self.safe_contract_1_1_0.functions.changeMasterCopy( LAST_SAFE_CONTRACT).buildTransaction(tx_params)["data"], self.safe_contract_1_1_0.functions.setFallbackHandler( LAST_DEFAULT_CALLBACK_HANDLER).buildTransaction(tx_params) ["data"], ) ] multisend_data = multisend.build_tx_data(multisend_txs) if self.prepare_and_execute_safe_transaction( multisend.address, 0, multisend_data, operation=SafeOperation.DELEGATE_CALL): self.safe_cli_info.master_copy = LAST_SAFE_CONTRACT self.safe_cli_info.fallback_handler = LAST_DEFAULT_CALLBACK_HANDLER self.safe_cli_info.version = self.safe.retrieve_version()