async def update_balances(self):
        asset_symbols: List[str] = []
        asset_update_tasks: List[asyncio.Task] = []

        for asset_name, contract in self._erc20_contracts.items():
            asset_symbols.append(asset_name)
            asset_update_tasks.append(
                self._ev_loop.run_in_executor(
                    hummingbot.get_executor(),
                    contract.functions.balanceOf(self._account_address).call
                )
            )

        asset_symbols.append("ETH")
        asset_update_tasks.append(self._ev_loop.run_in_executor(
            hummingbot.get_executor(),
            self._w3.eth.getBalance, self._account_address
        ))

        try:
            asset_raw_balances: List[int] = await asyncio.gather(*asset_update_tasks)
            for asset_name, raw_balance in zip(asset_symbols, asset_raw_balances):
                self._raw_account_balances[asset_name] = raw_balance
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().error("Unexpected error fetching account balance updates.", exc_info=True)
    async def check_transaction_receipts(self):
        """
        Look for failed transactions, and emit transaction fail event if any are found.
        """
        ev_loop: asyncio.BaseEventLoop = asyncio.get_event_loop()
        tasks = [
            ev_loop.run_in_executor(hummingbot.get_executor(),
                                    self._w3.eth.getTransactionReceipt,
                                    tx_hash)
            for tx_hash in self._pending_tx_dict.keys()
        ]
        transaction_receipts: List[AttributeDict] = [
            tr for tr in await asyncio.gather(*tasks)
            if (tr is not None and tr.get("blockHash") is not None)
        ]
        block_hash_set: Set[HexBytes] = set(tr.blockHash
                                            for tr in transaction_receipts)
        fetch_block_tasks = [
            ev_loop.run_in_executor(hummingbot.get_executor(),
                                    self._w3.eth.getBlock, block_hash)
            for block_hash in block_hash_set
        ]
        blocks: Dict[HexBytes, AttributeDict] = dict(
            (block.hash, block)
            for block in await asyncio.gather(*fetch_block_tasks)
            if block is not None)

        for receipt in transaction_receipts:
            # Emit gas used event.
            tx_hash: str = receipt.transactionHash.hex()
            gas_price_wei: int = self._pending_tx_dict[tx_hash]
            gas_used: int = receipt.gasUsed
            gas_eth_amount_raw: int = gas_price_wei * gas_used

            if receipt.blockHash in blocks:
                block: AttributeDict = blocks[receipt.blockHash]

                if receipt.status == 0:
                    self.logger().warning(
                        f"The transaction {tx_hash} has failed.")
                    self.trigger_event(WalletEvent.TransactionFailure, tx_hash)

                self.trigger_event(
                    WalletEvent.GasUsed,
                    EthereumGasUsedEvent(float(block.timestamp), tx_hash,
                                         float(gas_price_wei * 1e-9),
                                         gas_price_wei, gas_used,
                                         float(gas_eth_amount_raw * 1e-18),
                                         gas_eth_amount_raw))

                # Stop tracking the transaction.
                self._stop_tx_tracking(tx_hash)
示例#3
0
 async def _get_logs(self,
                     event_filter_params: Dict[str, any],
                     max_tries: Optional[int] = 30) -> List[Dict[str, any]]:
     ev_loop: asyncio.BaseEventLoop = self._ev_loop
     count: int = 0
     logs = []
     while True:
         try:
             count += 1
             if count > max_tries:
                 self.logger().debug(
                     f"Error fetching logs from block with filters: '{event_filter_params}'."
                 )
                 break
             logs = await ev_loop.run_in_executor(
                 hummingbot.get_executor(),
                 functools.partial(self._w3.eth.getLogs,
                                   event_filter_params))
             break
         except asyncio.CancelledError:
             raise
         except Exception as e:
             self.logger().debug(
                 f"Block not found with filters: '{event_filter_params}'. Retrying..."
             )
             await asyncio.sleep(0.5)
     return logs
示例#4
0
    async def _get_contract_info(self):
        if self._name is not None and self._symbol is not None and self._decimals is not None:
            return

        ev_loop: asyncio.AbstractEventLoop = asyncio.get_event_loop()
        tasks: List[asyncio.Task] = [
            ev_loop.run_in_executor(hummingbot.get_executor(), func, *args)
            for func, args in [(self.get_name_from_contract, [self._contract]),
                               (self.get_symbol_from_contract,
                                [self._contract]),
                               (self._contract.functions.decimals().call, [])]
        ]

        try:
            name, symbol, decimals = await asyncio.gather(*tasks)
            self._name = name
            self._symbol = symbol
            self._decimals = decimals
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().network(
                f"Error fetching token info for {self._contract.address}.",
                exc_info=True,
                app_warning_msg=
                f"Error fetching token info for {self._contract.address}. "
                f"Check wallet network connection")
示例#5
0
 async def get_timestamp_for_block(self,
                                   block_hash: HexBytes,
                                   max_tries: Optional[int] = 10) -> int:
     counter = 0
     block: AttributeDict = None
     if block_hash in self._blocks_window:
         block = self._blocks_window[block_hash]
         return block.timestamp
     else:
         while block is None:
             try:
                 if counter == max_tries:
                     raise ValueError(
                         f"Block hash {block_hash.hex()} does not exist.")
                 counter += 1
                 async with timeout(10.0):
                     ev_loop: asyncio.BaseEventLoop = self._ev_loop
                     block = await ev_loop.run_in_executor(
                         hummingbot.get_executor(),
                         functools.partial(self._w3.eth.getBlock,
                                           block_hash,
                                           full_transactions=False))
             except TimeoutError:
                 self.logger().network(
                     f"Timed out fetching new block - '{block_hash}'.",
                     exc_info=True,
                     app_warning_msg=
                     f"Timed out fetching new block - '{block_hash}'. "
                     f"Check wallet network connection")
             finally:
                 await asyncio.sleep(0.5)
         return block.timestamp
示例#6
0
    async def get_block_reorganization(
            self, incoming_block: AttributeDict) -> List[AttributeDict]:
        ev_loop: asyncio.BaseEventLoop = self._ev_loop
        block_reorganization: List[AttributeDict] = []
        expected_parent_hash: HexBytes = incoming_block.parentHash
        while expected_parent_hash not in self._blocks_window and len(
                block_reorganization) < len(self._blocks_window):
            replacement_block = None
            while replacement_block is None:
                replacement_block = await ev_loop.run_in_executor(
                    hummingbot.get_executor(),
                    functools.partial(self._w3.eth.getBlock,
                                      expected_parent_hash,
                                      full_transactions=True))
                if replacement_block is None:
                    await asyncio.sleep(0.5)

            replacement_block_number: int = replacement_block.number
            replacement_block_hash: HexBytes = replacement_block.hash
            replacement_block_parent_hash: HexBytes = replacement_block.parentHash
            self._block_number_to_hash_map[
                replacement_block_number] = replacement_block_hash
            self._blocks_window[replacement_block_hash] = replacement_block
            block_reorganization.append(replacement_block)
            expected_parent_hash = replacement_block_parent_hash

        block_reorganization.reverse()
        return block_reorganization
示例#7
0
    async def fetch_new_blocks_loop(self):
        ev_loop: asyncio.BaseEventLoop = self._ev_loop
        while True:
            try:
                async with timeout(30.0):
                    incoming_block: AttributeDict = await ev_loop.run_in_executor(
                        hummingbot.get_executor(),
                        functools.partial(self._w3.eth.getBlock,
                                          self._block_number_to_fetch,
                                          full_transactions=True))
                    if incoming_block is not None:
                        current_block_hash: HexBytes = self._block_number_to_hash_map.get(
                            self._current_block_number, None)
                        incoming_block_hash: HexBytes = incoming_block.hash
                        incoming_block_parent_hash: HexBytes = incoming_block.parentHash
                        new_blocks: List[AttributeDict] = []
                        if current_block_hash is not None and current_block_hash != incoming_block_parent_hash:
                            block_reorganization: List[
                                AttributeDict] = await self.get_block_reorganization(
                                    incoming_block)
                            new_blocks += block_reorganization

                        self._block_number_to_hash_map[
                            self._block_number_to_fetch] = incoming_block_hash
                        self._blocks_window[
                            incoming_block_hash] = incoming_block
                        new_blocks.append(incoming_block)

                        self._current_block_number = self._block_number_to_fetch
                        self._block_number_to_fetch += 1
                        self.trigger_event(NewBlocksWatcherEvent.NewBlocks,
                                           new_blocks)

                        while len(
                                self._blocks_window) > self._block_window_size:
                            block_hash = self._block_number_to_hash_map.popitem(
                                last=False)[1]
                            del self._blocks_window[block_hash]

            except asyncio.CancelledError:
                raise
            except asyncio.TimeoutError:
                self.logger().network(
                    f"Timed out fetching new block - '{block_hash}'.",
                    exc_info=True,
                    app_warning_msg=
                    f"Timed out fetching new block - '{block_hash}'. "
                    f"Check wallet network connection")
            except Exception:
                self.logger().network(
                    f"Error fetching new block.",
                    exc_info=True,
                    app_warning_msg=f"Error fetching new block. "
                    f"Check wallet network connection")

            now: float = time.time()
            next_second: float = (now // 1) + 1
            await asyncio.sleep(next_second - now)
 async def check_network(self) -> NetworkStatus:
     try:
         await self._ev_loop.run_in_executor(hummingbot.get_executor(),
                                             getattr, self._w3.eth,
                                             "blockNumber")
     except asyncio.CancelledError:
         raise
     except Exception:
         return NetworkStatus.NOT_CONNECTED
     return NetworkStatus.CONNECTED
 async def call_async(self,
                      func: Callable, *args,
                      timeout_seconds: float = 5.0,
                      app_warning_msg: str = "API call error.") -> any:
     coro: Coroutine = self._ev_loop.run_in_executor(
         hummingbot.get_executor(),
         func,
         *args,
     )
     return await self.schedule_async_call(coro, timeout_seconds, app_warning_msg=app_warning_msg)
示例#10
0
 async def outgoing_eth_transactions_loop(self):
     ev_loop: asyncio.AbstractEventLoop = self._ev_loop
     while True:
         signed_transaction: AttributeDict = await self._outgoing_transactions_queue.get(
         )
         tx_hash: str = signed_transaction.hash.hex()
         try:
             await ev_loop.run_in_executor(
                 hummingbot.get_executor(), self._w3.eth.sendRawTransaction,
                 signed_transaction.rawTransaction)
         except asyncio.CancelledError:
             raise
         except Exception:
             self.logger().error(f"Error sending transaction {tx_hash}.",
                                 exc_info=True)
             self.trigger_event(WalletEvent.TransactionFailure, tx_hash)
             self._local_nonce -= 1
    async def handler_loop(self, bot: Bot, update: Update) -> None:
        try:
            input_text = update.message.text.strip()
            output = f"\n[Telegram Input] {input_text}"
            self._hb.app.log(output)

            # if the command does starts with any disabled commands
            if any([input_text.startswith(dc) for dc in DISABLED_COMMANDS]):
                self.add_msg_to_queue(f"Command {input_text} is disabled from telegram")
            else:
                await self._ev_loop.run_in_executor(
                    hummingbot.get_executor(),
                    self._hb._handle_command,
                    input_text
                )
        except Exception as e:
            self.add_msg_to_queue(str(e))
示例#12
0
    async def check_and_fix_approval_amounts(self, spender: str) -> List[str]:
        """
        Maintain the approve amounts for a token.
        This function will be used to ensure trade execution using exchange protocols such as 0x, but should be
        defined in child classes

        Allowance amounts to manage:
         1. Allow external contract to pull tokens from local wallet
        """
        min_approve_amount: int = int(Decimal("1e35"))
        target_approve_amount: int = int(Decimal("1e36"))

        # Get currently approved amounts
        get_approved_amounts_tasks: List[asyncio.Task] = [
            self._ev_loop.run_in_executor(
                hummingbot.get_executor(),
                erc20_token.contract.functions.allowance(
                    self.address, spender).call)
            for erc20_token in self._erc20_token_list
        ]
        approved_amounts: List[int] = await asyncio.gather(
            *get_approved_amounts_tasks)

        # Check and fix the approved amounts
        tx_hashes: List[str] = []
        for approved_amount, erc20_token in zip(approved_amounts,
                                                self._erc20_token_list):
            token_name: str = await erc20_token.get_name()
            token_contract: Contract = erc20_token.contract
            if approved_amount >= min_approve_amount:
                self.logger().info(
                    f"Approval already exists for {token_name} from wallet address {self.address}."
                )
                continue
            self.logger().info(
                f"Approving spender for drawing {token_name} from wallet address {self.address}."
            )
            tx_hash: str = self.execute_transaction(
                token_contract.functions.approve(spender,
                                                 target_approve_amount))
            tx_hashes.append(tx_hash)
        return tx_hashes
示例#13
0
    async def check_incoming_eth(self, new_blocks: List[AttributeDict]):
        watch_addresses: Set[str] = self._watch_addresses
        filtered_blocks: List[AttributeDict] = [
            block for block in new_blocks if block is not None
        ]
        block_to_timestamp: Dict[str, float] = dict(
            (block.hash, float(block.timestamp)) for block in filtered_blocks)
        transactions: List[AttributeDict] = list(
            cytoolz.concat(b.transactions for b in filtered_blocks))
        incoming_eth_transactions: List[AttributeDict] = [
            t for t in transactions
            if ((t.get("to") in watch_addresses) and (t.get("value", 0) > 0))
        ]

        get_receipt_tasks: List[asyncio.Task] = [
            self._ev_loop.run_in_executor(hummingbot.get_executor(),
                                          self._w3.eth.getTransactionReceipt,
                                          t.hash)
            for t in incoming_eth_transactions
        ]
        transaction_receipts: List[AttributeDict] = await asyncio.gather(
            *get_receipt_tasks)

        for incoming_transaction, receipt in zip(incoming_eth_transactions,
                                                 transaction_receipts):
            # Filter out failed transactions.
            if receipt.status != 1:
                continue

            # Emit event.
            raw_eth_value: int = incoming_transaction.get("value")
            eth_value: float = raw_eth_value * 1e-18
            from_address: str = incoming_transaction.get("from")
            to_address: str = incoming_transaction.get("to")
            timestamp: float = block_to_timestamp[incoming_transaction.get(
                "blockHash")]
            self.trigger_event(
                IncomingEthWatcherEvent.ReceivedEther,
                WalletReceivedAssetEvent(timestamp,
                                         incoming_transaction.hash.hex(),
                                         from_address, to_address, "ETH",
                                         eth_value, raw_eth_value))
示例#14
0
 async def _update_gas_price(self):
     new_gas_price: int = await self._ev_loop.run_in_executor(
         hummingbot.get_executor(), getattr, self._w3.eth, "gasPrice")
     self._gas_price = new_gas_price