async def handler_loop(self, bot: Bot, update: Update) -> None:
        async_scheduler: AsyncCallScheduler = AsyncCallScheduler.shared_instance(
        )
        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.lower().startswith(dc)
                    for dc in DISABLED_COMMANDS
            ]):
                self.add_msg_to_queue(
                    f"Command {input_text} is disabled from telegram")
            else:
                # Set display options to max, so that telegram does not display truncated data
                pd.set_option('display.max_rows', 500)
                pd.set_option('display.max_columns', 500)
                pd.set_option('display.width', 1000)

                await async_scheduler.call_async(self._hb._handle_command,
                                                 input_text)

                # Reset to normal, so that pandas's default autodetect width still works
                pd.set_option('display.max_rows', 0)
                pd.set_option('display.max_columns', 0)
                pd.set_option('display.width', 0)
        except Exception as e:
            self.add_msg_to_queue(str(e))
示例#2
0
 async def _get_logs(self,
                     event_filter_params: Dict[str, any],
                     max_tries: Optional[int] = 30) -> List[Dict[str, any]]:
     async_scheduler: AsyncCallScheduler = AsyncCallScheduler.shared_instance(
     )
     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 async_scheduler.call_async(
                 functools.partial(self._w3.eth.getLogs,
                                   event_filter_params))
             break
         except asyncio.CancelledError:
             raise
         except Exception:
             self.logger().debug(
                 f"Block not found with filters: '{event_filter_params}'. Retrying..."
             )
             await asyncio.sleep(0.5)
     return logs
示例#3
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

        tasks: List[Coroutine] = [
            AsyncCallScheduler.shared_instance().call_async(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 safe_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")
示例#4
0
    def __init__(self,
                 mexc_api_key: str,
                 mexc_secret_key: str,
                 poll_interval: float = 5.0,
                 order_book_tracker_data_source_type: OrderBookTrackerDataSourceType = OrderBookTrackerDataSourceType.EXCHANGE_API,
                 trading_pairs: Optional[List[str]] = None,
                 trading_required: bool = True):

        super().__init__()
        self._throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS)
        self._shared_client = aiohttp.ClientSession()
        self._async_scheduler = AsyncCallScheduler(call_interval=0.5)
        self._data_source_type = order_book_tracker_data_source_type
        self._ev_loop = asyncio.get_event_loop()
        self._mexc_auth = MexcAuth(api_key=mexc_api_key, secret_key=mexc_secret_key)
        self._in_flight_orders = {}
        self._last_poll_timestamp = 0
        self._last_timestamp = 0
        self._order_book_tracker = MexcOrderBookTracker(
            throttler=self._throttler, trading_pairs=trading_pairs, shared_client=self._shared_client)
        self._poll_notifier = asyncio.Event()
        self._poll_interval = poll_interval
        self._status_polling_task = None
        self._trading_required = trading_required
        self._trading_rules = {}
        self._trading_rules_polling_task = None
        self._user_stream_tracker = MexcUserStreamTracker(throttler=self._throttler,
                                                          mexc_auth=self._mexc_auth,
                                                          trading_pairs=trading_pairs,
                                                          shared_client=self._shared_client)
        self._user_stream_tracker_task = None
        self._user_stream_event_listener_task = None
示例#5
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"))
        async_scheduler: AsyncCallScheduler = AsyncCallScheduler.shared_instance()

        # Get currently approved amounts
        get_approved_amounts_tasks: List[Coroutine] = [
            async_scheduler.call_async(erc20_token.contract.functions.allowance(self.address, spender).call)
            for erc20_token in self._erc20_token_list
        ]
        approved_amounts: List[int] = await safe_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
示例#6
0
 def login(cls, secrets_manager: BaseSecretsManager) -> bool:
     if not validate_password(secrets_manager):
         return False
     cls.secrets_manager = secrets_manager
     coro = AsyncCallScheduler.shared_instance().call_async(
         cls.decrypt_all, timeout_seconds=30)
     safe_ensure_future(coro)
     return True
    async def check_incoming_eth(self, new_blocks: List[AttributeDict]):
        async_scheduler: AsyncCallScheduler = AsyncCallScheduler.shared_instance(
        )
        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[Coroutine] = [
            async_scheduler.call_async(self._w3.eth.getTransactionReceipt,
                                       t.hash)
            for t in incoming_eth_transactions
        ]
        try:
            transaction_receipts: List[AttributeDict] = await asyncio.gather(
                *get_receipt_tasks)
        except asyncio.CancelledError:
            raise
        except Exception:
            self.logger().network(
                "Error fetching Ethereum block receipts.",
                app_warning_msg="Error fetching Ethereum block receipts. "
                "Please check Ethereum node connection.",
                exc_info=True)
            return

        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))
示例#8
0
    def __init__(self, token: str, chat_id: str, hb: "HummingbotApplication") -> None:
        super().__init__()
        self._token = token or global_config_map.get("telegram_token").value
        self._chat_id = chat_id or global_config_map.get("telegram_chat_id").value
        self._updater = Updater(token=token, workers=0)
        self._hb = hb
        self._ev_loop = asyncio.get_event_loop()
        self._async_call_scheduler = AsyncCallScheduler.shared_instance()

        # Register command handler and start telegram message polling
        handles = [MessageHandler(Filters.text, self.handler)]
        for handle in handles:
            self._updater.dispatcher.add_handler(handle)
    async def check_transaction_receipts(self):
        """
        Look for failed transactions, and emit transaction fail event if any are found.
        """
        async_scheduler: AsyncCallScheduler = AsyncCallScheduler.shared_instance(
        )
        tasks = [
            async_scheduler.call_async(self._w3.eth.getTransactionReceipt,
                                       tx_hash)
            for tx_hash in self._pending_tx_dict.keys()
        ]
        transaction_receipts: List[AttributeDict] = [
            tr for tr in await safe_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 = [
            async_scheduler.call_async(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 safe_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)
示例#10
0
 async def _check_transaction_receipt(self, tx_hash: str, timestamp: int):
     """
     Look for transaction receipt, only raise not found error if they are missing for longer than two minutes.
     """
     async_scheduler: AsyncCallScheduler = AsyncCallScheduler.shared_instance()
     try:
         return await async_scheduler.call_async(self._w3.eth.getTransactionReceipt, tx_hash)
     except TransactionNotFound as e:
         now: float = time.time()
         if now - timestamp > 120:
             stop_tx_hash = e.args[0].split(" ")[3]
             self._stop_tx_tracking(stop_tx_hash)
             self.logger().info(f"Stopped tracking transaction with hash: {stop_tx_hash}.")
         return None
示例#11
0
 async def outgoing_eth_transactions_loop(self):
     async_scheduler: AsyncCallScheduler = AsyncCallScheduler.shared_instance()
     while True:
         signed_transaction: AttributeDict = await self._outgoing_transactions_queue.get()
         tx_hash: str = signed_transaction.hash.hex()
         try:
             await async_scheduler.call_async(self._w3.eth.sendRawTransaction, signed_transaction.rawTransaction)
         except asyncio.CancelledError:
             raise
         except Exception:
             self.logger().network(
                 f"Error sending transaction {tx_hash}.", exc_info=True,
                 app_warning_msg=f"Error sending transaction {tx_hash}. Check wallet network connection")
             self.trigger_event(WalletEvent.TransactionFailure, tx_hash)
             self._local_nonce -= 1
示例#12
0
    def __init__(
        self, token: str, chat_id: str,
        hb: "hummingbot.client.hummingbot_application.HummingbotApplication"
    ) -> None:
        super().__init__()
        self._token = token
        self._chat_id = chat_id
        self._updater = Updater(token=token, workers=0)
        self._hb = hb
        self._ev_loop = asyncio.get_event_loop()
        self._async_call_scheduler = AsyncCallScheduler.shared_instance()
        self._msg_queue: asyncio.Queue = asyncio.Queue()
        self._send_msg_task: Optional[asyncio.Task] = None

        # Register command handler and start telegram message polling
        handles = [MessageHandler(Filters.text, self.handler)]
        for handle in handles:
            self._updater.dispatcher.add_handler(handle)
示例#13
0
 async def list_encrypted(
         self,  # type: HummingbotApplication
 ):
     encrypted_files = list_encrypted_file_paths()
     if len(encrypted_files) == 0:
         self._notify("There is no encrypted file in your conf folder.")
         return
     self.placeholder_mode = True
     self.app.toggle_hide_input()
     in_memory_config_map.get(
         "password").value = await self._one_password_config()
     password = in_memory_config_map.get("password").value
     coro = AsyncCallScheduler.shared_instance().call_async(
         partial(self._list_all_encrypted, encrypted_files, password),
         timeout_seconds=30)
     safe_ensure_future(coro)
     self.app.change_prompt(prompt=">>> ")
     self.app.toggle_hide_input()
     self.placeholder_mode = False
示例#14
0
 def login(cls, password):
     encrypted_files = list_encrypted_file_paths()
     wallets = list_wallets()
     if encrypted_files:
         try:
             decrypt_file(encrypted_files[0], password)
         except ValueError as err:
             if str(err) == "MAC mismatch":
                 return False
             raise err
     elif wallets:
         try:
             unlock_wallet(wallets[0], password)
         except ValueError as err:
             if str(err) == "MAC mismatch":
                 return False
             raise err
     Security.password = password
     coro = AsyncCallScheduler.shared_instance().call_async(cls.decrypt_all, timeout_seconds=30)
     safe_ensure_future(coro)
     return True
 async def _update_gas_price(self):
     async_scheduler: AsyncCallScheduler = AsyncCallScheduler.shared_instance(
     )
     new_gas_price: int = await async_scheduler.call_async(
         getattr, self._w3.eth, "gasPrice")
     self._gas_price = new_gas_price
    async def start_network(self):
        if self._outgoing_transactions_task is not None:
            await self.stop_network()

        async_scheduler: AsyncCallScheduler = AsyncCallScheduler.shared_instance(
        )
        if len(self._erc20_tokens) < len(self._erc20_token_list):
            # Fetch token data.
            fetch_symbols_tasks: List[Coroutine] = [
                token.get_symbol() for token in self._erc20_token_list
            ]
            fetch_decimals_tasks: List[Coroutine] = [
                token.get_decimals() for token in self._erc20_token_list
            ]
            token_symbols: List[str] = await safe_gather(*fetch_symbols_tasks)
            token_decimals: List[int] = await safe_gather(*fetch_decimals_tasks
                                                          )
            for token, symbol, decimals in zip(self._erc20_token_list,
                                               token_symbols, token_decimals):
                self._erc20_tokens[symbol] = token
                self._asset_decimals[symbol] = decimals
            self._weth_token = self._erc20_tokens.get("WETH")

            # Fetch blockchain data.
            self._local_nonce = await async_scheduler.call_async(
                lambda: self.get_remote_nonce())

            # Create event watchers.
            self._new_blocks_watcher = NewBlocksWatcher(self._w3)
            self._account_balance_watcher = AccountBalanceWatcher(
                self._w3, self._new_blocks_watcher, self._account.address, [
                    erc20_token.address
                    for erc20_token in self._erc20_tokens.values()
                ], [token.abi for token in self._erc20_tokens.values()])
            self._erc20_events_watcher = ERC20EventsWatcher(
                self._w3, self._new_blocks_watcher,
                [token.address for token in self._erc20_tokens.values()],
                [token.abi for token in self._erc20_tokens.values()],
                [self._account.address])
            self._incoming_eth_watcher = IncomingEthWatcher(
                self._w3, self._new_blocks_watcher, [self._account.address])
            if self._weth_token is not None:
                self._weth_watcher = WethWatcher(self._w3, self._weth_token,
                                                 self._new_blocks_watcher,
                                                 [self._account.address])
            self._zeroex_fill_watcher = ZeroExFillWatcher(
                self._w3, self._new_blocks_watcher)

        # Connect the event forwarders.
        self._new_blocks_watcher.add_listener(NewBlocksWatcherEvent.NewBlocks,
                                              self._event_forwarder)
        self._erc20_events_watcher.add_listener(
            ERC20WatcherEvent.ReceivedToken,
            self._received_asset_event_forwarder)
        self._erc20_events_watcher.add_listener(
            ERC20WatcherEvent.ApprovedToken,
            self._approved_token_event_forwarder)
        self._incoming_eth_watcher.add_listener(
            IncomingEthWatcherEvent.ReceivedEther,
            self._received_asset_event_forwarder)
        self._zeroex_fill_watcher.add_listener(
            ZeroExEvent.Fill, self._zeroex_fill_event_forwarder)

        if self._weth_watcher is not None:
            self._weth_watcher.add_listener(WalletEvent.WrappedEth,
                                            self._wrapped_eth_event_forwarder)
            self._weth_watcher.add_listener(
                WalletEvent.UnwrappedEth, self._unwrapped_eth_event_forwarder)

        # Start the transaction processing tasks.
        self._outgoing_transactions_task = safe_ensure_future(
            self.outgoing_eth_transactions_loop())
        self._check_transaction_receipts_task = safe_ensure_future(
            self.check_transaction_receipts_loop())

        # Start the event watchers.
        await self._new_blocks_watcher.start_network()
        await self._account_balance_watcher.start_network()
        await self._erc20_events_watcher.start_network()
        await self._incoming_eth_watcher.start_network()
        if self._weth_watcher is not None:
            await self._weth_watcher.start_network()