Esempio n. 1
0
    def build_test_safe(
        self,
        number_owners: int = 3,
        threshold: Optional[int] = None,
        owners: Optional[List[str]] = None,
        fallback_handler: Optional[str] = None,
    ) -> SafeCreate2Tx:
        salt_nonce = generate_salt_nonce()
        owners = (owners if owners else
                  [Account.create().address for _ in range(number_owners)])
        threshold = threshold if threshold else len(owners) - 1

        gas_price = self.ethereum_client.w3.eth.gas_price
        return Safe.build_safe_create2_tx(
            self.ethereum_client,
            self.safe_contract_address,
            self.proxy_factory_contract_address,
            salt_nonce,
            owners,
            threshold,
            fallback_handler=fallback_handler,
            gas_price=gas_price,
            payment_token=None,
            fixed_creation_cost=0,
        )
Esempio n. 2
0
    def test_deploy_proxy_contract_with_nonce(self):
        salt_nonce = generate_salt_nonce()
        owners = [Account.create().address for _ in range(2)]
        threshold = 2
        payment_token = None
        safe_create2_tx = Safe.build_safe_create2_tx(
            self.ethereum_client, self.safe_contract_address,
            self.proxy_factory_contract_address, salt_nonce, owners, threshold,
            self.gas_price, payment_token)
        # Send ether for safe deploying costs
        self.send_tx(
            {
                'to': safe_create2_tx.safe_address,
                'value': safe_create2_tx.payment
            }, self.ethereum_test_account)

        proxy_factory = ProxyFactory(self.proxy_factory_contract_address,
                                     self.ethereum_client)
        ethereum_tx_sent = proxy_factory.deploy_proxy_contract_with_nonce(
            self.ethereum_test_account,
            safe_create2_tx.master_copy_address,
            safe_create2_tx.safe_setup_data,
            salt_nonce,
            safe_create2_tx.gas,
            gas_price=self.gas_price)
        receipt = self.ethereum_client.get_transaction_receipt(
            ethereum_tx_sent.tx_hash, timeout=20)
        self.assertEqual(receipt.status, 1)
        safe = Safe(ethereum_tx_sent.contract_address, self.ethereum_client)
        self.assertEqual(ethereum_tx_sent.contract_address,
                         safe_create2_tx.safe_address)
        self.assertEqual(set(safe.retrieve_owners()), set(owners))
        self.assertEqual(safe.retrieve_master_copy_address(),
                         safe_create2_tx.master_copy_address)
Esempio n. 3
0
    def predict_address(self, salt_nonce: int, owners: Iterable[str],
                        threshold: int, payment_token: Optional[str]) -> str:
        """
        Return the predicted Safe address
        :param salt_nonce: Random value for solidity `create2` salt
        :param owners: Owners of the new Safe
        :param threshold: Minimum number of users required to operate the Safe
        :param payment_token: Address of the payment token, otherwise `ether` is used
        :rtype: str
        :raises: InvalidPaymentToken
        """

        payment_token = payment_token or NULL_ADDRESS
        payment_token_eth_value = self._get_token_eth_value_or_raise(
            payment_token)
        gas_price: int = self._get_configured_gas_price()
        current_block_number = self.ethereum_client.current_block_number

        logger.info(
            'Safe.build_safe_create2_tx params: %s %s %s %s %s %s %s %s %s %s %s',
            self.safe_contract_address, self.proxy_factory.address, salt_nonce,
            owners, threshold, gas_price, payment_token,
            self.funder_account.address, self.default_callback_handler,
            payment_token_eth_value, self.safe_fixed_creation_cost)

        safe_creation_tx = Safe.build_safe_create2_tx(
            self.ethereum_client,
            self.safe_contract_address,
            self.proxy_factory.address,
            salt_nonce,
            owners,
            threshold,
            gas_price,
            payment_token,
            payment_receiver=self.funder_account.address,
            fallback_handler=self.default_callback_handler,
            payment_token_eth_value=payment_token_eth_value,
            fixed_creation_cost=self.safe_fixed_creation_cost)
        return safe_creation_tx.safe_address
Esempio n. 4
0
    def create2_safe_tx(self, salt_nonce: int, owners: Iterable[str],
                        threshold: int,
                        payment_token: Optional[str]) -> SafeCreation2:
        """
        Prepare creation tx for a new safe using CREATE2 method
        :param salt_nonce: Random value for solidity `create2` salt
        :param owners: Owners of the new Safe
        :param threshold: Minimum number of users required to operate the Safe
        :param payment_token: Address of the payment token, otherwise `ether` is used
        :rtype: SafeCreation2
        :raises: InvalidPaymentToken
        """

        payment_token = payment_token or NULL_ADDRESS
        payment_token_eth_value = self._get_token_eth_value_or_raise(
            payment_token)
        gas_price: int = self._get_configured_gas_price()
        current_block_number = self.ethereum_client.current_block_number
        logger.debug('Building safe create2 tx with gas price %d', gas_price)
        safe_creation_tx = Safe.build_safe_create2_tx(
            self.ethereum_client,
            self.safe_contract_address,
            self.proxy_factory.address,
            salt_nonce,
            owners,
            threshold,
            gas_price,
            payment_token,
            payment_receiver=self.funder_account.address,
            fallback_handler=self.default_callback_handler,
            payment_token_eth_value=payment_token_eth_value,
            fixed_creation_cost=self.safe_fixed_creation_cost)

        safe_contract, created = SafeContract.objects.get_or_create(
            address=safe_creation_tx.safe_address,
            defaults={'master_copy': safe_creation_tx.master_copy_address})

        if not created:
            raise SafeAlreadyExistsException(
                f'Safe={safe_contract.address} cannot be created, already exists'
            )

        # Enable tx and erc20 tracing
        SafeTxStatus.objects.create(safe=safe_contract,
                                    initial_block_number=current_block_number,
                                    tx_block_number=current_block_number,
                                    erc_20_block_number=current_block_number)

        return SafeCreation2.objects.create(
            safe=safe_contract,
            master_copy=safe_creation_tx.master_copy_address,
            proxy_factory=safe_creation_tx.proxy_factory_address,
            salt_nonce=salt_nonce,
            owners=owners,
            threshold=threshold,
            # to  # Contract address for optional delegate call
            # data # Data payload for optional delegate call
            payment_token=None if safe_creation_tx.payment_token
            == NULL_ADDRESS else safe_creation_tx.payment_token,
            payment=safe_creation_tx.payment,
            payment_receiver=safe_creation_tx.payment_receiver,
            setup_data=safe_creation_tx.safe_setup_data,
            gas_estimated=safe_creation_tx.gas,
            gas_price_estimated=safe_creation_tx.gas_price,
        )
Esempio n. 5
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}')