Ejemplo n.º 1
0
    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)))
Ejemplo n.º 2
0
    def buy_tokens(self,
                   account: Account,
                   token_amount: TokenAmount,
                   transaction_costs=None):
        if transaction_costs is None:
            transaction_costs = dict()
        if self.network.name not in self.SUPPORTED_NETWORKS:
            raise ExchangeError(
                f"{self.name} does not list {token_amount.ticker} on {self.network.name}"
            )

        if not transaction_costs:
            transaction_costs = self.calculate_transaction_costs(
                token_amount, account)
        if transaction_costs is None:
            raise ExchangeError("Failed to get transactions costs")

        eth_to_sell = transaction_costs["eth_sold"]
        exchange_rate = transaction_costs["exchange_rate"]
        gas_price = transaction_costs["gas_price"]
        gas = transaction_costs["gas"]

        eth_address = to_checksum_address(
            kyber_tokens.get_token_network_address(self.chain_id,
                                                   TokenTicker("ETH")))

        transaction_params = {
            "from": account.address,
            "gas_price": gas_price.as_wei,
            "gas": gas,
            "value": eth_to_sell.as_wei,
        }
        return send_raw_transaction(
            self.w3,
            account,
            self.network_contract_proxy.functions.trade,
            eth_address,
            eth_to_sell.as_wei,
            self.get_token_network_address(token_amount.ticker),
            account.address,
            token_amount.as_wei,
            exchange_rate.as_wei,
            account.address,
            **transaction_params,
        )
Ejemplo n.º 3
0
    def _buy_tokens(self, account: Account, token_amount: TokenAmount,
                    transaction_costs: dict):
        exchange_rate = transaction_costs["exchange_rate"]
        eth_to_sell = transaction_costs["eth_sold"]
        eth_address = self.get_token_network_address(TokenTicker("ETH"))

        return self._send_buy_transaction(
            account,
            transaction_costs,
            self.network_contract_proxy.functions.trade,
            eth_address,
            eth_to_sell.as_wei,
            self.get_token_network_address(token_amount.ticker),
            account.address,
            token_amount.as_wei,
            exchange_rate.as_wei,
            account.address,
        )
Ejemplo n.º 4
0
    def _estimate_gas(self, token_amount: TokenAmount, account: Account,
                      transaction_params: dict, **kw):
        exchange_rate = kw.get("exchange_rate")
        if exchange_rate is None:
            raise ExchangeError(
                f"An exchange rate is needed to estimate gas for a swap on {self.name}"
            )

        eth_address = self.get_token_network_address(TokenTicker("ETH"))
        return estimate_gas(
            self.w3,
            account,
            self.network_contract_proxy.functions.trade,
            eth_address,
            transaction_params["value"],
            self.get_token_network_address(token_amount.ticker),
            account.address,
            token_amount.as_wei,
            exchange_rate.as_wei,
            account.address,
            **transaction_params,
        )
Ejemplo n.º 5
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,
        }