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 _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 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 test_create_swap_amounts(self):
        swap_amounts = SwapAmounts.from_settings(self.settings)

        self.assertEqual(
            swap_amounts.service_token,
            TokenAmount(Wei(self.settings.service_token.swap_amount), self.service_token)
        )
        self.assertEqual(
            swap_amounts.transfer_token,
            TokenAmount(Wei(self.settings.transfer_token.swap_amount), self.transfer_token)
        )
    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,
        }
Exemple #6
0
def get_token_deposit(w3: Web3, account: Account,
                      token: Erc20Token) -> TokenAmount:
    deposit_proxy = _make_deposit_proxy(w3=w3, token=token)
    amount = Wei(
        deposit_proxy.functions.effectiveBalance(account.address).call())

    return TokenAmount(amount, token)
Exemple #7
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
    def test_udc_deposit_when_already_deposited(self, ws_client, config,
                                                settings, unlocked,
                                                mock_deposit_service_tokens):
        required_deposit = Wei(settings.service_token.amount_required)
        token_balance_patch = patch(
            "raiden_installer.web.get_token_balance",
            side_effect=lambda w3, account, token: TokenAmount(10, token))
        token_deposit_patch = patch("raiden_installer.web.get_token_deposit",
                                    side_effect=lambda w3, account, token:
                                    TokenAmount(required_deposit, token))

        with token_balance_patch, token_deposit_patch:
            data = {
                "method": "udc_deposit",
                "configuration_file_name": config.file_name,
            }
            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"/launch/{config.file_name}")

            mock_deposit_service_tokens.assert_not_called()
def deposit_service_tokens(w3: Web3, account: Account, token: Erc20Token,
                           amount: Wei):
    token_proxy = _make_token_proxy(w3=w3, token=token)
    deposit_proxy = _make_deposit_proxy(w3=w3, token=token)

    current_deposit_amount = TokenAmount(
        Wei(deposit_proxy.functions.total_deposit(account.address).call()),
        token)

    new_deposit_amount = TokenAmount(amount, token)

    total_deposit = current_deposit_amount + new_deposit_amount

    send_raw_transaction(
        w3,
        account,
        token_proxy.functions.approve,
        deposit_proxy.address,
        total_deposit.as_wei,
        gas=GAS_REQUIRED_FOR_APPROVE,
    )

    return send_raw_transaction(
        w3,
        account,
        deposit_proxy.functions.deposit,
        account.address,
        total_deposit.as_wei,
        gas=GAS_REQUIRED_FOR_DEPOSIT,
    )
    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)
Exemple #11
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,
            }
        })
    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")
Exemple #13
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)
    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)
    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()
Exemple #16
0
def deposit_service_tokens(w3: Web3, account: Account, token: Erc20Token,
                           amount: Wei):
    token_proxy = _make_token_proxy(w3=w3, token=token)
    deposit_proxy = _make_deposit_proxy(w3=w3, token=token)

    current_deposit_amount = TokenAmount(
        Wei(deposit_proxy.functions.total_deposit(account.address).call()),
        token)

    gas_price = Wei(int(w3.eth.generateGasPrice() * GAS_PRICE_MARGIN))
    new_deposit_amount = TokenAmount(amount, token)
    total_deposit = current_deposit_amount + new_deposit_amount
    nonce = w3.eth.getTransactionCount(account.address)

    send_raw_transaction(
        w3,
        account,
        token_proxy.functions.approve,
        deposit_proxy.address,
        0,
        gas=GAS_REQUIRED_FOR_APPROVE,
        gas_price=gas_price,
        nonce=nonce,
    )

    send_raw_transaction(
        w3,
        account,
        token_proxy.functions.approve,
        deposit_proxy.address,
        total_deposit.as_wei,
        gas=GAS_REQUIRED_FOR_APPROVE,
        gas_price=gas_price,
        nonce=nonce + 1,
    )

    return send_raw_transaction(
        w3,
        account,
        deposit_proxy.functions.deposit,
        account.address,
        total_deposit.as_wei,
        gas=GAS_REQUIRED_FOR_DEPOSIT,
        gas_price=gas_price,
        nonce=nonce + 2,
    )
    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)
        )
Exemple #18
0
def run_action_swap_kyber():
    account = prompt_account_selection()
    ethereum_rpc_endpoint = prompt_ethereum_rpc_endpoint_selection()
    w3 = make_web3_provider(ethereum_rpc_endpoint.url, account)

    kyber = Exchange.get_by_name("kyber")(w3=w3)
    amount = Wei(5 * (10**18))
    kyber.buy_tokens(account,
                     TokenAmount(amount, Erc20Token.find_by_ticker("RDN")))

    return main_prompt()
    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
    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)))
Exemple #21
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)
Exemple #22
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,
        }
    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")
Exemple #24
0
def get_token_balance(w3: Web3, account: Account,
                      token: Erc20Token) -> TokenAmount:
    token_proxy = _make_token_proxy(w3=w3, token=token)
    amount = Wei(token_proxy.functions.balanceOf(account.address).call())

    return TokenAmount(amount, token)
Exemple #25
0
    def _run_swap(self, **kw):
        try:
            configuration_file_name = kw.get("configuration_file_name")
            exchange_name = kw["exchange"]
            token_amount = kw["amount"]
            token_ticker = kw["token"]
        except (ValueError, KeyError, TypeError) as exc:
            self._send_error_message(f"Invalid request: {exc}")
            return

        try:
            configuration_file = RaidenConfigurationFile.get_by_filename(
                configuration_file_name)
            network_name = configuration_file.network.name
            form = TokenExchangeForm({
                "network": [network_name],
                "exchange": [exchange_name],
                "token_amount": [token_amount],
                "token_ticker": [token_ticker],
            })

            if form.validate():
                account = configuration_file.account
                w3 = make_web3_provider(
                    configuration_file.ethereum_client_rpc_endpoint, account)
                token = Erc20Token.find_by_ticker(form.data["token_ticker"],
                                                  network_name)

                token_amount = TokenAmount(Wei(form.data["token_amount"]),
                                           token)
                exchange = Exchange.get_by_name(form.data["exchange"])(w3=w3)
                self._send_status_update(f"Starting swap at {exchange.name}")

                costs = exchange.calculate_transaction_costs(
                    token_amount, account)
                needed_funds = costs["total"]
                exchange_rate = costs["exchange_rate"]
                balance_before_swap = account.get_ethereum_balance(w3)

                if needed_funds > balance_before_swap:
                    raise ValueError((
                        f"Not enough ETH. {balance_before_swap.formatted} available, but "
                        f"{needed_funds.formatted} needed"))

                self._send_status_update(
                    (f"Best exchange rate found at {exchange.name}: "
                     f"{exchange_rate} / {token_amount.ticker}"))
                self._send_status_update(
                    f"Trying to acquire {token_amount} at this rate")
                self._send_status_update(
                    f"maximal costs estimated: {needed_funds} ")

                transaction_receipt = exchange.buy_tokens(
                    account, token_amount, costs)
                block_with_transaction = transaction_receipt["blockNumber"]
                current_block = w3.eth.blockNumber

                while current_block < block_with_transaction:
                    log.debug("wait for block with transaction to be fetched")
                    current_block = w3.eth.blockNumber
                    time.sleep(1)

                token_balance = get_token_balance(w3, account, token)
                balance_after_swap = account.get_ethereum_balance(w3)
                actual_total_costs = balance_before_swap - balance_after_swap

                self._send_status_update(
                    f"Swap complete. {token_balance.formatted} available")
                self._send_status_update(f"Actual costs: {actual_total_costs}")
                required = RequiredAmounts.for_network(network_name)
                service_token = Erc20Token.find_by_ticker(
                    required.service_token.ticker, network_name)
                service_token_balance = get_token_balance(
                    w3, account, service_token)
                transfer_token = Erc20Token.find_by_ticker(
                    required.transfer_token.ticker, network_name)
                transfer_token_balance = get_token_balance(
                    w3, account, transfer_token)
                time.sleep(2)

                if service_token_balance < required.service_token:
                    self._send_redirect(
                        self.reverse_url("swap", configuration_file.file_name,
                                         service_token.ticker))
                elif transfer_token_balance < required.transfer_token:
                    self._send_redirect(
                        self.reverse_url("swap", configuration_file.file_name,
                                         transfer_token.ticker))
                else:
                    self._send_redirect(
                        self.reverse_url("launch",
                                         configuration_file.file_name))
            else:
                for key, error_list in form.errors.items():
                    error_message = f"{key}: {'/'.join(error_list)}"
                    self._send_error_message(error_message)
        except (json.decoder.JSONDecodeError, KeyError, ExchangeError,
                ValueError) as exc:
            self._send_error_message(str(exc))
Exemple #26
0
 def get_ethereum_balance(self, w3) -> TokenAmount:
     return TokenAmount(Wei(w3.eth.getBalance(self.address)), ETH)
Exemple #27
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,
        }
    def test_can_multiply_amounts(self):
        two_eth_in_wei = 2 * self.one_eth.as_wei

        self.assertEqual(two_eth_in_wei, Wei(2 * 10 ** 18))
 def test_can_convert_to_wei(self):
     self.assertEqual(self.one_eth.as_wei, Wei(10 ** 18))
Exemple #30
0
 def get_ethereum_balance(self, w3) -> EthereumAmount:
     return EthereumAmount(Wei(w3.eth.getBalance(self.address)))