async def _generate_certs( self, # type: HummingbotApplication from_client_password: bool = False ): cert_path: str = get_gateway_paths().local_certs_path.as_posix() if not from_client_password: if certs_files_exist(): self.notify(f"Gateway SSL certification files exist in {cert_path}.") self.notify("To create new certification files, please first manually delete those files.") return with begin_placeholder_mode(self): while True: pass_phase = await self.app.prompt( prompt='Enter pass phase to generate Gateway SSL certifications >>> ', is_password=True ) if pass_phase is not None and len(pass_phase) > 0: break self.notify("Error: Invalid pass phase") else: pass_phase = Security.password create_self_sign_certs(pass_phase) self.notify(f"Gateway SSL certification files are created in {cert_path}.") GatewayHttpClient.get_instance().reload_certs()
def setUpClass(cls) -> None: super().setUpClass() GatewayHttpClient.__instance = None cls._db_path = realpath( join(__file__, "../fixtures/gateway_evm_amm_fixture.db")) cls._http_player = HttpPlayer(cls._db_path) cls._clock: Clock = Clock(ClockMode.REALTIME) cls._client_config_map = ClientConfigAdapter(ClientConfigMap()) cls._connector: GatewayEVMAMM = GatewayEVMAMM( client_config_map=cls._client_config_map, connector_name="uniswap", chain="ethereum", network="ropsten", wallet_address="0x5821715133bB451bDE2d5BC6a4cE3430a4fdAF92", trading_pairs=["DAI-WETH"], trading_required=True) cls._clock.add_iterator(cls._connector) cls._patch_stack = ExitStack() cls._patch_stack.enter_context(cls._http_player.patch_aiohttp_client()) cls._patch_stack.enter_context( patch( "hummingbot.core.gateway.gateway_http_client.GatewayHttpClient._http_client", return_value=ClientSession())) cls._patch_stack.enter_context(cls._clock) GatewayHttpClient.get_instance(client_config_map=cls._client_config_map ).base_url = "https://localhost:5000" ev_loop.run_until_complete(cls.wait_til_ready())
async def _monitor_loop(self): while True: try: if await asyncio.wait_for( GatewayHttpClient.get_instance().ping_gateway(), timeout=POLL_TIMEOUT): if self._current_status is Status.OFFLINE: gateway_connectors = await GatewayHttpClient.get_instance( ).get_connectors(fail_silently=True) GATEWAY_CONNECTORS.clear() GATEWAY_CONNECTORS.extend([ connector["name"] for connector in gateway_connectors.get( "connectors", []) ]) await self.update_gateway_config_key_list() self._current_status = Status.ONLINE else: self._current_status = Status.OFFLINE except asyncio.CancelledError: raise except Exception: self.logger().error( "Unable to find Gateway service. Please check that Gateway service is online. " ) self._current_status = Status.OFFLINE await asyncio.sleep(POLL_INTERVAL)
def setUpClass(cls) -> None: super().setUpClass() cls._db_path = realpath( join(__file__, "../fixtures/gateway_evm_amm_lp_fixture.db")) cls._http_player = HttpPlayer(cls._db_path) cls._clock: Clock = Clock(ClockMode.REALTIME) cls._client_config_map = ClientConfigAdapter(ClientConfigMap()) cls._connector: GatewayEVMAMMLP = GatewayEVMAMMLP( client_config_map=cls._client_config_map, connector_name="uniswapLP", chain="ethereum", network="kovan", wallet_address="0xefb7be8631d154d4c0ad8676fec0897b2894fe8f", trading_pairs=["COIN1-COIN3"], trading_required=True) cls._clock.add_iterator(cls._connector) cls._patch_stack = ExitStack() cls._patch_stack.enter_context(cls._http_player.patch_aiohttp_client()) cls._patch_stack.enter_context( patch( "hummingbot.core.gateway.gateway_http_client.GatewayHttpClient._http_client", return_value=ClientSession())) cls._patch_stack.enter_context(cls._clock) GatewayHttpClient.get_instance(client_config_map=cls._client_config_map ).base_url = "https://localhost:5000" ev_loop.run_until_complete(cls.wait_til_ready())
def setUpClass(cls) -> None: cls._db_path = realpath(join(__file__, "../fixtures/gateway_cancel_fixture.db")) cls._http_player = HttpPlayer(cls._db_path) cls._clock: Clock = Clock(ClockMode.REALTIME) cls._client_config_map = ClientConfigAdapter(ClientConfigMap()) cls._connector: GatewayEVMAMM = GatewayEVMAMM( client_config_map=cls._client_config_map, connector_name="uniswap", chain="ethereum", network=NETWORK, wallet_address=WALLET_ADDRESS, trading_pairs=[TRADING_PAIR], trading_required=True ) cls._clock.add_iterator(cls._connector) cls._patch_stack = ExitStack() cls._patch_stack.enter_context(cls._http_player.patch_aiohttp_client()) cls._patch_stack.enter_context( patch( "hummingbot.core.gateway.gateway_http_client.GatewayHttpClient._http_client", return_value=ClientSession(), ) ) cls._patch_stack.enter_context(cls._clock) GatewayHttpClient.get_instance().base_url = "https://localhost:5000" ev_loop.run_until_complete(cls.wait_til_ready())
async def update_canceling_transactions( self, canceled_tracked_orders: List[GatewayInFlightOrder]): """ Update tracked orders that have a cancel_tx_hash. :param canceled_tracked_orders: Canceled tracked_orders (cancel_tx_has is not None). """ if len(canceled_tracked_orders) < 1: return self.logger().debug( "Polling for order status updates of %d canceled orders.", len(canceled_tracked_orders)) update_results: List[Union[Dict[ str, Any], Exception]] = await safe_gather(*[ GatewayHttpClient.get_instance().get_transaction_status( self.chain, self.network, tx_hash) for tx_hash in [t.cancel_tx_hash for t in canceled_tracked_orders] ], return_exceptions=True) for tracked_order, update_result in zip(canceled_tracked_orders, update_results): if isinstance(update_result, Exception): raise update_result if "txHash" not in update_result: self.logger().error( f"No txHash field for transaction status of {tracked_order.client_order_id}: " f"{update_result}.") continue if update_result["txStatus"] == 1: if update_result["txReceipt"]["status"] == 1: if tracked_order.last_state == "CANCELING": if self.is_amm_order(tracked_order): self.trigger_event( MarketEvent.OrderCancelled, OrderCancelledEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.exchange_order_id, )) self.logger().info( f"The {tracked_order.trade_type.name} order " f"{tracked_order.client_order_id} has been canceled " f"according to the order status API.") elif self.is_approval_order(tracked_order): token_symbol: str = self.get_token_symbol_from_approval_order_id( tracked_order.client_order_id) self.trigger_event( TokenApprovalEvent.ApprovalCancelled, TokenApprovalCancelledEvent( self.current_timestamp, self.connector_name, token_symbol)) self.logger().info( f"Token approval for {tracked_order.client_order_id} on " f"{self.connector_name} has been canceled.") tracked_order.last_state = "CANCELED" self.stop_tracking_order(tracked_order.client_order_id)
async def update_token_approval_status( self, tracked_approvals: List[GatewayInFlightOrder]): """ Calls REST API to get status update for each in-flight token approval transaction. """ if len(tracked_approvals) < 1: return tx_hash_list: List[str] = await safe_gather(*[ tracked_approval.get_exchange_order_id() for tracked_approval in tracked_approvals ]) transaction_states: List[Union[Dict[ str, Any], Exception]] = await safe_gather(*[ GatewayHttpClient.get_instance().get_transaction_status( self.chain, self.network, tx_hash) for tx_hash in tx_hash_list ], return_exceptions=True) for tracked_approval, transaction_status in zip( tracked_approvals, transaction_states): token_symbol: str = self.get_token_symbol_from_approval_order_id( tracked_approval.client_order_id) if isinstance(transaction_status, Exception): self.logger().error( f"Error while trying to approve token {token_symbol} for {self.connector_name}: " f"{transaction_status}") continue if "txHash" not in transaction_status: self.logger().error( f"Error while trying to approve token {token_symbol} for {self.connector_name}: " "txHash key not found in transaction status.") continue if transaction_status["txStatus"] == 1: if transaction_status["txReceipt"]["status"] == 1: self.logger().info( f"Token approval for {tracked_approval.client_order_id} on {self.connector_name} " f"successful.") self.trigger_event( TokenApprovalEvent.ApprovalSuccessful, TokenApprovalSuccessEvent(self.current_timestamp, self.connector_name, token_symbol)) safe_ensure_future(self.update_allowances()) else: self.logger().warning( f"Token approval for {tracked_approval.client_order_id} on {self.connector_name} failed." ) self.trigger_event( TokenApprovalEvent.ApprovalFailed, TokenApprovalFailureEvent(self.current_timestamp, self.connector_name, token_symbol)) self.stop_tracking_order(tracked_approval.client_order_id)
def setUpClass(cls) -> None: super().setUpClass() cls._db_path = realpath( join(__file__, "../fixtures/gateway_http_client_fixture.db")) cls._http_player = HttpPlayer(cls._db_path) cls._patch_stack = ExitStack() cls._patch_stack.enter_context(cls._http_player.patch_aiohttp_client()) cls._patch_stack.enter_context( patch( "hummingbot.core.gateway.gateway_http_client.GatewayHttpClient._http_client", return_value=ClientSession())) GatewayHttpClient.get_instance().base_url = "https://localhost:5000"
def _get_gateway_instance(self) -> GatewayHttpClient: gateway_instance = GatewayHttpClient.get_instance(self._client_config) return gateway_instance
async def _create_gateway(self): gateway_paths: GatewayPaths = get_gateway_paths() gateway_container_name: str = get_gateway_container_name() gateway_conf_mount_path: str = gateway_paths.mount_conf_path.as_posix() certificate_mount_path: str = gateway_paths.mount_certs_path.as_posix() logs_mount_path: str = gateway_paths.mount_logs_path.as_posix() gateway_port: int = get_default_gateway_port() # remove existing container(s) try: old_container = await docker_ipc( "containers", all=True, filters={"name": gateway_container_name} ) for container in old_container: self.notify(f"Removing existing gateway container with id {container['Id']}...") await docker_ipc( "remove_container", container["Id"], force=True ) except Exception: pass # silently ignore exception await self._generate_certs(from_client_password=True) # create cert if await self.check_gateway_image(GATEWAY_DOCKER_REPO, GATEWAY_DOCKER_TAG): self.notify("Found Gateway docker image. No image pull needed.") else: self.notify("Pulling Gateway docker image...") try: await self.pull_gateway_docker(GATEWAY_DOCKER_REPO, GATEWAY_DOCKER_TAG) self.logger().info("Done pulling Gateway docker image.") except Exception as e: self.notify("Error pulling Gateway docker image. Try again.") self.logger().network("Error pulling Gateway docker image. Try again.", exc_info=True, app_warning_msg=str(e)) return self.notify("Creating new Gateway docker container...") host_config: Dict[str, Any] = await docker_ipc( "create_host_config", port_bindings={5000: gateway_port}, binds={ gateway_conf_mount_path: { "bind": "/usr/src/app/conf/", "mode": "rw" }, certificate_mount_path: { "bind": "/usr/src/app/certs/", "mode": "rw" }, logs_mount_path: { "bind": "/usr/src/app/logs/", "mode": "rw" }, } ) container_info: Dict[str, str] = await docker_ipc( "create_container", image=f"{GATEWAY_DOCKER_REPO}:{GATEWAY_DOCKER_TAG}", name=gateway_container_name, ports=[5000], volumes=[ gateway_conf_mount_path, certificate_mount_path, logs_mount_path ], host_config=host_config, environment=[f"GATEWAY_PASSPHRASE={Security.password}"] ) self.notify(f"New Gateway docker container id is {container_info['Id']}.") # Save the gateway port number, if it's not already there. if global_config_map.get("gateway_api_port").value != gateway_port: global_config_map["gateway_api_port"].value = gateway_port global_config_map["gateway_api_host"].value = "localhost" save_to_yml(GLOBAL_CONFIG_PATH, global_config_map) GatewayHttpClient.get_instance().base_url = f"https://{global_config_map['gateway_api_host'].value}:" \ f"{global_config_map['gateway_api_port'].value}" await start_gateway() # create Gateway configs await self._generate_gateway_confs(container_id=container_info["Id"]) # Restarts the Gateway container to ensure that Gateway server reloads new configs try: await docker_ipc(method_name="restart", container=container_info["Id"]) except docker.errors.APIError as e: self.notify(f"Error restarting Gateway container. Error: {e}") self.notify(f"Loaded new configs into Gateway container {container_info['Id']}")
MarketEvent, TokenApprovalEvent, OrderCancelledEvent, TokenApprovalCancelledEvent, ) from hummingbot.core.event.event_logger import EventLogger from hummingbot.core.gateway.gateway_http_client import GatewayHttpClient from hummingbot.core.utils.async_utils import safe_ensure_future from test.mock.http_recorder import HttpRecorder WALLET_ADDRESS = "0x5821715133bB451bDE2d5BC6a4cE3430a4fdAF92" NETWORK = "ropsten" TRADING_PAIR = "WETH-DAI" MAX_FEE_PER_GAS = 2000 MAX_PRIORITY_FEE_PER_GAS = 200 gateway_http_client: GatewayHttpClient = GatewayHttpClient.get_instance() class GatewayCancelDataCollector: fixture_path: str = realpath( join(__file__, "../fixtures/gateway_cancel_fixture.db")) def __init__(self): self._clock: Clock = Clock(ClockMode.REALTIME) self._connector: GatewayEVMAMM = GatewayEVMAMM( "uniswap", "ethereum", NETWORK, WALLET_ADDRESS, trading_pairs=[TRADING_PAIR], trading_required=True)
async def update_order_status(self, tracked_orders: List[GatewayInFlightOrder]): """ Calls REST API to get status update for each in-flight amm orders. """ if len(tracked_orders) < 1: return # split canceled and non-canceled orders tx_hash_list: List[str] = await safe_gather(*[ tracked_order.get_exchange_order_id() for tracked_order in tracked_orders ]) self.logger().debug("Polling for order status updates of %d orders.", len(tracked_orders)) update_results: List[Union[Dict[ str, Any], Exception]] = await safe_gather(*[ GatewayHttpClient.get_instance().get_transaction_status( self.chain, self.network, tx_hash) for tx_hash in tx_hash_list ], return_exceptions=True) for tracked_order, update_result in zip(tracked_orders, update_results): if isinstance(update_result, Exception): raise update_result if "txHash" not in update_result: self.logger().error( f"No txHash field for transaction status of {tracked_order.client_order_id}: " f"{update_result}.") continue if update_result["txStatus"] == 1: if update_result["txReceipt"]["status"] == 1: gas_used: int = update_result["txReceipt"]["gasUsed"] gas_price: Decimal = tracked_order.gas_price fee: Decimal = Decimal(str(gas_used)) * Decimal( str(gas_price)) / Decimal(str(1e9)) self.trigger_event( MarketEvent.OrderFilled, OrderFilledEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.trading_pair, tracked_order.trade_type, tracked_order.order_type, Decimal(str(tracked_order.price)), Decimal(str(tracked_order.amount)), AddedToCostTradeFee(flat_fees=[ TokenAmount(tracked_order.fee_asset, Decimal(str(fee))) ]), exchange_trade_id=tracked_order.exchange_order_id)) tracked_order.last_state = "FILLED" event_tag: MarketEvent = ( MarketEvent.BuyOrderCompleted if tracked_order.trade_type is TradeType.BUY else MarketEvent.SellOrderCompleted) event_class: Union[Type[BuyOrderCompletedEvent], Type[SellOrderCompletedEvent]] = ( BuyOrderCompletedEvent if tracked_order.trade_type is TradeType.BUY else SellOrderCompletedEvent) self.trigger_event( event_tag, event_class( timestamp=self.current_timestamp, order_id=tracked_order.client_order_id, base_asset=tracked_order.base_asset, quote_asset=tracked_order.quote_asset, base_asset_amount=tracked_order. executed_amount_base, quote_asset_amount=tracked_order. executed_amount_quote, order_type=tracked_order.order_type, exchange_order_id=tracked_order.exchange_order_id)) else: self.logger().info( f"The market order {tracked_order.client_order_id} has failed according to order status API. " ) self.trigger_event( MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, tracked_order.client_order_id, tracked_order.order_type)) self.stop_tracking_order(tracked_order.client_order_id)
def _get_gateway_instance( self # type: HummingbotApplication ) -> GatewayHttpClient: gateway_instance = GatewayHttpClient.get_instance(self.client_config_map) return gateway_instance
async def main(): client_config_map: ClientConfigAdapter = load_client_config_map_from_file() await read_system_configs_from_yml() client_config_map.gateway.gateway_api_port = 5000 fixture_db_path: str = realpath(join(__file__, "../fixtures/gateway_http_client_fixture.db")) http_recorder: HttpRecorder = HttpRecorder(fixture_db_path) with http_recorder.patch_aiohttp_client(): gateway_http_client: GatewayHttpClient = GatewayHttpClient() print("ping gateway:", await gateway_http_client.ping_gateway()) print("gateway status:", await gateway_http_client.get_gateway_status()) print("add wallet:", await gateway_http_client.add_wallet( "ethereum", "ropsten", "0000000000000000000000000000000000000000000000000000000000000001" # noqa: mock )) print("get wallets:", await gateway_http_client.get_wallets()) print("get connectors:", await gateway_http_client.get_connectors()) print("set configuration:", await gateway_http_client.update_config("telemetry.enabled", False)) print("get configuration:", await gateway_http_client.get_configuration()) print("get tokens:", await gateway_http_client.get_tokens("ethereum", "ropsten")) print("get network status:", await gateway_http_client.get_network_status("ethereum", "ropsten")) print("get price:", await gateway_http_client.get_price( "ethereum", "ropsten", "uniswap", "DAI", "WETH", Decimal(1000), TradeType.BUY )) print("get balances:", await gateway_http_client.get_balances( "ethereum", "ropsten", "0x5821715133bB451bDE2d5BC6a4cE3430a4fdAF92", ["WETH", "DAI"], )) print("get transaction status:", await gateway_http_client.get_transaction_status( "ethereum", "ropsten", "0xa8d428627dc7f453be79a32129dc18ea29d1a715249a4a5762ca6273da5d96e3" # noqa: mock )) print("get transaction status:", await gateway_http_client.get_transaction_status( "ethereum", "ropsten", "0xa8d428627dc7f453be79a32129dc18ea29d1a715249a4a5762ca6273da5d96e1" # noqa: mock )) print("get evm nonce:", await gateway_http_client.get_evm_nonce( "ethereum", "ropsten", "0x5821715133bB451bDE2d5BC6a4cE3430a4fdAF92" )) print("approve WETH:", await gateway_http_client.approve_token( "ethereum", "ropsten", "0x5821715133bB451bDE2d5BC6a4cE3430a4fdAF92", "WETH", "uniswap", 2 )) print("approve DAI:", await gateway_http_client.approve_token( "ethereum", "ropsten", "0x5821715133bB451bDE2d5BC6a4cE3430a4fdAF92", "DAI", "uniswap", 3 )) print("get WETH, DAI allowance:", await gateway_http_client.get_allowances( "ethereum", "ropsten", "0x5821715133bB451bDE2d5BC6a4cE3430a4fdAF92", ["WETH", "DAI"], "uniswap" )) print("buy DAI with WETH:", await gateway_http_client.amm_trade( "ethereum", "ropsten", "uniswap", "0x5821715133bB451bDE2d5BC6a4cE3430a4fdAF92", "DAI", "WETH", TradeType.BUY, Decimal(1000), Decimal("0.00266"), 4 ))