def _calculate_transaction_costs(self, token_amount: TokenAmount, account: Account) -> dict:
        exchange_rate = self.get_current_rate(token_amount)
        eth_sold = EthereumAmount(token_amount.value * exchange_rate.value)
        max_gas_price = min(
            self.w3.eth.gasPrice, self.network_contract_proxy.functions.maxGasPrice().call()
        )
        gas_price = EthereumAmount(Wei(max_gas_price))
        token_network_address = self.get_token_network_address(token_amount.ticker)
        transaction_params = {"from": account.address, "value": eth_sold.as_wei}

        gas = estimate_gas(
            self.w3,
            account,
            self.network_contract_proxy.functions.swapEtherToToken,
            token_network_address,
            exchange_rate.as_wei,
            **transaction_params,
        )

        gas_cost = EthereumAmount(Wei(gas * gas_price.as_wei))
        total = EthereumAmount(gas_cost.value + eth_sold.value)
        return {
            "gas_price": gas_price,
            "gas": gas,
            "eth_sold": eth_sold,
            "total": total,
            "exchange_rate": exchange_rate,
        }
    def get_current_rate(self, token_amount: TokenAmount) -> EthereumAmount:
        amounts_in = self.router_proxy.functions.getAmountsIn(
            token_amount.as_wei,
            [self.weth_address, token_amount.address]).call()

        eth_to_sell = EthereumAmount(Wei(amounts_in[0]))
        return EthereumAmount(eth_to_sell.value / token_amount.value)
    def _calculate_transaction_costs(self, token_amount: TokenAmount, account: Account) -> dict:
        exchange_rate = self.get_current_rate(token_amount)
        eth_sold = EthereumAmount(token_amount.value * exchange_rate.value)
        gas_price = EthereumAmount(Wei(self.w3.eth.gasPrice))
        exchange_proxy = self._get_exchange_proxy(token_amount.ticker)
        latest_block = self.w3.eth.getBlock("latest")
        deadline = latest_block.timestamp + self.EXCHANGE_TIMEOUT
        transaction_params = {"from": account.address, "value": eth_sold.as_wei}

        gas = estimate_gas(
            self.w3,
            account,
            exchange_proxy.functions.ethToTokenSwapOutput,
            token_amount.as_wei,
            deadline,
            **transaction_params,
        )

        gas_cost = EthereumAmount(Wei(gas * gas_price.as_wei))
        total = EthereumAmount(gas_cost.value + eth_sold.value)
        return {
            "gas_price": gas_price,
            "gas": gas,
            "eth_sold": eth_sold,
            "total": total,
            "exchange_rate": exchange_rate,
        }
    def get_current_rate(self, token_amount: TokenAmount) -> EthereumAmount:
        exchange_proxy = self._get_exchange_proxy(token_amount.ticker)

        eth_to_sell = EthereumAmount(
            Wei(exchange_proxy.functions.getEthToTokenOutputPrice(token_amount.as_wei).call())
        )
        return EthereumAmount(eth_to_sell.value / token_amount.value)
示例#5
0
    def test_swap(self, ws_client, config, settings, unlocked,
                  mock_get_exchange, mock_deposit_service_tokens,
                  mock_wait_for_transaction):
        def token_balance(w3, account, token):
            return (TokenAmount(0, token) if token.ticker
                    == settings.transfer_token.ticker else TokenAmount(
                        10, token))

        eth_balance_patch = patch(
            "raiden_installer.account.Account.get_ethereum_balance",
            return_value=EthereumAmount(100))
        token_balance_patch = patch("raiden_installer.web.get_token_balance",
                                    side_effect=token_balance)
        total_tokens_patch = patch(
            "raiden_installer.web.get_total_token_owned",
            side_effect=lambda w3, account, token: TokenAmount(10, token))
        token_deposit_patch = patch(
            "raiden_installer.shared_handlers.get_token_deposit",
            side_effect=lambda w3, account, token: TokenAmount(10, token))

        with eth_balance_patch, token_balance_patch, total_tokens_patch, token_deposit_patch:
            mock_exchange = mock_get_exchange()()
            mock_exchange.calculate_transaction_costs.return_value = {
                "gas_price": EthereumAmount(Wei(1000000000)),
                "gas": Wei(500000),
                "eth_sold": EthereumAmount(0.5),
                "total": EthereumAmount(0.505),
                "exchange_rate": EthereumAmount(0.05),
            }
            mock_exchange.buy_tokens.return_value = os.urandom(32)
            mock_exchange.name = "uniswap"

            data = {
                "method": "swap",
                "configuration_file_name": config.file_name,
                "amount": "10000000000000000000",
                "token": settings.service_token.ticker,
                "exchange": "uniswap"
            }
            ws_client.write_message(json.dumps(data))

            for _ in range(8):
                message = json.loads((yield ws_client.read_message()))
                assert message["type"] == "status-update"

            message = json.loads((yield ws_client.read_message()))
            assert message["type"] == "summary"

            message = json.loads((yield ws_client.read_message()))
            assert message["type"] == "redirect"
            assert message["redirect_url"] == (
                f"/swap/{config.file_name}/{settings.transfer_token.ticker}")

            mock_exchange.calculate_transaction_costs.assert_called_once()
            mock_exchange.buy_tokens.assert_called_once()
            mock_deposit_service_tokens.assert_called_once()
    def calculate_transaction_costs(self, token_amount: TokenAmount,
                                    account: Account) -> dict:
        if not self.is_listing_token(token_amount.ticker):
            raise ExchangeError(
                f"Cannot calculate costs because {self.name} is not listing {token_amount.ticker}"
            )
        if token_amount.as_wei <= 0:
            raise ExchangeError(
                f"Cannot calculate costs for a swap of {token_amount.formatted}"
            )

        log.debug("calculating exchange rate")
        exchange_rate = self.get_current_rate(token_amount)
        eth_sold = EthereumAmount(token_amount.value * exchange_rate.value *
                                  Decimal(EXCHANGE_PRICE_MARGIN))

        log.debug("calculating gas price")
        gas_price = self._get_gas_price()

        transaction_params = {
            "from": account.address,
            "value": eth_sold.as_wei,
            "gasPrice": gas_price.as_wei,
        }
        log.debug("estimating gas")
        gas = self._estimate_gas(token_amount,
                                 account,
                                 transaction_params,
                                 exchange_rate=exchange_rate)

        block = self.w3.eth.getBlock(self.w3.eth.blockNumber)
        max_gas_limit = Wei(int(block["gasLimit"] * 0.9))
        gas_with_margin = Wei(int(gas * GAS_LIMIT_MARGIN))
        gas = min(gas_with_margin, max_gas_limit)
        gas_cost = EthereumAmount(Wei(gas * gas_price.as_wei))
        total = EthereumAmount(gas_cost.value + eth_sold.value)

        log.debug("transaction cost",
                  gas_price=gas_price,
                  gas=gas,
                  eth=eth_sold)
        return {
            "gas_price": gas_price,
            "gas": gas,
            "eth_sold": eth_sold,
            "total": total,
            "exchange_rate": exchange_rate,
        }
示例#7
0
def send_raw_transaction(w3, account, contract_function, *args, **kw):
    transaction_params = {
        "chainId": int(w3.net.version),
        "nonce": w3.eth.getTransactionCount(account.address),
        "gasPrice": kw.pop("gas_price", (w3.eth.generateGasPrice())),
        "gas": kw.pop("gas", None),
    }

    transaction_params.update(**kw)
    if not transaction_params.get("gas"):
        transaction_params["gas"] = estimate_gas(w3, account,
                                                 contract_function, *args,
                                                 **kw)

    gas_price = transaction_params["gasPrice"]
    gas = transaction_params["gas"]
    value = transaction_params.get("value", 0)

    estimated_cost = EthereumAmount(Wei((gas * gas_price) + value))

    log.debug(f"Estimated cost: {estimated_cost.formatted}")

    result = contract_function(*args)
    transaction_data = result.buildTransaction(transaction_params)
    signed = w3.eth.account.signTransaction(transaction_data,
                                            account.private_key)
    tx_hash = w3.eth.sendRawTransaction(signed.rawTransaction)
    log.debug(f"transaction hash: {tx_hash.hex()}")
    return w3.eth.waitForTransactionReceipt(tx_hash, timeout=WEB3_TIMEOUT)
示例#8
0
def send_raw_transaction(w3, account, contract_function, *args, **kw):
    transaction_params = {
        "chainId": w3.eth.chainId,
        "nonce": w3.eth.getTransactionCount(account.address, "pending"),
        "gasPrice": kw.pop("gas_price", (w3.eth.generateGasPrice())),
        "gas": kw.pop("gas", None),
        "from": to_checksum_address(kw.pop("from", account.address))
    }

    transaction_params.update(**kw)
    if not transaction_params.get("gas"):
        transaction_params["gas"] = estimate_gas(w3, account,
                                                 contract_function, *args,
                                                 **kw)

    gas_price = transaction_params["gasPrice"]
    gas = transaction_params["gas"]
    value = transaction_params.get("value", 0)

    estimated_cost = EthereumAmount(Wei((gas * gas_price) + value))

    log.debug(f"Estimated cost: {estimated_cost.formatted}")

    result = contract_function(*args)
    transaction_data = result.buildTransaction(transaction_params)
    signed = w3.eth.account.signTransaction(transaction_data,
                                            account.private_key)
    tx_hash = w3.eth.sendRawTransaction(signed.rawTransaction)
    log.debug(f"transaction hash: {tx_hash.hex()}")
    return tx_hash
示例#9
0
    def get(self, configuration_file_name):
        # Returns the highest estimate of ETH needed to get required service token amount
        configuration_file = RaidenConfigurationFile.get_by_filename(
            configuration_file_name)
        account = configuration_file.account
        w3 = make_web3_provider(
            configuration_file.ethereum_client_rpc_endpoint, account)
        required = RequiredAmounts.for_network(configuration_file.network.name)

        kyber = Kyber(w3=w3)
        uniswap = Uniswap(w3=w3)

        highest_cost = 0
        for exchange in (kyber, uniswap):
            exchange_costs = exchange.calculate_transaction_costs(
                required.service_token, account)
            if not exchange_costs:
                continue
            total_cost = exchange_costs["total"].as_wei
            highest_cost = max(highest_cost, total_cost)

        estimated_cost = EthereumAmount(Wei(highest_cost))
        self.render_json({
            "dex_swap_RDN": {
                "as_wei": estimated_cost.as_wei,
                "formatted": estimated_cost.formatted,
            }
        })
示例#10
0
    def _run_funding(self, configuration_file: RaidenConfigurationFile):
        network = configuration_file.network
        settings = network_settings[network.name]

        if not network.FAUCET_AVAILABLE:
            self._send_error_message(
                f"Can not run automatic funding for {network.capitalized_name}"
            )
            return

        account = configuration_file.account
        w3 = make_web3_provider(
            configuration_file.ethereum_client_rpc_endpoint, account)
        self._send_status_update(
            f"Obtaining {network.capitalized_name} ETH through faucet")
        network.fund(account)
        balance = account.wait_for_ethereum_funds(
            w3=w3, expected_amount=EthereumAmount(0.01))
        self._send_status_update(f"Account funded with {balance.formatted}")

        if settings.service_token.mintable:
            service_token = Erc20Token.find_by_ticker(
                settings.service_token.ticker, settings.network)
            self._send_status_update(f"Minting {service_token.ticker}")
            mint_tokens(w3, account, service_token)

        if settings.transfer_token.mintable:
            transfer_token = Erc20Token.find_by_ticker(
                settings.transfer_token.ticker, settings.network)
            self._send_status_update(f"Minting {transfer_token.ticker}")
            mint_tokens(w3, account, transfer_token)
示例#11
0
 def test_can_mint_tokens(self):
     self.network.fund(self.account)
     self.account.wait_for_ethereum_funds(self.w3, EthereumAmount(0.01))
     tx_hash = mint_tokens(self.w3, self.account, self.svt_token)
     wait_for_transaction(self.w3, tx_hash)
     balance = get_token_balance(self.w3, self.account, self.svt_token)
     self.assertTrue(balance.as_wei >= self.svt_token.supply)
示例#12
0
    def test_can_get_formatted_amount(self):
        zero_eth = EthereumAmount(0)
        one_twei = EthereumAmount(Wei(10 ** 12))
        one_gwei = EthereumAmount(Wei(10 ** 9))
        one_mwei = EthereumAmount(Wei(10 ** 6))
        almost_one_eth = EthereumAmount("0.875")
        some_wei = EthereumAmount(Wei(50_000))

        self.assertEqual(self.one_eth.formatted, "1 ETH")
        self.assertEqual(self.one_rdn.formatted, "1 RDN")
        self.assertEqual(zero_eth.formatted, "0 ETH")
        self.assertEqual(one_twei.formatted, "1 TWEI")
        self.assertEqual(one_gwei.formatted, "1 GWEI")
        self.assertEqual(one_mwei.formatted, "1 MWEI")
        self.assertEqual(almost_one_eth.formatted, "0.875 ETH")
        self.assertEqual(some_wei.formatted, "50000 WEI")
示例#13
0
def addLiquidity(w3, account, router_proxy, current_rate):
    max_tokens = get_token_balance(w3, account, WIZ_TOKEN)

    approve(w3, account, router_proxy.address, max_tokens.as_wei, WIZ_TOKEN)

    deadline = generateDeadline(w3)
    eth_amount = EthereumAmount(0.001)
    token_amount_desired = TokenAmount(eth_amount.value / current_rate.value, WIZ_TOKEN)
    transaction_params = {
        "from": account.address,
        "value": eth_amount.as_wei,
        "gas_price": w3.eth.generateGasPrice(),
        "gas": GAS_LIMIT,
    }

    tx_hash = send_raw_transaction(
        w3,
        account,
        router_proxy.functions.addLiquidityETH,
        WIZ_TOKEN.address,
        token_amount_desired.as_wei,
        int(token_amount_desired.as_wei * 0.8),
        int(eth_amount.as_wei * 0.8),
        account.address,
        deadline,
        **transaction_params,
    )
    wait_for_transaction(w3, tx_hash)
示例#14
0
    def test_swap_without_enough_eth(
        self,
        ws_client,
        config,
        settings,
        unlocked,
        mock_get_exchange,
        mock_deposit_service_tokens,
        mock_wait_for_transaction
    ):
        with patch(
                "raiden_installer.account.Account.get_ethereum_balance",
                return_value=EthereumAmount(0)
        ):
            mock_exchange = mock_get_exchange()()
            mock_exchange.calculate_transaction_costs.return_value = {
                "gas_price": EthereumAmount(Wei(1000000000)),
                "gas": Wei(500000),
                "eth_sold": EthereumAmount(0.5),
                "total": EthereumAmount(0.505),
                "exchange_rate": EthereumAmount(0.05),
            }

            data = {
                "method": "swap",
                "configuration_file_name": config.file_name,
                "amount": "10000000000000000000",
                "token": settings.service_token.ticker,
                "exchange": "uniswap"
            }
            ws_client.write_message(json.dumps(data))

            message = json.loads((yield ws_client.read_message()))
            assert message["type"] == "status-update"

            message = json.loads((yield ws_client.read_message()))
            assert message["type"] == "summary"

            message = json.loads((yield ws_client.read_message()))
            assert message["type"] == "redirect"
            assert message["redirect_url"] == (
                f"/swap/{config.file_name}/{settings.service_token.ticker}"
            )

            mock_exchange.calculate_transaction_costs.assert_called_once()
            mock_exchange.buy_tokens.assert_not_called()
            mock_deposit_service_tokens.assert_not_called()
示例#15
0
    def test_create_required_amounts(self):
        required_amounts = RequiredAmounts.from_settings(self.settings)

        self.assertEqual(
            required_amounts.eth,
            EthereumAmount(Wei(self.settings.ethereum_amount_required))
        )
        self.assertEqual(
            required_amounts.eth_after_swap,
            EthereumAmount(Wei(self.settings.ethereum_amount_required_after_swap))
        )
        self.assertEqual(
            required_amounts.service_token,
            TokenAmount(Wei(self.settings.service_token.amount_required), self.service_token)
        )
        self.assertEqual(
            required_amounts.transfer_token,
            TokenAmount(Wei(self.settings.transfer_token.amount_required), self.transfer_token)
        )
示例#16
0
    def test_cost_estimation_handler(
        self,
        http_client,
        base_url,
        config,
        settings,
        mock_get_exchange
    ):
        exchange = "Kyber"
        exchange_costs = {
            "gas_price": EthereumAmount(Wei(1000000000)),
            "gas": Wei(500000),
            "eth_sold": EthereumAmount(0.5),
            "total": EthereumAmount(0.505),
            "exchange_rate": EthereumAmount(0.05),
        }
        mock_exchange = mock_get_exchange()()
        mock_exchange.name = exchange
        mock_exchange.calculate_transaction_costs.return_value = exchange_costs

        currency = settings.transfer_token.ticker
        target_amount = 3
        data = {
            "exchange": exchange,
            "currency": currency,
            "target_amount": target_amount,
        }
        request = HTTPRequest(
            url=f"{base_url}/api/cost-estimation/{config.file_name}",
            method="POST",
            body=json.dumps(data)
        )
        response = yield http_client.fetch(request)
        json_response = json.loads(response.body)
        assert successful_json_response(response)
        assert json_response["exchange"] == exchange
        assert json_response["currency"] == currency
        assert json_response["target_amount"] == target_amount
        assert json_response["as_wei"] == exchange_costs["total"].as_wei
        assert json_response["formatted"] == exchange_costs["total"].formatted
示例#17
0
    def test_udc_deposit(self):
        self.network.fund(self.account)
        self.account.wait_for_ethereum_funds(self.w3, EthereumAmount(0.01))
        tx_hash = mint_tokens(self.w3, self.account, self.svt_token)
        wait_for_transaction(self.w3, tx_hash)

        amount = get_token_balance(self.w3, self.account, self.svt_token)
        tx_hash = deposit_service_tokens(self.w3, self.account, self.svt_token,
                                         amount.as_wei)
        wait_for_transaction(self.w3, tx_hash)

        deposited = get_token_deposit(self.w3, self.account, self.svt_token)
        self.assertEqual(deposited, amount)
示例#18
0
    def _ensure_ethereum_funds(self, ethereum_amount: EthereumAmount):
        w3 = self._get_web3()
        current_balance = self.account.get_ethereum_balance(w3)
        log.debug(f"Current balance: {current_balance.formatted}")
        network = self._get_network()

        if current_balance < ethereum_amount:
            needed_funds = EthereumAmount(Wei(ethereum_amount.as_wei - current_balance.as_wei))
            print(
                f"Please send at least {needed_funds.formatted} to {self.account.address} on "
                f"{network.capitalized_name}"
            )
            return self._wait_for_ethereum_funds(ethereum_amount=needed_funds)
    def get_current_rate(self, token_amount: TokenAmount) -> EthereumAmount:
        eth_address = self.get_token_network_address(TokenTicker("ETH"))
        token_network_address = self.get_token_network_address(
            token_amount.ticker)

        expected_rate, slippage_rate = self.network_contract_proxy.functions.getExpectedRate(
            token_network_address, eth_address, token_amount.as_wei).call()

        if expected_rate == 0 or slippage_rate == 0:
            raise ExchangeError(
                "Trade not possible at the moment due to lack of liquidity")

        return EthereumAmount(Wei(max(expected_rate, slippage_rate)))
示例#20
0
    def _calculate_transaction_costs(self, token_amount: TokenAmount,
                                     account: Account) -> dict:
        exchange_rate = self.get_current_rate(token_amount)
        eth_sold = EthereumAmount(token_amount.value * exchange_rate.value)
        gas_price = EthereumAmount(Wei(self.w3.eth.generateGasPrice()))
        exchange_proxy = self._get_exchange_proxy(token_amount.ticker)
        latest_block = self.w3.eth.getBlock("latest")
        deadline = latest_block.timestamp + self.EXCHANGE_TIMEOUT
        transaction_params = {
            "from": account.address,
            "value": eth_sold.as_wei,
            "gasPrice": gas_price.as_wei,
        }

        gas = estimate_gas(
            self.w3,
            account,
            exchange_proxy.functions.ethToTokenSwapOutput,
            token_amount.as_wei,
            deadline,
            **transaction_params,
        )

        max_gas_limit = Wei(int(latest_block["gasLimit"] * 0.9))
        gas_with_margin = Wei(int(gas * GAS_LIMIT_MARGIN))
        gas = min(gas_with_margin, max_gas_limit)
        gas_cost = EthereumAmount(Wei(gas * gas_price.as_wei))
        total = EthereumAmount(gas_cost.value + eth_sold.value)
        log.debug("transaction cost",
                  gas_price=gas_price,
                  gas=gas,
                  eth=eth_sold)
        return {
            "gas_price": gas_price,
            "gas": gas,
            "eth_sold": eth_sold,
            "total": total,
            "exchange_rate": exchange_rate,
        }
示例#21
0
    def test_goerli_faucet(self):
        TIMEOUT = 10
        INTERVAL = 1
        time_remaining = TIMEOUT
        self.network.fund(self.account)

        balance = EthereumAmount(Wei(0))
        while time_remaining > 0 or balance.as_wei == 0:
            balance = self.account.get_ethereum_balance(self.w3)
            time.sleep(INTERVAL)
            time_remaining -= INTERVAL

        self.assertTrue(balance.as_wei > 0,
                        f"After {TIMEOUT} seconds, balance was not updated")
示例#22
0
 def test_ge_operator(self):
     self.assertGreaterEqual(self.one_eth, EthereumAmount(1))
示例#23
0
 def test_le_operator(self):
     self.assertLessEqual(self.one_eth, EthereumAmount(1))
示例#24
0
 def test_equality(self):
     self.assertEqual(self.one_eth, EthereumAmount(1))
示例#25
0
 def setUp(self):
     self.one_eth = EthereumAmount(1)
     self.two_eth = EthereumAmount(2)
     self.one_rdn = TokenAmount(1, Erc20Token.find_by_ticker("RDN", "mainnet"))
     self.one_wiz = TokenAmount(1, Erc20Token.find_by_ticker("WIZ", "goerli"))
 def _get_gas_price(self):
     web3_gas_price = self.w3.eth.generateGasPrice()
     kyber_max_gas_price = self.network_contract_proxy.functions.maxGasPrice(
     ).call()
     max_gas_price = min(web3_gas_price, kyber_max_gas_price)
     return EthereumAmount(Wei(max_gas_price))
示例#27
0
 def get_ethereum_balance(self, w3) -> EthereumAmount:
     return EthereumAmount(Wei(w3.eth.getBalance(self.address)))
示例#28
0
    def _calculate_transaction_costs(self, token_amount: TokenAmount,
                                     account: Account) -> dict:
        exchange_rate = self.get_current_rate(token_amount)
        eth_sold = EthereumAmount(token_amount.value * exchange_rate.value *
                                  Decimal(1.2))
        web3_gas_price = Wei(
            int(self.w3.eth.generateGasPrice() * self.GAS_PRICE_MARGIN))

        kyber_max_gas_price = self.network_contract_proxy.functions.maxGasPrice(
        ).call()
        max_gas_price = min(web3_gas_price, kyber_max_gas_price)
        gas_price = EthereumAmount(Wei(max_gas_price))
        log.debug(f"gas price: {gas_price}")
        token_network_address = self.get_token_network_address(
            token_amount.ticker)
        transaction_params = {
            "from": account.address,
            "value": eth_sold.as_wei
        }
        eth_address = to_checksum_address(
            kyber_tokens.get_token_network_address(self.chain_id,
                                                   TokenTicker("ETH")))

        gas = estimate_gas(
            self.w3,
            account,
            self.network_contract_proxy.functions.trade,
            eth_address,
            eth_sold.as_wei,
            token_network_address,
            account.address,
            token_amount.as_wei,
            exchange_rate.as_wei,
            account.address,
            **transaction_params,
        )

        block = self.w3.eth.getBlock(self.w3.eth.blockNumber)
        max_gas_limit = Wei(int(block["gasLimit"] * 0.9))
        gas_with_margin = Wei(int(gas * self.GAS_PRICE_MARGIN))
        gas = min(gas_with_margin, max_gas_limit)
        log.debug("Gas Limit",
                  gas_with_margin=gas_with_margin,
                  max_gas_limit=max_gas_limit)
        if max_gas_limit < gas_with_margin:
            log.debug(
                f"calculated gas was higher than block's gas limit {max_gas_limit}. Using this limit."
            )

        gas_cost = EthereumAmount(Wei(gas * gas_price.as_wei))
        total = EthereumAmount(gas_cost.value + eth_sold.value)

        log.debug("transaction cost",
                  gas_price=gas_price,
                  gas=gas,
                  eth=eth_sold)

        return {
            "gas_price": gas_price,
            "gas": gas,
            "eth_sold": eth_sold,
            "total": total,
            "exchange_rate": exchange_rate,
        }
示例#29
0
def fund_account(account, w3):
    NETWORK.fund(account)
    account.wait_for_ethereum_funds(w3, EthereumAmount(0.01))
 def _get_gas_price(self):
     return EthereumAmount(Wei(self.w3.eth.generateGasPrice()))