Esempio n. 1
0
    def wait_for_ethereum_funds(self,
                                w3: Web3,
                                expected_amount: EthereumAmount,
                                timeout: int = WEB3_TIMEOUT) -> EthereumAmount:
        time_remaining = timeout
        POLLING_INTERVAL = 1
        block_with_balance = math.inf
        current_block = w3.eth.blockNumber

        while (current_block <
               block_with_balance + REQUIRED_BLOCK_CONFIRMATIONS
               and time_remaining > 0):
            current_block = w3.eth.blockNumber
            balance = self.get_ethereum_balance(w3)

            if balance >= expected_amount:
                if block_with_balance == math.inf:
                    block_with_balance = w3.eth.blockNumber
            else:
                block_with_balance = math.inf

            time.sleep(POLLING_INTERVAL)
            time_remaining -= POLLING_INTERVAL
        log.debug(f"Balance is {balance}")
        return balance
Esempio n. 2
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)
Esempio n. 3
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
Esempio n. 4
0
 def wait_for_ethereum_funds(
     self, w3: Web3, expected_amount: TokenAmount, timeout: int = 300
 ) -> TokenAmount:
     time_remaining = timeout
     POLLING_INTERVAL = 1
     balance = self.get_ethereum_balance(w3)
     while balance < expected_amount and time_remaining > 0:
         balance = self.get_ethereum_balance(w3)
         time.sleep(POLLING_INTERVAL)
         time_remaining -= POLLING_INTERVAL
     log.debug(f"Balance is {balance}")
     return balance
Esempio n. 5
0
def wait_for_transaction(web3: Web3, transaction_receipt: Dict[str, Any]) -> None:

    if "blockNumber" not in transaction_receipt:
        raise KeyError("blockNumber not in transaction receipt.")

    block_with_transaction = transaction_receipt["blockNumber"]
    current_block = web3.eth.blockNumber

    while current_block < block_with_transaction:
        log.debug("wait for block with transaction to be fetched")
        current_block = web3.eth.blockNumber
        time.sleep(1)
Esempio n. 6
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)
Esempio n. 7
0
def wait_for_transaction(w3: Web3, transaction_hash) -> None:
    log.debug("wait for block with transaction to be fetched")
    time_start = time.time()
    block_with_transaction = math.inf
    current_block = w3.eth.blockNumber

    while current_block < block_with_transaction + REQUIRED_BLOCK_CONFIRMATIONS:
        if time.time() - time_start >= WEB3_TIMEOUT:
            raise TransactionTimeoutError(
                f"Tx with hash {transaction_hash} was not found after {WEB3_TIMEOUT} seconds"
            )
        try:
            tx_receipt = w3.eth.getTransactionReceipt(transaction_hash)
            block_with_transaction = tx_receipt["blockNumber"]
        except TransactionNotFound:
            pass

        current_block = w3.eth.blockNumber
        time.sleep(1)
Esempio n. 8
0
 def _execute_rdn_swap(self, exchange):
     log.debug(f"RDN balance is {self.rdn.balance}")
     swap_costs = exchange.calculate_transaction_costs(self.rdn_amount)
     exchange_rate = swap_costs["exchange_rate"]
     log.debug(f"{exchange.name} exchange rate: {exchange_rate.formatted} maximum")
     self._ensure_ethereum_funds(swap_costs["total"])
     exchange.buy_tokens(self.rdn_amount)
     log.debug(f"RDN balance after swap is {self.rdn.balance} RDN")
Esempio n. 9
0
    def _deposit(self):
        network = self._get_network()
        w3 = self._get_web3()
        ethereum_balance = self.account.get_ethereum_balance(w3=w3)

        log.debug(f"Ethereum Balance: {ethereum_balance.formatted}")
        if not ethereum_balance.as_wei:
            network.fund(self.account)

        token = Erc20Token.find_by_ticker(settings.service_token.ticker)
        token_balance = get_token_balance(w3, self.account, token)
        log.debug(f"Token Balance: {token_balance.formatted}")

        if not token_balance.as_wei:
            mint_tokens(w3, self.account, token)
            token_balance = get_token_balance(w3, self.account, token)
            log.debug(f"Tokens minted. New Balance: {token_balance.formatted}")

        deposit_service_tokens(w3, self.account, token, token_balance.as_wei)
Esempio n. 10
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))