def __init__(self, w3: Web3, master_copy_address: str, proxy_factory_address: str): """ Init builder for safe creation using create2 :param w3: Web3 instance :param master_copy_address: `Gnosis Safe` master copy address :param proxy_factory_address: `Gnosis Proxy Factory` address """ assert Web3.isChecksumAddress(master_copy_address) assert Web3.isChecksumAddress(proxy_factory_address) self.w3 = w3 self.master_copy_address = master_copy_address self.proxy_factory_address = proxy_factory_address self.safe_version = (get_safe_contract( w3, master_copy_address).functions.VERSION().call()) if self.safe_version == "1.3.0": self.master_copy_contract = get_safe_V1_3_0_contract( w3, master_copy_address) elif self.safe_version == "1.1.1": self.master_copy_contract = get_safe_V1_1_1_contract( w3, master_copy_address) elif self.safe_version == "1.0.0": self.master_copy_contract = get_safe_V1_0_0_contract( w3, master_copy_address) else: raise ValueError("Safe version must be 1.3.0, 1.1.1 or 1.0.0") self.proxy_factory_contract = get_proxy_factory_contract( w3, proxy_factory_address)
def get_contract(self) -> Contract: v_1_3_0_contract = get_safe_V1_3_0_contract(self.w3, address=self.address) version = v_1_3_0_contract.functions.VERSION().call() if version == "1.3.0": return v_1_3_0_contract else: return get_safe_V1_1_1_contract(self.w3, address=self.address)
def get_supported_abis(self) -> Iterable[ABIFunction]: safe_abis = [ get_safe_V0_0_1_contract(self.dummy_w3).abi, get_safe_V1_0_0_contract(self.dummy_w3).abi, get_safe_V1_1_1_contract(self.dummy_w3).abi, get_safe_V1_3_0_contract(self.dummy_w3).abi, ] # Order is important. If signature is the same (e.g. renaming of `baseGas`) last elements in the list # will take preference return safe_abis
def setUpClass(cls): super().setUpClass() for key, value in _contract_addresses.items(): if callable(value): _contract_addresses[key] = value( cls.ethereum_client, cls.ethereum_test_account).contract_address settings.SAFE_DEFAULT_CALLBACK_HANDLER = _contract_addresses[ "compatibility_fallback_handler"] settings.SAFE_MULTISEND_ADDRESS = _contract_addresses["multi_send"] settings.SAFE_CONTRACT_ADDRESS = _contract_addresses["safe_v1_3_0"] settings.SAFE_V1_1_1_CONTRACT_ADDRESS = _contract_addresses[ "safe_V1_1_1"] settings.SAFE_V1_0_0_CONTRACT_ADDRESS = _contract_addresses[ "safe_V1_0_0"] settings.SAFE_V0_0_1_CONTRACT_ADDRESS = _contract_addresses[ "safe_V0_0_1"] settings.SAFE_PROXY_FACTORY_ADDRESS = _contract_addresses[ "proxy_factory"] settings.SAFE_PROXY_FACTORY_V1_0_0_ADDRESS = _contract_addresses[ "proxy_factory_V1_0_0"] settings.SAFE_VALID_CONTRACT_ADDRESSES = { settings.SAFE_CONTRACT_ADDRESS, settings.SAFE_V1_1_1_CONTRACT_ADDRESS, settings.SAFE_V1_0_0_CONTRACT_ADDRESS, settings.SAFE_V0_0_1_CONTRACT_ADDRESS, } cls.compatibility_fallback_handler = ( get_compatibility_fallback_handler_V1_3_0_contract( cls.w3, _contract_addresses["compatibility_fallback_handler"])) cls.safe_contract_address = _contract_addresses["safe_v1_3_0"] cls.safe_contract = get_safe_V1_3_0_contract(cls.w3, cls.safe_contract_address) cls.safe_contract_V1_1_1_address = _contract_addresses["safe_V1_1_1"] cls.safe_contract_V1_1_1 = get_safe_V1_1_1_contract( cls.w3, cls.safe_contract_V1_1_1_address) cls.safe_contract_V1_0_0_address = _contract_addresses["safe_V1_0_0"] cls.safe_contract_V1_0_0 = get_safe_V1_0_0_contract( cls.w3, cls.safe_contract_V1_0_0_address) cls.safe_contract_V0_0_1_address = _contract_addresses["safe_V0_0_1"] cls.safe_contract_V0_0_1 = get_safe_V1_0_0_contract( cls.w3, cls.safe_contract_V0_0_1_address) cls.proxy_factory_contract_address = _contract_addresses[ "proxy_factory"] cls.proxy_factory_contract = get_proxy_factory_contract( cls.w3, cls.proxy_factory_contract_address) cls.proxy_factory = ProxyFactory(cls.proxy_factory_contract_address, cls.ethereum_client) cls.multi_send_contract = get_multi_send_contract( cls.w3, _contract_addresses["multi_send"]) cls.multi_send = MultiSend(cls.multi_send_contract.address, cls.ethereum_client)
def is_valid(self, ethereum_client: EthereumClient, *args) -> bool: safe_contract = get_safe_V1_1_1_contract(ethereum_client.w3, self.owner) # Newest versions of the Safe contract have `isValidSignature` on the compatibility fallback handler for block_identifier in ("pending", "latest"): try: return safe_contract.functions.isValidSignature( self.safe_tx_hash, self.contract_signature ).call(block_identifier=block_identifier) in ( self.EIP1271_MAGIC_VALUE, self.EIP1271_MAGIC_VALUE_UPDATED, ) except (ValueError, BadFunctionCallOutput, DecodingError): # Error using `pending` block identifier or contract does not exist logger.warning( "Cannot check EIP1271 signature from contract %s", self.owner ) return False
def __init__(self, address: str, node_url: str): self.address = address self.node_url = node_url self.ethereum_client = EthereumClient(self.node_url) self.ens = ENS.fromWeb3(self.ethereum_client.w3) self.network: EthereumNetwork = self.ethereum_client.get_network() self.etherscan = EtherscanApi.from_ethereum_client( self.ethereum_client) self.safe_relay_service = RelayServiceApi.from_ethereum_client( self.ethereum_client) self.safe_tx_service = TransactionServiceApi.from_ethereum_client( self.ethereum_client) self.safe = Safe(address, self.ethereum_client) self.safe_contract = self.safe.get_contract() self.safe_contract_1_1_0 = get_safe_V1_1_1_contract( self.ethereum_client.w3, address=self.address) self.accounts: Set[LocalAccount] = set() self.default_sender: Optional[LocalAccount] = None self.executed_transactions: List[str] = [] self._safe_cli_info: Optional[ SafeCliInfo] = None # Cache for SafeCliInfo self.require_all_signatures = ( True # Require all signatures to be present to send a tx )
def contract_events(self) -> List[ContractEvent]: """ event SafeMultiSigTransaction( address to, uint256 value, bytes data, Enum.Operation operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address payable refundReceiver, bytes signatures, // We combine nonce, sender and threshold into one to avoid stack too deep // Dev note: additionalInfo should not contain `bytes`, as this complicates decoding bytes additionalInfo // abi.encode(nonce, msg.sender, threshold); ); event SafeModuleTransaction( address module, address to, uint256 value, bytes data, Enum.Operation operation, ); event SafeSetup( address indexed initiator, address[] owners, uint256 threshold, address initializer, address fallbackHandler ); event ApproveHash( bytes32 indexed approvedHash, address indexed owner ); event SignMsg( bytes32 indexed msgHash ); event ExecutionFailure( bytes32 txHash, uint256 payment ); event ExecutionSuccess( bytes32 txHash, uint256 payment ); event EnabledModule(address module); event DisabledModule(address module); event ExecutionFromModuleSuccess(address indexed module); event ExecutionFromModuleFailure(address indexed module); event AddedOwner(address owner); event RemovedOwner(address owner); event ChangedThreshold(uint256 threshold); event SafeReceived(address indexed sender, uint256 value); // Incoming ether event ChangedFallbackHandler(address handler); event ChangedGuard(address guard); # ProxyFactory event ProxyCreation(GnosisSafeProxy proxy, address singleton); :return: """ l2_contract = self.ethereum_client.w3.eth.contract( abi=gnosis_safe_l2_v1_3_0_abi ) proxy_factory_contract = self.ethereum_client.w3.eth.contract( abi=proxy_factory_v1_3_0_abi ) old_contract = get_safe_V1_1_1_contract(self.ethereum_client.w3) return [ l2_contract.events.SafeMultiSigTransaction(), l2_contract.events.SafeModuleTransaction(), l2_contract.events.SafeSetup(), l2_contract.events.ApproveHash(), l2_contract.events.SignMsg(), l2_contract.events.ExecutionFailure(), l2_contract.events.ExecutionSuccess(), # Modules l2_contract.events.EnabledModule(), l2_contract.events.DisabledModule(), l2_contract.events.ExecutionFromModuleSuccess(), l2_contract.events.ExecutionFromModuleFailure(), # Owners l2_contract.events.AddedOwner(), l2_contract.events.RemovedOwner(), l2_contract.events.ChangedThreshold(), # Incoming Ether l2_contract.events.SafeReceived(), # Changed FallbackHandler l2_contract.events.ChangedFallbackHandler(), # Changed Guard l2_contract.events.ChangedGuard(), # Change Master Copy old_contract.events.ChangedMasterCopy(), # Proxy creation proxy_factory_contract.events.ProxyCreation(), ]