def deploy_create2_safe_tx(self, safe_address: str) -> SafeCreation2:
        """
        Deploys safe if SafeCreation2 exists.
        :param safe_address:
        :return: tx_hash
        """
        safe_creation2: SafeCreation2 = SafeCreation2.objects.get(
            safe=safe_address)

        if safe_creation2.tx_hash:
            logger.info('Safe=%s has already been deployed with tx-hash=%s',
                        safe_address, safe_creation2.tx_hash)
            return safe_creation2

        if safe_creation2.payment_token and safe_creation2.payment_token != NULL_ADDRESS:
            safe_balance = self.ethereum_client.erc20.get_balance(
                safe_address, safe_creation2.payment_token)
        else:
            safe_balance = self.ethereum_client.get_balance(safe_address)

        if safe_balance < safe_creation2.payment:
            message = 'Balance=%d for safe=%s with payment-token=%s. Not found ' \
                      'required=%d' % (safe_balance,
                                       safe_address,
                                       safe_creation2.payment_token,
                                       safe_creation2.payment)
            logger.info(message)
            raise NotEnoughFundingForCreation(message)

        logger.info(
            'Found %d balance for safe=%s with payment-token=%s. Required=%d',
            safe_balance, safe_address, safe_creation2.payment_token,
            safe_creation2.payment)

        setup_data = HexBytes(safe_creation2.setup_data.tobytes())

        with EthereumNonceLock(self.redis,
                               self.ethereum_client,
                               self.funder_account.address,
                               timeout=60 * 2) as tx_nonce:
            proxy_factory = ProxyFactory(safe_creation2.proxy_factory,
                                         self.ethereum_client)
            ethereum_tx_sent = proxy_factory.deploy_proxy_contract_with_nonce(
                self.funder_account,
                safe_creation2.master_copy,
                setup_data,
                safe_creation2.salt_nonce,
                gas=safe_creation2.gas_estimated,
                gas_price=safe_creation2.gas_price_estimated,
                nonce=tx_nonce)
            EthereumTx.objects.create_from_tx(ethereum_tx_sent.tx,
                                              ethereum_tx_sent.tx_hash)
            safe_creation2.tx_hash = ethereum_tx_sent.tx_hash
            safe_creation2.save()
            logger.info('Deployed safe=%s with tx-hash=%s', safe_address,
                        ethereum_tx_sent.tx_hash.hex())
            return safe_creation2
    def deploy_again_create2_safe_tx(self, safe_address: str) -> SafeCreation2:
        """
        Try to deploy Safe again with a higher gas price
        :param safe_address:
        :return: tx_hash
        """
        safe_creation2: SafeCreation2 = SafeCreation2.objects.get(
            safe=safe_address)

        if not safe_creation2.tx_hash:
            message = f"Safe={safe_address} deploy transaction does not exist"
            logger.info(message)
            raise DeployTransactionDoesNotExist(message)

        if safe_creation2.block_number is not None:
            message = (
                f"Safe={safe_address} has already been deployed with tx-hash={safe_creation2.tx_hash} "
                f"on block-number={safe_creation2.block_number}")
            logger.info(message)
            raise SafeAlreadyExistsException(message)

        ethereum_tx: EthereumTx = EthereumTx.objects.get(
            tx_hash=safe_creation2.tx_hash)
        assert ethereum_tx, "Ethereum tx cannot be missing"

        self._check_safe_balance(safe_creation2)

        setup_data = HexBytes(safe_creation2.setup_data.tobytes())
        proxy_factory = ProxyFactory(safe_creation2.proxy_factory,
                                     self.ethereum_client)
        # Increase gas price a little
        gas_price = math.ceil(
            max(self.gas_station.get_gas_prices().fast, ethereum_tx.gas_price)
            * 1.1)
        ethereum_tx_sent = proxy_factory.deploy_proxy_contract_with_nonce(
            self.funder_account,
            safe_creation2.master_copy,
            setup_data,
            safe_creation2.salt_nonce,
            gas=safe_creation2.gas_estimated + 50000,  # Just in case
            gas_price=gas_price,
            nonce=ethereum_tx.nonce,
        )  # Replace old transaction
        EthereumTx.objects.create_from_tx_dict(ethereum_tx_sent.tx,
                                               ethereum_tx_sent.tx_hash)
        safe_creation2.tx_hash = ethereum_tx_sent.tx_hash.hex()
        safe_creation2.save(update_fields=["tx_hash"])
        logger.info(
            "Send again transaction to deploy Safe=%s with tx-hash=%s",
            safe_address,
            safe_creation2.tx_hash,
        )
        return safe_creation2
    def deploy_create2_safe_tx(self, safe_address: str) -> SafeCreation2:
        """
        Deploys safe if SafeCreation2 exists.
        :param safe_address:
        :return: tx_hash
        """
        safe_creation2: SafeCreation2 = SafeCreation2.objects.get(
            safe=safe_address)

        if safe_creation2.tx_hash:
            logger.info(
                "Safe=%s has already been deployed with tx-hash=%s",
                safe_address,
                safe_creation2.tx_hash,
            )
            return safe_creation2

        self._check_safe_balance(safe_creation2)

        setup_data = HexBytes(safe_creation2.setup_data.tobytes())
        proxy_factory = ProxyFactory(safe_creation2.proxy_factory,
                                     self.ethereum_client)
        with EthereumNonceLock(
                self.redis,
                self.ethereum_client,
                self.funder_account.address,
                lock_timeout=60 * 2,
        ) as tx_nonce:
            ethereum_tx_sent = proxy_factory.deploy_proxy_contract_with_nonce(
                self.funder_account,
                safe_creation2.master_copy,
                setup_data,
                safe_creation2.salt_nonce,
                gas=safe_creation2.gas_estimated + 50000,  # Just in case
                gas_price=safe_creation2.gas_price_estimated,
                nonce=tx_nonce,
            )
            EthereumTx.objects.create_from_tx_dict(ethereum_tx_sent.tx,
                                                   ethereum_tx_sent.tx_hash)
            safe_creation2.tx_hash = ethereum_tx_sent.tx_hash
            safe_creation2.save(update_fields=["tx_hash"])
            logger.info(
                "Send transaction to deploy Safe=%s with tx-hash=%s",
                safe_address,
                ethereum_tx_sent.tx_hash.hex(),
            )
            return safe_creation2
示例#4
0
            f'Sender {account.address} - Balance: {ether_account_balance}Ξ')

    if not ethereum_client.w3.eth.getCode(safe_contract_address) \
            or not ethereum_client.w3.eth.getCode(proxy_factory_address):
        print_formatted_text('Network not supported')
        sys.exit(1)

    salt_nonce = secrets.SystemRandom().randint(0, 2**256 -
                                                1)  # TODO Add support for CPK
    print_formatted_text(
        f'Creating new Safe with owners={owners} threshold={threshold} and sat-nonce={salt_nonce}'
    )
    gas_price = 0
    safe_creation_tx = Safe.build_safe_create2_tx(
        ethereum_client,
        safe_contract_address,
        proxy_factory_address,
        salt_nonce,
        owners,
        threshold,
        gas_price,
        fallback_handler=callback_handler_address,
        payment_token=None)
    proxy_factory = ProxyFactory(proxy_factory_address, ethereum_client)
    ethereum_tx_sent = proxy_factory.deploy_proxy_contract_with_nonce(
        account, safe_contract_address, safe_creation_tx.safe_setup_data,
        safe_creation_tx.salt_nonce)
    print_formatted_text(
        f'Tx with tx-hash={ethereum_tx_sent.tx_hash.hex()} '
        f'will create safe={ethereum_tx_sent.contract_address}')
示例#5
0
def main(*args, **kwargs):
    parser = setup_argument_parser()
    print_formatted_text(
        pyfiglet.figlet_format("Gnosis Safe Creator"))  # Print fancy text
    args = parser.parse_args()
    node_url: URI = args.node_url
    account: LocalAccount = Account.from_key(args.private_key)
    owners: List[str] = args.owners if args.owners else [account.address]
    threshold: int = args.threshold
    salt_nonce: int = args.salt_nonce
    to = NULL_ADDRESS
    data = b""
    payment_token = NULL_ADDRESS
    payment = 0
    payment_receiver = NULL_ADDRESS

    if len(owners) < threshold:
        print_formatted_text(
            "Threshold cannot be bigger than the number of unique owners")
        sys.exit(1)

    safe_contract_address = args.safe_contract or (
        LAST_SAFE_L2_CONTRACT if args.l2 else LAST_SAFE_CONTRACT)
    proxy_factory_address = args.proxy_factory
    fallback_handler = args.callback_handler
    ethereum_client = EthereumClient(node_url)
    ethereum_network = ethereum_client.get_network()

    if not ethereum_client.is_contract(safe_contract_address):
        print_formatted_text(
            f"Safe contract address {safe_contract_address} "
            f"does not exist on network {ethereum_network.name}")
        sys.exit(1)
    elif not ethereum_client.is_contract(proxy_factory_address):
        print_formatted_text(
            f"Proxy contract address {proxy_factory_address} "
            f"does not exist on network {ethereum_network.name}")
        sys.exit(1)
    elif fallback_handler != NULL_ADDRESS and not ethereum_client.is_contract(
            fallback_handler):
        print_formatted_text(
            f"Fallback handler address {fallback_handler} "
            f"does not exist on network {ethereum_network.name}")
        sys.exit(1)

    account_balance: int = ethereum_client.get_balance(account.address)
    if not account_balance:
        print_formatted_text(
            "Client does not have any funds. Let's try anyway in case it's a network without gas costs"
        )
    else:
        ether_account_balance = round(
            ethereum_client.w3.fromWei(account_balance, "ether"), 6)
        print_formatted_text(
            f"Network {ethereum_client.get_network().name} - Sender {account.address} - "
            f"Balance: {ether_account_balance}Ξ")

    if not ethereum_client.w3.eth.getCode(
            safe_contract_address) or not ethereum_client.w3.eth.getCode(
                proxy_factory_address):
        print_formatted_text("Network not supported")
        sys.exit(1)

    print_formatted_text(
        f"Creating new Safe with owners={owners} threshold={threshold} salt-nonce={salt_nonce}"
    )
    print_formatted_text(
        f"Proxy factory={proxy_factory_address} safe-master-copy={safe_contract_address} and "
        f"fallback-handler={fallback_handler}")
    if yes_or_no_question("Do you want to continue?"):
        safe_contract = get_safe_V1_3_0_contract(ethereum_client.w3,
                                                 safe_contract_address)
        safe_creation_tx_data = HexBytes(
            safe_contract.functions.setup(
                owners,
                threshold,
                to,
                data,
                fallback_handler,
                payment_token,
                payment,
                payment_receiver,
            ).buildTransaction({
                "gas": 1,
                "gasPrice": 1
            })["data"])

        proxy_factory = ProxyFactory(proxy_factory_address, ethereum_client)
        ethereum_tx_sent = proxy_factory.deploy_proxy_contract_with_nonce(
            account, safe_contract_address, safe_creation_tx_data, salt_nonce)
        print_formatted_text(
            f"Tx with tx-hash={ethereum_tx_sent.tx_hash.hex()} "
            f"will create safe={ethereum_tx_sent.contract_address}")
        print_formatted_text(f"Tx paramters={ethereum_tx_sent.tx}")