From f5d44a5e9743e788da9a390fff1b999854c3a125 Mon Sep 17 00:00:00 2001 From: abel Date: Wed, 22 Nov 2023 11:47:54 -0300 Subject: [PATCH] (feat) Improved markets and tokens parsing to ensure there are no duplicates --- pyinjective/async_client.py | 81 +++++++++++++----------- tests/model_fixtures/markets_fixtures.py | 2 +- tests/rpc_fixtures/markets_fixtures.py | 2 +- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 44b72d14..7540f6f9 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -120,17 +120,18 @@ def __init__( self._initialize_timeout_height_sync_task() self._tokens_and_markets_initialization_lock = asyncio.Lock() - self._tokens: Optional[Dict[str, Token]] = None + self._tokens_by_denom: Optional[Dict[str, Token]] = None + self._tokens_by_symbol: Optional[Dict[str, Token]] = None self._spot_markets: Optional[Dict[str, SpotMarket]] = None self._derivative_markets: Optional[Dict[str, DerivativeMarket]] = None self._binary_option_markets: Optional[Dict[str, BinaryOptionMarket]] = None async def all_tokens(self) -> Dict[str, Token]: - if self._tokens is None: + if self._tokens_by_symbol is None: async with self._tokens_and_markets_initialization_lock: - if self._tokens is None: + if self._tokens_by_symbol is None: await self._initialize_tokens_and_markets() - return deepcopy(self._tokens) + return deepcopy(self._tokens_by_symbol) async def all_spot_markets(self) -> Dict[str, SpotMarket]: if self._spot_markets is None: @@ -968,7 +969,7 @@ async def _initialize_tokens_and_markets(self): spot_markets = dict() derivative_markets = dict() binary_option_markets = dict() - tokens = dict() + tokens_by_symbol = dict() tokens_by_denom = dict() markets_info = (await self.get_spot_markets(market_status="active")).markets valid_markets = ( @@ -989,19 +990,16 @@ async def _initialize_tokens_and_markets(self): symbol=base_token_symbol, token_meta=market_info.base_token_meta, denom=market_info.base_denom, - all_tokens=tokens, + tokens_by_denom=tokens_by_denom, + tokens_by_symbol=tokens_by_symbol, ) - if base_token.denom not in tokens_by_denom: - tokens_by_denom[base_token.denom] = base_token - quote_token = self._token_representation( symbol=quote_token_symbol, token_meta=market_info.quote_token_meta, denom=market_info.quote_denom, - all_tokens=tokens, + tokens_by_denom=tokens_by_denom, + tokens_by_symbol=tokens_by_symbol, ) - if quote_token.denom not in tokens_by_denom: - tokens_by_denom[quote_token.denom] = quote_token market = SpotMarket( id=market_info.market_id, @@ -1029,10 +1027,9 @@ async def _initialize_tokens_and_markets(self): symbol=quote_token_symbol, token_meta=market_info.quote_token_meta, denom=market_info.quote_denom, - all_tokens=tokens, + tokens_by_denom=tokens_by_denom, + tokens_by_symbol=tokens_by_symbol, ) - if quote_token.denom not in tokens_by_denom: - tokens_by_denom[quote_token.denom] = quote_token market = DerivativeMarket( id=market_info.market_id, @@ -1078,33 +1075,41 @@ async def _initialize_tokens_and_markets(self): binary_option_markets[market.id] = market - self._tokens = tokens + self._tokens_by_denom = tokens_by_denom + self._tokens_by_symbol = tokens_by_symbol self._spot_markets = spot_markets self._derivative_markets = derivative_markets self._binary_option_markets = binary_option_markets - def _token_representation(self, symbol: str, token_meta, denom: str, all_tokens: Dict[str, Token]) -> Token: - token = Token( - name=token_meta.name, - symbol=symbol, - denom=denom, - address=token_meta.address, - decimals=token_meta.decimals, - logo=token_meta.logo, - updated=token_meta.updated_at, - ) - - existing_token = all_tokens.get(token.symbol, None) - if existing_token is None: - all_tokens[token.symbol] = token - existing_token = token - elif existing_token.denom != denom: - existing_token = all_tokens.get(token.name, None) - if existing_token is None: - all_tokens[token.name] = token - existing_token = token - - return existing_token + def _token_representation( + self, + symbol: str, + token_meta, + denom: str, + tokens_by_denom: Dict[str, Token], + tokens_by_symbol: Dict[str, Token], + ) -> Token: + if denom not in tokens_by_denom: + unique_symbol = denom + for symbol_candidate in [symbol, token_meta.symbol, token_meta.name]: + if symbol_candidate not in tokens_by_symbol: + unique_symbol = symbol_candidate + break + + token = Token( + name=token_meta.name, + symbol=symbol, + denom=denom, + address=token_meta.address, + decimals=token_meta.decimals, + logo=token_meta.logo, + updated=token_meta.updated_at, + ) + + tokens_by_denom[denom] = token + tokens_by_symbol[unique_symbol] = token + + return tokens_by_denom[denom] def _chain_cookie_metadata_requestor(self) -> Coroutine: request = tendermint_query.GetLatestBlockRequest() diff --git a/tests/model_fixtures/markets_fixtures.py b/tests/model_fixtures/markets_fixtures.py index 15b35021..47c0bd4f 100644 --- a/tests/model_fixtures/markets_fixtures.py +++ b/tests/model_fixtures/markets_fixtures.py @@ -11,7 +11,7 @@ def inj_token(): token = Token( name="Injective Protocol", symbol="INJ", - denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", + denom="inj", address="0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30", decimals=18, logo="https://static.alchemyapi.io/images/assets/7226.png", diff --git a/tests/rpc_fixtures/markets_fixtures.py b/tests/rpc_fixtures/markets_fixtures.py index 534ec8d7..69f835df 100644 --- a/tests/rpc_fixtures/markets_fixtures.py +++ b/tests/rpc_fixtures/markets_fixtures.py @@ -111,7 +111,7 @@ def inj_usdt_spot_market_meta(inj_token_meta, usdt_token_meta): market_id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", market_status="active", ticker="INJ/USDT", - base_denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", + base_denom="inj", base_token_meta=inj_token_meta, quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", quote_token_meta=usdt_token_meta,