Exemplo n.º 1
0
    def get_current_rate(self, token_amount: TokenAmount) -> EthereumAmount:
        eth_address = to_checksum_address(
            kyber_tokens.get_token_network_address(self.chain_id, TokenTicker("ETH"))
        )

        token_network_address = to_checksum_address(
            kyber_tokens.get_token_network_address(self.chain_id, 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)))
Exemplo n.º 2
0
 def get_token_network_address(self, ticker: TokenTicker):
     try:
         token_network_address = kyber_tokens.get_token_network_address(
             self.chain_id, ticker)
         return token_network_address and to_checksum_address(
             token_network_address)
     except KeyError:
         return None
Exemplo n.º 3
0
 def get_token_network_address(self, ticker: TokenTicker) -> Address:
     try:
         token_network_address = to_canonical_address(
             kyber_tokens.get_token_network_address(self.chain_id, ticker))
         return token_network_address
     except (KeyError, TypeError) as exc:
         raise ExchangeError(
             f"{self.name} is not listing {ticker}") from exc
Exemplo n.º 4
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,
        )
Exemplo 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,
        }