From ee19f3fe13ed7c1553c302a51ad8f3f1245fadc9 Mon Sep 17 00:00:00 2001 From: abel Date: Mon, 22 May 2023 12:32:31 +0200 Subject: [PATCH 01/40] (feat) Add pytest-grpc plugin to mock grpc iteractions --- Pipfile | 1 + Pipfile.lock | 10 ++- pyinjective/async_client.py | 69 ++++++++++++++- pyinjective/core/__init__.py | 0 pyinjective/core/market.py | 18 ++++ pyinjective/core/token.py | 46 ++++++++++ setup.py | 1 + tests/async_client_tests.py | 58 ++++++++++++- tests/rpc_fixtures/__init__.py | 0 tests/rpc_fixtures/configurable_servicers.py | 18 ++++ tests/rpc_fixtures/markets_fixtures.py | 89 ++++++++++++++++++++ 11 files changed, 304 insertions(+), 6 deletions(-) create mode 100644 pyinjective/core/__init__.py create mode 100644 pyinjective/core/market.py create mode 100644 pyinjective/core/token.py create mode 100644 tests/rpc_fixtures/__init__.py create mode 100644 tests/rpc_fixtures/configurable_servicers.py create mode 100644 tests/rpc_fixtures/markets_fixtures.py diff --git a/Pipfile b/Pipfile index 48efadb4..ca08fc03 100644 --- a/Pipfile +++ b/Pipfile @@ -23,6 +23,7 @@ websockets = "*" [dev-packages] pytest = "*" pytest-asyncio = "*" +pytest-grpc = "*" [requires] python_version = "3" diff --git a/Pipfile.lock b/Pipfile.lock index 5114fcbf..eac635d2 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "feb83698c4edd095a91215ecabe31aa683d9bc6ca8b3a827c9d7a51e6dacff19" + "sha256": "3fd408c25ac559b69dd47dcedde5f431486bf0ac0ff8f27f12d904de7bbe1826" }, "pipfile-spec": 6, "requires": { @@ -1161,6 +1161,14 @@ "index": "pypi", "version": "==0.21.0" }, + "pytest-grpc": { + "hashes": [ + "sha256:0bd2683ffd34199444d707c0ab01970b22e0afbba6cb1ddb6d578c85ebfe09bd", + "sha256:5b062cf498e59995e84b3051da76f7bcff8cfe307927869f7bdc27ab967eee35" + ], + "index": "pypi", + "version": "==0.8.0" + }, "tomli": { "hashes": [ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index db863ff3..2bb5aa03 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -1,12 +1,14 @@ -import os +import asyncio import time import grpc import aiocron -import logging import datetime +from decimal import Decimal from http.cookies import SimpleCookie -from typing import List, Optional, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union +from .core.market import Market +from .core.token import Token from .exceptions import NotFoundError, EmptyMsgError from .proto.cosmos.base.abci.v1beta1 import abci_pb2 as abci_type @@ -179,6 +181,11 @@ def __init__( start=True, ) + self._tokens_and_markets_initialization_lock = asyncio.Lock() + self._tokens: Optional[Dict[str, Token]] = None + self._spot_markets: Optional[Dict[str, Market]] = None + self._derivative_markets: Optional[Dict] + def get_sequence(self): current_seq = self.sequence self.sequence += 1 @@ -976,7 +983,7 @@ async def get_funding_rates(self, market_id: str, **kwargs): skip=kwargs.get("skip"), limit=kwargs.get("limit"), end_time=kwargs.get("end_time"), -) + ) return await self.stubDerivativeExchange.FundingRates(req) async def get_binary_options_markets(self, **kwargs): @@ -1006,3 +1013,57 @@ async def stream_account_portfolio(self, account_address: str, **kwargs): ) metadata = await self.load_cookie(type="exchange") return self.stubPortfolio.StreamAccountPortfolio.__call__(req, metadata=metadata) + + async def _initialize_tokens_and_markets(self): + markets = dict() + tokens = dict() + markets_info = (await self.get_spot_markets()).markets + + for market_info in markets_info: + base_token = tokens.get(market_info.base_token.symbol) + if base_token is None: + base_token = Token( + name=market_info.base_token.name, + symbol=market_info.base_token.symbol, + decimals=market_info.base_token.decimals, + logo=market_info.base_token.logo, + ) + tokens[base_token.symbol] = base_token + base_token.add_source( + denom=market_info.base_denom, + symbol=market_info.base_token.symbol, + address=market_info.base_token.address, + decimals=market_info.base_token.decimals, + updated=market_info.base_token.updated_at, + ) + + quote_token = tokens.get(market_info.base_token.symbol) + if quote_token is None: + quote_token = Token( + name=market_info.quote_token.name, + symbol=market_info.quote_token.symbol, + decimals=market_info.quote_token.decimals, + logo=market_info.quote_token.logo, + ) + quote_token.add_source( + denom=market_info.quote_denom, + symbol=market_info.quote_token.symbol, + address=market_info.quote_token.address, + decimals=market_info.quote_token.decimals, + updated=market_info.quote_token.updated_at, + ) + + market = Market( + id=market_info.market_id, + status=market_info.market_status, + ticker=market_info.ticker, + base_token=base_token, + quote_token=quote_token, + maker_fee_rate=Decimal(market_info.maker_fee_rate), + taker_fee_rate=Decimal(market_info.taker_fee_rate), + service_provider_fee=Decimal(market_info.service_provider_fee), + min_price_tick_size=Decimal(market_info.min_price_tick_size), + min_quantity_tick_size=Decimal(market_info.min_quantity_tick_size), + ) + + markets[market.id] = market diff --git a/pyinjective/core/__init__.py b/pyinjective/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pyinjective/core/market.py b/pyinjective/core/market.py new file mode 100644 index 00000000..c17ce795 --- /dev/null +++ b/pyinjective/core/market.py @@ -0,0 +1,18 @@ +from dataclasses import dataclass +from decimal import Decimal + +from pyinjective.core.token import Token + + +@dataclass +class Market: + id: str + status: str + ticker: str + base_token: Token + quote_token: Token + maker_fee_rate: Decimal + taker_fee_rate: Decimal + service_provider_fee: Decimal + min_price_tick_size: Decimal + min_quantity_tick_size: Decimal \ No newline at end of file diff --git a/pyinjective/core/token.py b/pyinjective/core/token.py new file mode 100644 index 00000000..c80d8e89 --- /dev/null +++ b/pyinjective/core/token.py @@ -0,0 +1,46 @@ +from typing import Dict + + +class TokenSource: + + def __init__( + self, + denom: str, + symbol: str, + address: str, + decimals: int, + updated: int, + ): + self.denom = denom + self.symbol = symbol + self.address = address + self.decimals = decimals + self.updated = updated + + +class Token: + + def __init__( + self, + name: str, + symbol: str, + decimals: int, + logo: str, + ): + self.name = name + self.symbol = symbol + self.decimals = decimals + self.logo = logo + + self._sources = Dict[str, TokenSource] + + def add_source(self, denom: str, symbol: str, address: str, decimals: int, updated: int): + if denom not in self._sources: + token_source = TokenSource( + denom=denom, + symbol=symbol, + address=address, + decimals=decimals, + updated=updated, + ) + self._sources[denom] = token_source \ No newline at end of file diff --git a/setup.py b/setup.py index 52777c1c..af998e2a 100755 --- a/setup.py +++ b/setup.py @@ -40,6 +40,7 @@ DEV_REQUIRED = [ "pytest", "pytest-asyncio", + "pytest-grpc", ] # The rest you shouldn't have to touch too much :) diff --git a/tests/async_client_tests.py b/tests/async_client_tests.py index 0446d9ec..3c2995ba 100644 --- a/tests/async_client_tests.py +++ b/tests/async_client_tests.py @@ -4,7 +4,33 @@ from pyinjective.constant import Network from pyinjective.async_client import AsyncClient +from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import ( + MarketRequest, + MarketsRequest, + MarketResponse, + MarketsResponse, +) +from tests.rpc_fixtures.markets_fixtures import inj_token_meta, ape_token_meta, usdt_token_meta, inj_usdt_spot_market, ape_usdt_spot_market +@pytest.fixture(scope='module') +def grpc_add_to_server(): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import add_InjectiveSpotExchangeRPCServicer_to_server + + return add_InjectiveSpotExchangeRPCServicer_to_server + + +@pytest.fixture(scope='module') +def grpc_servicer(): + from tests.rpc_fixtures.configurable_servicers import ConfigurableInjectiveSpotExchangeRPCServicer + + return ConfigurableInjectiveSpotExchangeRPCServicer() + + +@pytest.fixture(scope='module') +def grpc_stub_cls(grpc_channel): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import InjectiveSpotExchangeRPCStub + + return InjectiveSpotExchangeRPCStub class TestAsyncClient: @@ -81,4 +107,34 @@ async def test_get_account_logs_exception(self, caplog): ) assert (found_log is not None) assert (found_log[0] == "pyinjective.async_client.AsyncClient") - assert (found_log[1] == logging.DEBUG) \ No newline at end of file + assert (found_log[1] == logging.DEBUG) + + @pytest.mark.asyncio + async def test_initialize_tokens_and_markets( + self, + grpc_stub, + grpc_servicer, + inj_usdt_spot_market, + ape_usdt_spot_market + ): + grpc_servicer.markets_queue.append(MarketsResponse( + markets=[inj_usdt_spot_market, ape_usdt_spot_market] + )) + + client = AsyncClient( + network=Network.local(), + insecure=False, + ) + + client.stubSpotExchange = grpc_stub + + await client._initialize_tokens_and_markets() + + assert(3 == len(client.tokens)) + assert(any((inj_usdt_spot_market.base_token_meta.symbol == token.symbol for token in client.tokens))) + assert (any((inj_usdt_spot_market.quote_token_meta.symbol == token.symbol for token in client.tokens))) + assert (any((ape_usdt_spot_market.base_token_meta.symbol == token.symbol for token in client.tokens))) + + assert (2 == len(client.markets)) + assert (any((inj_usdt_spot_market.market_id == market.id for market in client.markets))) + assert (any((ape_usdt_spot_market.market_id == market.id for market in client.markets))) diff --git a/tests/rpc_fixtures/__init__.py b/tests/rpc_fixtures/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/rpc_fixtures/configurable_servicers.py b/tests/rpc_fixtures/configurable_servicers.py new file mode 100644 index 00000000..dff625cf --- /dev/null +++ b/tests/rpc_fixtures/configurable_servicers.py @@ -0,0 +1,18 @@ +from collections import deque + +from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import ( + MarketsRequest, + MarketsResponse, +) +from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import InjectiveSpotExchangeRPCServicer + + +class ConfigurableInjectiveSpotExchangeRPCServicer(InjectiveSpotExchangeRPCServicer): + + def __init__(self): + super().__init__() + self.markets_queue = deque() + + def Markets(self, request: MarketsRequest, context): + return self.markets_queue.pop() + diff --git a/tests/rpc_fixtures/markets_fixtures.py b/tests/rpc_fixtures/markets_fixtures.py new file mode 100644 index 00000000..c21cd755 --- /dev/null +++ b/tests/rpc_fixtures/markets_fixtures.py @@ -0,0 +1,89 @@ +import pytest + + +@pytest.fixture +def inj_token_meta(): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import TokenMeta + + token = TokenMeta( + name="Injective Protocol", + address="0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30", + symbol="INJ", + logo="https://static.alchemyapi.io/images/assets/7226.png", + decimals=18, + updated_at=1681739137644 + ) + + return token + +@pytest.fixture +def ape_token_meta(): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import TokenMeta + + token = TokenMeta( + name="APE", + address="0x0000000000000000000000000000000000000000", + symbol="APE", + logo="https://assets.coingecko.com/coins/images/24383/small/apecoin.jpg?1647476455", + decimals=18, + updated_at=1681739137646 + ) + + return token + +@pytest.fixture +def usdt_token_meta(): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import TokenMeta + + token = TokenMeta( + name="USDT", + address="0x0000000000000000000000000000000000000000", + symbol="USDT", + logo="https://static.alchemyapi.io/images/assets/825.png", + decimals=6, + updated_at=1681739137645 + ) + + return token + +@pytest.fixture +def ape_usdt_spot_market(ape_token_meta, usdt_token_meta): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo + + market_request = SpotMarketInfo( + market_id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", + market_status="active", + ticker="APE/USDT", + base_denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", + base_token_meta=ape_token_meta, + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + quote_token_meta=usdt_token_meta, + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + service_provider_fee="0.4", + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + + return market_request + +@pytest.fixture +def inj_usdt_spot_market(inj_token_meta, usdt_token_meta): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo + + market_request = SpotMarketInfo( + market_id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", + market_status="active", + ticker="INJ/USDT", + base_denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", + base_token_meta=inj_token_meta, + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + quote_token_meta=usdt_token_meta, + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + service_provider_fee="0.4", + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + + return market_request From 06524013d62a640eb9437036d3d6c8fc6adf25c4 Mon Sep 17 00:00:00 2001 From: abel Date: Thu, 25 May 2023 18:21:05 +0200 Subject: [PATCH 02/40] (feat) Refactor Composer to use actual markets and tokens to translate human-readable values into chain format --- Pipfile | 1 - Pipfile.lock | 10 +- README.md | 6 +- examples/chain_client/0_LocalOrderHash.py | 4 +- .../13_MsgIncreasePositionMargin.py | 4 +- examples/chain_client/15_MsgWithdraw.py | 4 +- .../chain_client/16_MsgSubaccountTransfer.py | 4 +- .../chain_client/17_MsgBatchUpdateOrders.py | 6 +- examples/chain_client/18_MsgBid.py | 4 +- examples/chain_client/19_MsgGrant.py | 4 +- examples/chain_client/1_MsgSend.py | 4 +- examples/chain_client/20_MsgExec.py | 8 +- examples/chain_client/21_MsgRevoke.py | 4 +- examples/chain_client/22_MsgSendToEth.py | 4 +- .../chain_client/23_MsgRelayPriceFeedPrice.py | 4 +- examples/chain_client/24_MsgRewardsOptOut.py | 4 +- examples/chain_client/25_MsgDelegate.py | 4 +- .../26_MsgWithdrawDelegatorReward.py | 4 +- examples/chain_client/2_MsgDeposit.py | 4 +- examples/chain_client/30_ExternalTransfer.py | 4 +- .../31_MsgCreateBinaryOptionsLimitOrder.py | 6 +- .../32_MsgCreateBinaryOptionsMarketOrder.py | 6 +- .../33_MsgCancelBinaryOptionsOrder.py | 6 +- .../34_MsgAdminUpdateBinaryOptionsMarket.py | 6 +- .../35_MsgInstantBinaryOptionsMarketLaunch.py | 6 +- .../chain_client/36_MsgRelayProviderPrices.py | 6 +- .../chain_client/3_MsgCreateSpotLimitOrder.py | 6 +- .../chain_client/40_MsgExecuteContract.py | 4 +- .../chain_client/41_MsgCreateInsuranceFund.py | 4 +- examples/chain_client/42_MsgUnderwrite.py | 4 +- .../chain_client/43_MsgRequestRedemption.py | 4 +- .../4_MsgCreateSpotMarketOrder.py | 6 +- examples/chain_client/5_MsgCancelSpotOrder.py | 4 +- .../6_MsgCreateDerivativeLimitOrder.py | 6 +- .../7_MsgCreateDerivativeMarketOrder.py | 6 +- .../8_MsgCancelDerivativeOrder.py | 4 +- pyinjective/async_client.py | 171 ++++++++-- pyinjective/client.py | 2 +- pyinjective/composer.py | 315 +++++++++++------- pyinjective/constant.py | 14 + pyinjective/core/market.py | 137 +++++++- pyinjective/core/token.py | 39 +-- ...ective_derivative_exchange_rpc_pb2_grpc.py | 24 +- .../injective_spot_exchange_rpc_pb2_grpc.py | 22 +- pyinjective/utils/utils.py | 108 ------ setup.py | 1 - tests/composer_tests.py | 183 ---------- tests/{ => core}/__init__.py | 0 tests/core/test_market.py | 213 ++++++++++++ tests/core/test_token.py | 15 + tests/model_fixtures/__init__.py | 0 tests/model_fixtures/markets_fixtures.py | 113 +++++++ tests/rpc_fixtures/configurable_servicers.py | 28 +- tests/rpc_fixtures/markets_fixtures.py | 95 +++++- ...c_client_tests.py => test_async_client.py} | 90 +++-- tests/test_composer.py | 222 ++++++++++++ 56 files changed, 1308 insertions(+), 659 deletions(-) delete mode 100644 pyinjective/utils/utils.py delete mode 100644 tests/composer_tests.py rename tests/{ => core}/__init__.py (100%) create mode 100644 tests/core/test_market.py create mode 100644 tests/core/test_token.py create mode 100644 tests/model_fixtures/__init__.py create mode 100644 tests/model_fixtures/markets_fixtures.py rename tests/{async_client_tests.py => test_async_client.py} (55%) create mode 100644 tests/test_composer.py diff --git a/Pipfile b/Pipfile index ca08fc03..48efadb4 100644 --- a/Pipfile +++ b/Pipfile @@ -23,7 +23,6 @@ websockets = "*" [dev-packages] pytest = "*" pytest-asyncio = "*" -pytest-grpc = "*" [requires] python_version = "3" diff --git a/Pipfile.lock b/Pipfile.lock index eac635d2..5114fcbf 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "3fd408c25ac559b69dd47dcedde5f431486bf0ac0ff8f27f12d904de7bbe1826" + "sha256": "feb83698c4edd095a91215ecabe31aa683d9bc6ca8b3a827c9d7a51e6dacff19" }, "pipfile-spec": 6, "requires": { @@ -1161,14 +1161,6 @@ "index": "pypi", "version": "==0.21.0" }, - "pytest-grpc": { - "hashes": [ - "sha256:0bd2683ffd34199444d707c0ab01970b22e0afbba6cb1ddb6d578c85ebfe09bd", - "sha256:5b062cf498e59995e84b3051da76f7bcff8cfe307927869f7bdc27ab967eee35" - ], - "index": "pypi", - "version": "==0.8.0" - }, "tomli": { "hashes": [ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", diff --git a/README.md b/README.md index 82b55893..f3c37feb 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,12 @@ make tests ``` ### Changelogs -**0.6.3**(change before release) +**0.7**(change before release) * Change logging logic to use different loggers for each module and class +* Refactor Composer to be created with all the markets and tokens. The Composer now uses the real markets and tokens to convert human-readable values to chain format +* The Composer can still be instantiated without markets and tokens. When markets and tokens are not provided the Composer loads the required information from the Denoms used in previous versions +* Change in AsyncClient to be able to create Composer instances for the client network, markets and tokens +* Examples have been adapted to create Composer instances using the AsyncClient * Add `pytest` as a development dependency to implement and run unit tests **0.6.2.7** diff --git a/examples/chain_client/0_LocalOrderHash.py b/examples/chain_client/0_LocalOrderHash.py index a43cffee..12f6e448 100644 --- a/examples/chain_client/0_LocalOrderHash.py +++ b/examples/chain_client/0_LocalOrderHash.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/13_MsgIncreasePositionMargin.py b/examples/chain_client/13_MsgIncreasePositionMargin.py index 6d3926ec..1f89b287 100644 --- a/examples/chain_client/13_MsgIncreasePositionMargin.py +++ b/examples/chain_client/13_MsgIncreasePositionMargin.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/15_MsgWithdraw.py b/examples/chain_client/15_MsgWithdraw.py index 74fc8bce..5694ae46 100644 --- a/examples/chain_client/15_MsgWithdraw.py +++ b/examples/chain_client/15_MsgWithdraw.py @@ -13,9 +13,7 @@ # limitations under the License. import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -25,10 +23,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/16_MsgSubaccountTransfer.py b/examples/chain_client/16_MsgSubaccountTransfer.py index 6d02e5c2..7ec93b4c 100644 --- a/examples/chain_client/16_MsgSubaccountTransfer.py +++ b/examples/chain_client/16_MsgSubaccountTransfer.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/17_MsgBatchUpdateOrders.py b/examples/chain_client/17_MsgBatchUpdateOrders.py index 71060bb6..044a93a7 100644 --- a/examples/chain_client/17_MsgBatchUpdateOrders.py +++ b/examples/chain_client/17_MsgBatchUpdateOrders.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -132,7 +130,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/18_MsgBid.py b/examples/chain_client/18_MsgBid.py index 35ab0256..e48ef1fa 100644 --- a/examples/chain_client/18_MsgBid.py +++ b/examples/chain_client/18_MsgBid.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -10,10 +8,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/19_MsgGrant.py b/examples/chain_client/19_MsgGrant.py index da9fbbb5..2b0bbb7b 100644 --- a/examples/chain_client/19_MsgGrant.py +++ b/examples/chain_client/19_MsgGrant.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/1_MsgSend.py b/examples/chain_client/1_MsgSend.py index f3a48769..0a37afc1 100644 --- a/examples/chain_client/1_MsgSend.py +++ b/examples/chain_client/1_MsgSend.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,11 +9,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False, chain_cookie_location="/tmp/.chain_cookie") + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/20_MsgExec.py b/examples/chain_client/20_MsgExec.py index 48e83e61..d54bba07 100644 --- a/examples/chain_client/20_MsgExec.py +++ b/examples/chain_client/20_MsgExec.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -63,9 +61,9 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) data=(str(sim_res_msg[0]).replace("results:", '')) - unpacked_msg_res = ProtoMsgComposer.UnpackMsgExecResponse( + unpacked_msg_res = composer.UnpackMsgExecResponse( msg_type=msg0.__class__.__name__, data=data ) diff --git a/examples/chain_client/21_MsgRevoke.py b/examples/chain_client/21_MsgRevoke.py index b01d799c..e6d35bd2 100644 --- a/examples/chain_client/21_MsgRevoke.py +++ b/examples/chain_client/21_MsgRevoke.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/22_MsgSendToEth.py b/examples/chain_client/22_MsgSendToEth.py index 91ecceb3..3b9abfc8 100644 --- a/examples/chain_client/22_MsgSendToEth.py +++ b/examples/chain_client/22_MsgSendToEth.py @@ -1,8 +1,6 @@ import asyncio -import logging import requests -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/23_MsgRelayPriceFeedPrice.py b/examples/chain_client/23_MsgRelayPriceFeedPrice.py index 592e993e..1f9bfc53 100644 --- a/examples/chain_client/23_MsgRelayPriceFeedPrice.py +++ b/examples/chain_client/23_MsgRelayPriceFeedPrice.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/24_MsgRewardsOptOut.py b/examples/chain_client/24_MsgRewardsOptOut.py index eb413004..34c48bc7 100644 --- a/examples/chain_client/24_MsgRewardsOptOut.py +++ b/examples/chain_client/24_MsgRewardsOptOut.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/25_MsgDelegate.py b/examples/chain_client/25_MsgDelegate.py index fb78dba8..d040dfd2 100644 --- a/examples/chain_client/25_MsgDelegate.py +++ b/examples/chain_client/25_MsgDelegate.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/26_MsgWithdrawDelegatorReward.py b/examples/chain_client/26_MsgWithdrawDelegatorReward.py index a1b955a7..c133f0ec 100644 --- a/examples/chain_client/26_MsgWithdrawDelegatorReward.py +++ b/examples/chain_client/26_MsgWithdrawDelegatorReward.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/2_MsgDeposit.py b/examples/chain_client/2_MsgDeposit.py index bcb6f78e..a1684ddc 100644 --- a/examples/chain_client/2_MsgDeposit.py +++ b/examples/chain_client/2_MsgDeposit.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/30_ExternalTransfer.py b/examples/chain_client/30_ExternalTransfer.py index 26defc09..1fcef982 100644 --- a/examples/chain_client/30_ExternalTransfer.py +++ b/examples/chain_client/30_ExternalTransfer.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py index 41aebc5c..bc6b18e3 100644 --- a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py +++ b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network, Denom @@ -10,10 +8,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -62,7 +60,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py index bdbecab8..1bbec407 100644 --- a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py +++ b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -57,7 +55,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py index 2063046a..c90b8d02 100644 --- a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py +++ b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -53,7 +51,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py index 136d931e..c888824a 100644 --- a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py +++ b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -58,7 +56,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py index 8c8634d5..25fef87f 100644 --- a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py +++ b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -60,7 +58,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/36_MsgRelayProviderPrices.py b/examples/chain_client/36_MsgRelayProviderPrices.py index 32beb38d..aa681186 100644 --- a/examples/chain_client/36_MsgRelayProviderPrices.py +++ b/examples/chain_client/36_MsgRelayProviderPrices.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -53,7 +51,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/3_MsgCreateSpotLimitOrder.py b/examples/chain_client/3_MsgCreateSpotLimitOrder.py index 733cf308..0b9dafa2 100644 --- a/examples/chain_client/3_MsgCreateSpotLimitOrder.py +++ b/examples/chain_client/3_MsgCreateSpotLimitOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -58,7 +56,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/40_MsgExecuteContract.py b/examples/chain_client/40_MsgExecuteContract.py index 4661f4b4..d3ab1dda 100644 --- a/examples/chain_client/40_MsgExecuteContract.py +++ b/examples/chain_client/40_MsgExecuteContract.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,11 +9,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/41_MsgCreateInsuranceFund.py b/examples/chain_client/41_MsgCreateInsuranceFund.py index 255419b0..1a511f05 100644 --- a/examples/chain_client/41_MsgCreateInsuranceFund.py +++ b/examples/chain_client/41_MsgCreateInsuranceFund.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -10,11 +8,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/42_MsgUnderwrite.py b/examples/chain_client/42_MsgUnderwrite.py index 49aa7313..d7d04fb3 100644 --- a/examples/chain_client/42_MsgUnderwrite.py +++ b/examples/chain_client/42_MsgUnderwrite.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -10,11 +8,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/43_MsgRequestRedemption.py b/examples/chain_client/43_MsgRequestRedemption.py index a37a774d..640a42d2 100644 --- a/examples/chain_client/43_MsgRequestRedemption.py +++ b/examples/chain_client/43_MsgRequestRedemption.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -10,11 +8,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/4_MsgCreateSpotMarketOrder.py b/examples/chain_client/4_MsgCreateSpotMarketOrder.py index a1ef8cea..3d16426b 100644 --- a/examples/chain_client/4_MsgCreateSpotMarketOrder.py +++ b/examples/chain_client/4_MsgCreateSpotMarketOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -57,7 +55,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/5_MsgCancelSpotOrder.py b/examples/chain_client/5_MsgCancelSpotOrder.py index a347a54b..ced2467f 100644 --- a/examples/chain_client/5_MsgCancelSpotOrder.py +++ b/examples/chain_client/5_MsgCancelSpotOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py index e3f47069..4471fb79 100644 --- a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py +++ b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -59,7 +57,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py index 242f519a..10f318f5 100644 --- a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py +++ b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -58,7 +56,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res.result.data, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res.result.data, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/8_MsgCancelDerivativeOrder.py b/examples/chain_client/8_MsgCancelDerivativeOrder.py index 7abbf16a..66afe95d 100644 --- a/examples/chain_client/8_MsgCancelDerivativeOrder.py +++ b/examples/chain_client/8_MsgCancelDerivativeOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 2bb5aa03..25d9f2ce 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -1,5 +1,7 @@ import asyncio import time +from copy import deepcopy + import grpc import aiocron import datetime @@ -7,9 +9,12 @@ from http.cookies import SimpleCookie from typing import Dict, List, Optional, Tuple, Union -from .core.market import Market +from pyinjective.composer import Composer + +from . import constant +from .core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket from .core.token import Token -from .exceptions import NotFoundError, EmptyMsgError +from .exceptions import NotFoundError from .proto.cosmos.base.abci.v1beta1 import abci_pb2 as abci_type @@ -183,8 +188,37 @@ def __init__( self._tokens_and_markets_initialization_lock = asyncio.Lock() self._tokens: Optional[Dict[str, Token]] = None - self._spot_markets: Optional[Dict[str, Market]] = None - self._derivative_markets: Optional[Dict] + 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: + async with self._tokens_and_markets_initialization_lock: + if self._tokens is None: + await self._initialize_tokens_and_markets() + return deepcopy(self._tokens) + + async def all_spot_markets(self) -> Dict[str, SpotMarket]: + if self._spot_markets is None: + async with self._tokens_and_markets_initialization_lock: + if self._spot_markets is None: + await self._initialize_tokens_and_markets() + return deepcopy(self._spot_markets) + + async def all_derivative_markets(self) -> Dict[str, DerivativeMarket]: + if self._derivative_markets is None: + async with self._tokens_and_markets_initialization_lock: + if self._derivative_markets is None: + await self._initialize_tokens_and_markets() + return deepcopy(self._derivative_markets) + + async def all_binary_option_markets(self) -> Dict[str, BinaryOptionMarket]: + if self._binary_option_markets is None: + async with self._tokens_and_markets_initialization_lock: + if self._binary_option_markets is None: + await self._initialize_tokens_and_markets() + return deepcopy(self._binary_option_markets) def get_sequence(self): current_seq = self.sequence @@ -1014,50 +1048,120 @@ async def stream_account_portfolio(self, account_address: str, **kwargs): metadata = await self.load_cookie(type="exchange") return self.stubPortfolio.StreamAccountPortfolio.__call__(req, metadata=metadata) + async def composer(self): + return Composer( + network=self.network.string(), + spot_markets=await self.all_spot_markets(), + derivative_markets=await self.all_derivative_markets(), + binary_option_markets=await self.all_binary_option_markets(), + tokens=await self.all_tokens(), + ) + async def _initialize_tokens_and_markets(self): - markets = dict() + spot_markets = dict() + derivative_markets = dict() + binary_option_markets = dict() tokens = dict() + tokens_by_denom = dict() markets_info = (await self.get_spot_markets()).markets for market_info in markets_info: - base_token = tokens.get(market_info.base_token.symbol) + base_token_symbol, quote_token_symbol = market_info.ticker.split(constant.TICKER_TOKENS_SEPARATOR) + base_token = tokens.get(base_token_symbol, None) if base_token is None: base_token = Token( - name=market_info.base_token.name, - symbol=market_info.base_token.symbol, - decimals=market_info.base_token.decimals, - logo=market_info.base_token.logo, + name=market_info.base_token_meta.name, + symbol=base_token_symbol, + denom=market_info.base_denom, + address=market_info.base_token_meta.address, + decimals=market_info.base_token_meta.decimals, + logo=market_info.base_token_meta.logo, + updated=market_info.base_token_meta.updated_at, ) - tokens[base_token.symbol] = base_token - base_token.add_source( - denom=market_info.base_denom, - symbol=market_info.base_token.symbol, - address=market_info.base_token.address, - decimals=market_info.base_token.decimals, - updated=market_info.base_token.updated_at, + tokens[base_token_symbol] = base_token + tokens_by_denom[base_token.denom] = base_token + + quote_token = tokens.get(quote_token_symbol, None) + if quote_token is None: + quote_token = Token( + name=market_info.quote_token_meta.name, + symbol=quote_token_symbol, + denom=market_info.quote_denom, + address=market_info.quote_token_meta.address, + decimals=market_info.quote_token_meta.decimals, + logo=market_info.quote_token_meta.logo, + updated=market_info.quote_token_meta.updated_at, + ) + tokens[quote_token_symbol] = quote_token + tokens_by_denom[quote_token.denom] = quote_token + + market = SpotMarket( + id=market_info.market_id, + status=market_info.market_status, + ticker=market_info.ticker, + base_token=base_token, + quote_token=quote_token, + maker_fee_rate=Decimal(market_info.maker_fee_rate), + taker_fee_rate=Decimal(market_info.taker_fee_rate), + service_provider_fee=Decimal(market_info.service_provider_fee), + min_price_tick_size=Decimal(market_info.min_price_tick_size), + min_quantity_tick_size=Decimal(market_info.min_quantity_tick_size), ) - quote_token = tokens.get(market_info.base_token.symbol) + spot_markets[market.id] = market + + markets_info = (await self.get_derivative_markets()).markets + for market_info in markets_info: + quote_token_symbol = market_info.quote_token_meta.symbol + + quote_token = tokens.get(quote_token_symbol, None) if quote_token is None: quote_token = Token( - name=market_info.quote_token.name, - symbol=market_info.quote_token.symbol, - decimals=market_info.quote_token.decimals, - logo=market_info.quote_token.logo, + name=market_info.quote_token_meta.name, + symbol=quote_token_symbol, + denom=market_info.quote_denom, + address=market_info.quote_token_meta.address, + decimals=market_info.quote_token_meta.decimals, + logo=market_info.quote_token_meta.logo, + updated=market_info.quote_token_meta.updated_at, ) - quote_token.add_source( - denom=market_info.quote_denom, - symbol=market_info.quote_token.symbol, - address=market_info.quote_token.address, - decimals=market_info.quote_token.decimals, - updated=market_info.quote_token.updated_at, + tokens[quote_token_symbol] = quote_token + tokens_by_denom[quote_token.denom] = quote_token + + market = DerivativeMarket( + id=market_info.market_id, + status=market_info.market_status, + ticker=market_info.ticker, + oracle_base=market_info.oracle_base, + oracle_quote=market_info.oracle_quote, + oracle_type=market_info.oracle_type, + oracle_scale_factor=market_info.oracle_scale_factor, + initial_margin_ratio=Decimal(market_info.initial_margin_ratio), + maintenance_margin_ratio=Decimal(market_info.maintenance_margin_ratio), + quote_token=quote_token, + maker_fee_rate=Decimal(market_info.maker_fee_rate), + taker_fee_rate = Decimal(market_info.taker_fee_rate), + service_provider_fee = Decimal(market_info.service_provider_fee), + min_price_tick_size = Decimal(market_info.min_price_tick_size), + min_quantity_tick_size = Decimal(market_info.min_quantity_tick_size), ) - market = Market( + derivative_markets[market.id] = market + + markets_info = (await self.get_binary_options_markets()).markets + for market_info in markets_info: + quote_token = tokens_by_denom.get(market_info.quote_denom, None) + + market = BinaryOptionMarket( id=market_info.market_id, status=market_info.market_status, ticker=market_info.ticker, - base_token=base_token, + oracle_symbol=market_info.oracle_symbol, + oracle_provider=market_info.oracle_provider, + oracle_type=market_info.oracle_type, + oracle_scale_factor=market_info.oracle_scale_factor, + expiration_timestamp=market_info.expiration_timestamp, + settlement_timestamp=market_info.settlement_timestamp, quote_token=quote_token, maker_fee_rate=Decimal(market_info.maker_fee_rate), taker_fee_rate=Decimal(market_info.taker_fee_rate), @@ -1066,4 +1170,9 @@ async def _initialize_tokens_and_markets(self): min_quantity_tick_size=Decimal(market_info.min_quantity_tick_size), ) - markets[market.id] = market + binary_option_markets[market.id] = market + + self._tokens = tokens + self._spot_markets = spot_markets + self._derivative_markets = derivative_markets + self._binary_option_markets = binary_option_markets diff --git a/pyinjective/client.py b/pyinjective/client.py index 662d9840..10b82329 100644 --- a/pyinjective/client.py +++ b/pyinjective/client.py @@ -6,7 +6,7 @@ from http.cookies import SimpleCookie from typing import List, Optional, Tuple, Union -from .exceptions import NotFoundError, EmptyMsgError +from .exceptions import NotFoundError from .proto.cosmos.base.abci.v1beta1 import abci_pb2 as abci_type diff --git a/pyinjective/composer.py b/pyinjective/composer.py index f3b8a329..4af1eb63 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -1,9 +1,11 @@ +from configparser import ConfigParser +from decimal import Decimal from time import time -import json -import logging -from google.protobuf import any_pb2, message, timestamp_pb2 +from google.protobuf import any_pb2, timestamp_pb2 +from .core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from .core.token import Token from .proto.cosmos.authz.v1beta1 import authz_pb2 as cosmos_authz_pb from .proto.cosmos.authz.v1beta1 import tx_pb2 as cosmos_authz_tx_pb @@ -33,16 +35,47 @@ from .proto.cosmwasm.wasm.v1 import tx_pb2 as wasm_tx_pb -from .constant import Denom -from .utils.utils import * -from typing import List +from .constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS, INJ_DENOM +from typing import Dict, List, Optional -from pyinjective.utils.logger import LoggerProvider +from pyinjective import constant class Composer: - def __init__(self, network: str): + def __init__( + self, + network: str, + spot_markets: Optional[Dict[str, SpotMarket]] = None, + derivative_markets: Optional[Dict[str, DerivativeMarket]] = None, + binary_option_markets: Optional[Dict[str, BinaryOptionMarket]] = None, + tokens: Optional[Dict[str, Token]] = None): + """ Composer is used to create the requests to send to the nodes using the Client + + :param network: the name of the network to use (mainnet, testnet, devnet) + :type network: str + + :param spot_markets: a dictionary containing all spot markets + :type spot_markets: Dictionary + + :param derivative_markets: a dictionary containing all derivative markets + :type derivative_markets: Dictionary + + :param binary_option_markets: a dictionary containing all derivative markets + :type binary_option_markets: Dictionary + + :param tokens: a dictionary with all the possible tokens + :type tokens: Dictionary + + + """ self.network = network + if spot_markets is None or derivative_markets is None or binary_option_markets is None or tokens is None: + self._initialize_markets_and_tokens_from_files() + else: + self.spot_markets = spot_markets + self.derivative_markets = derivative_markets + self.binary_option_markets = binary_option_markets + self.tokens = tokens def Coin(self, amount: int, denom: str): return cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin(amount=str(amount), denom=denom) @@ -92,15 +125,12 @@ def SpotOrder( quantity: float, **kwargs, ): - # load denom metadata - denom = Denom.load_market(self.network, market_id) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded market metadata for: {denom.description}") + market = self.spot_markets[market_id] # prepare values - quantity = spot_quantity_to_backend(quantity, denom) - price = spot_price_to_backend(price, denom) - trigger_price = spot_price_to_backend(0, denom) + quantity = market.quantity_to_chain_format(human_readable_value=Decimal(str(quantity))) + price = market.price_to_chain_format(human_readable_value=Decimal(str(price))) + trigger_price = market.price_to_chain_format(human_readable_value=Decimal(0)) if kwargs.get("is_buy") and not kwargs.get("is_po"): order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY @@ -119,11 +149,11 @@ def SpotOrder( order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=str(price), - quantity=str(quantity), + price=str(int(price)), + quantity=str(int(quantity)), ), order_type=order_type, - trigger_price=str(trigger_price), + trigger_price=str(int(trigger_price)), ) def DerivativeOrder( @@ -136,26 +166,21 @@ def DerivativeOrder( trigger_price: float = 0, **kwargs, ): - # load denom metadata - denom = Denom.load_market(self.network, market_id) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded market metadata for: {denom.description}") - - if kwargs.get("is_reduce_only") is None: - margin = derivative_margin_to_backend( - price, quantity, kwargs.get("leverage"), denom - ) - elif kwargs.get("is_reduce_only", True): + market = self.derivative_markets[market_id] + + if kwargs.get("is_reduce_only", False): margin = 0 else: - margin = derivative_margin_to_backend( - price, quantity, kwargs.get("leverage"), denom + margin = market.calculate_margin_in_chain_format( + human_readable_quantity=Decimal(str(quantity)), + human_readable_price=Decimal(str(price)), + leverage=Decimal(str(kwargs["leverage"])), ) # prepare values - price = derivative_price_to_backend(price, denom) - trigger_price = derivative_price_to_backend(trigger_price, denom) - quantity = derivative_quantity_to_backend(quantity, denom) + quantity = market.quantity_to_chain_format(human_readable_value=Decimal(str(quantity))) + price = market.price_to_chain_format(human_readable_value=Decimal(str(price))) + trigger_price = market.price_to_chain_format(human_readable_value=Decimal(str(trigger_price))) if kwargs.get("is_buy") and not kwargs.get("is_po"): order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY @@ -186,12 +211,12 @@ def DerivativeOrder( order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=str(price), - quantity=str(quantity), + price=str(int(price)), + quantity=str(int(quantity)), ), - margin=str(margin), + margin=str(int(margin)), order_type=order_type, - trigger_price=str(trigger_price), + trigger_price=str(int(trigger_price)), ) def BinaryOptionsOrder( @@ -204,30 +229,23 @@ def BinaryOptionsOrder( **kwargs, ): - if "denom" in kwargs: - denom = kwargs.get("denom") - else: - denom = Denom.load_market(self.network, market_id) - - # load denom metadata - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded market metadata for: {denom.description}") - - if kwargs.get("is_reduce_only") is None and kwargs.get("is_buy"): - margin = binary_options_buy_margin_to_backend(price, quantity, denom) - elif kwargs.get("is_reduce_only") is None and not kwargs.get("is_buy"): - margin = binary_options_sell_margin_to_backend(price, quantity, denom) - elif kwargs.get("is_reduce_only") is False and kwargs.get("is_buy"): - margin = binary_options_buy_margin_to_backend(price, quantity, denom) - elif kwargs.get("is_reduce_only") is False and not kwargs.get("is_buy"): - margin = binary_options_sell_margin_to_backend(price, quantity, denom) - elif kwargs.get("is_reduce_only", True): + market = self.binary_option_markets[market_id] + denom = kwargs.get("denom", None) + + if kwargs.get("is_reduce_only", False): margin = 0 + else: + margin = market.calculate_margin_in_chain_format( + human_readable_quantity=Decimal(str(quantity)), + human_readable_price=Decimal(str(price)), + is_buy=kwargs["is_buy"], + special_denom=denom, + ) # prepare values - price = binary_options_price_to_backend(price, denom) - trigger_price = binary_options_price_to_backend(0, denom) - quantity = binary_options_quantity_to_backend(quantity, denom) + price = market.price_to_chain_format(human_readable_value=Decimal(str(price)), special_denom=denom) + trigger_price = market.price_to_chain_format(human_readable_value=Decimal(str(0)), special_denom=denom) + quantity = market.quantity_to_chain_format(human_readable_value=Decimal(str(quantity)), special_denom=denom) if kwargs.get("is_buy") and not kwargs.get("is_po"): order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY @@ -246,25 +264,22 @@ def BinaryOptionsOrder( order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=str(price), - quantity=str(quantity), + price=str(int(price)), + quantity=str(int(quantity)), ), - margin=str(margin), + margin=str(int(margin)), order_type=order_type, - trigger_price=str(trigger_price), + trigger_price=str(int(trigger_price)), ) def MsgSend(self, from_address: str, to_address: str, amount: float, denom: str): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded send symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return cosmos_bank_tx_pb.MsgSend( from_address=from_address, to_address=to_address, - amount=[self.Coin(amount=be_amount, denom=peggy_denom)], + amount=[self.Coin(amount=int(be_amount), denom=token.denom)], ) def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): @@ -276,16 +291,13 @@ def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): ) def MsgDeposit(self, sender: str, subaccount_id: str, amount: float, denom: str): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded deposit symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return injective_exchange_tx_pb.MsgDeposit( sender=sender, subaccount_id=subaccount_id, - amount=self.Coin(amount=be_amount, denom=peggy_denom), + amount=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgCreateSpotLimitOrder( @@ -608,14 +620,15 @@ def MsgIncreasePositionMargin( market_id: str, amount: float, ): - denom = Denom.load_market(self.network, market_id) - additional_margin = derivative_additional_margin_to_backend(amount, denom) + market = self.derivative_markets[market_id] + + additional_margin = market.margin_to_chain_format(human_readable_value=Decimal(str(amount))) return injective_exchange_tx_pb.MsgIncreasePositionMargin( sender=sender, source_subaccount_id=source_subaccount_id, destination_subaccount_id=destination_subaccount_id, market_id=market_id, - amount=str(additional_margin), + amount=str(int(additional_margin)), ) def MsgSubaccountTransfer( @@ -635,16 +648,13 @@ def MsgSubaccountTransfer( ) def MsgWithdraw(self, sender: str, subaccount_id: str, amount: float, denom: str): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded withdrawal symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return injective_exchange_tx_pb.MsgWithdraw( sender=sender, subaccount_id=subaccount_id, - amount=self.Coin(amount=be_amount, denom=peggy_denom), + amount=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgExternalTransfer( @@ -655,27 +665,24 @@ def MsgExternalTransfer( amount: int, denom: str, ): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded send symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return injective_exchange_tx_pb.MsgExternalTransfer( sender=sender, source_subaccount_id=source_subaccount_id, destination_subaccount_id=destination_subaccount_id, - amount=self.Coin(amount=be_amount, denom=peggy_denom), + amount=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgBid(self, sender: str, bid_amount: float, round: float): - be_amount = amount_to_backend(bid_amount, 18) + be_amount = Decimal(str(bid_amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") return injective_auction_tx_pb.MsgBid( sender=sender, round=round, - bid_amount=self.Coin(amount=be_amount, denom="inj"), + bid_amount=self.Coin(amount=int(be_amount), denom=INJ_DENOM), ) def MsgGrantGeneric( @@ -788,31 +795,27 @@ def MsgRelayPriceFeedPrice( def MsgSendToEth( self, denom: str, sender: str, eth_dest: str, amount: float, bridge_fee: float ): - - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - be_bridge_fee = amount_to_backend(bridge_fee, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded withdrawal symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) + be_bridge_fee = token.chain_formatted_value(human_readable_value=Decimal(str(bridge_fee))) return injective_peggy_tx_pb.MsgSendToEth( sender=sender, eth_dest=eth_dest, - amount=self.Coin(amount=be_amount, denom=peggy_denom), - bridge_fee=self.Coin(amount=be_bridge_fee, denom=peggy_denom), + amount=self.Coin(amount=int(be_amount), denom=token.denom), + bridge_fee=self.Coin(amount=int(be_bridge_fee), denom=token.denom), ) def MsgDelegate( self, delegator_address: str, validator_address: str, amount: float ): - be_amount = amount_to_backend(amount, 18) + be_amount = Decimal(str(amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") return cosmos_staking_tx_pb.MsgDelegate( delegator_address=delegator_address, validator_address=validator_address, - amount=self.Coin(amount=be_amount, denom="inj"), + amount=self.Coin(amount=int(be_amount), denom=INJ_DENOM), ) def MsgCreateInsuranceFund( @@ -826,15 +829,18 @@ def MsgCreateInsuranceFund( expiry: int, initial_deposit: int ): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, quote_denom) - be_amount = amount_to_backend(initial_deposit, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded send symbol {quote_denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[quote_denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(initial_deposit))) return injective_insurance_tx_pb.MsgCreateInsuranceFund( - sender=sender, ticker=ticker, quote_denom=peggy_denom, oracle_base=oracle_base, oracle_quote=oracle_quote, - oracle_type=oracle_type, expiry=expiry, initial_deposit=self.Coin(amount=be_amount, denom=peggy_denom), + sender=sender, + ticker=ticker, + quote_denom=token.denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_type=oracle_type, + expiry=expiry, + initial_deposit=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgUnderwrite( @@ -844,14 +850,11 @@ def MsgUnderwrite( quote_denom: str, amount: int, ): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, quote_denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded send symbol {quote_denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[quote_denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return injective_insurance_tx_pb.MsgUnderwrite( - sender=sender, market_id=market_id, deposit=self.Coin(amount=be_amount, denom=peggy_denom), + sender=sender, market_id=market_id, deposit=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgRequestRedemption( @@ -957,3 +960,85 @@ def UnpackMsgExecResponse(msg_type, data): } return header_map[msg_type].FromString(bytes(data, "utf-8")) + + def _initialize_markets_and_tokens_from_files(self): + config: ConfigParser = constant.CONFIGS[self.network] + spot_markets = dict() + derivative_markets = dict() + tokens = dict() + + for section_name, configuration_section in config.items(): + if section_name.startswith("0x"): + description = configuration_section["description"] + + quote_token = Token( + name="", + symbol="", + denom="", + address="", + decimals=int(configuration_section["quote"]), + logo="", + updated=-1, + ) + + if "Spot" in description: + base_token = Token( + name="", + symbol="", + denom="", + address="", + decimals=int(configuration_section["base"]), + logo="", + updated=-1, + ) + + market = SpotMarket( + id=section_name, + status="", + ticker=description, + base_token=base_token, + quote_token=quote_token, + maker_fee_rate=None, + taker_fee_rate=None, + service_provider_fee=None, + min_price_tick_size=Decimal(str(configuration_section["min_price_tick_size"])), + min_quantity_tick_size=Decimal(str(configuration_section["min_quantity_tick_size"])) + ) + spot_markets[description] = market + else: + market = DerivativeMarket( + id=section_name, + status="", + ticker=description, + oracle_base="", + oracle_quote="", + oracle_type="", + oracle_scale_factor=1, + initial_margin_ratio=None, + maintenance_margin_ratio=None, + quote_token=quote_token, + maker_fee_rate=None, + taker_fee_rate=None, + service_provider_fee=None, + min_price_tick_size=Decimal(str(configuration_section["min_price_tick_size"])), + min_quantity_tick_size=Decimal(str(configuration_section["min_quantity_tick_size"])), + ) + + derivative_markets[description] = market + + elif section_name != "DEFAULT": + token = Token( + name=section_name, + symbol=section_name, + denom=configuration_section["peggy_denom"], + address="", + decimals=int(configuration_section["decimals"]), + logo="", + updated=-1, + ) + + tokens[token.symbol] = Token + + self.tokens = tokens + self.spot_markets = spot_markets + self.derivative_markets = derivative_markets diff --git a/pyinjective/constant.py b/pyinjective/constant.py index 72bbf2ec..0774e4b3 100644 --- a/pyinjective/constant.py +++ b/pyinjective/constant.py @@ -1,9 +1,13 @@ import os from configparser import ConfigParser +from warnings import warn MAX_CLIENT_ID_LENGTH = 128 MAX_DATA_SIZE = 256 MAX_MEMO_CHARACTERS = 256 +ADDITIONAL_CHAIN_FORMAT_DECIMALS = 18 +TICKER_TOKENS_SEPARATOR = "/" +INJ_DENOM = "inj" devnet_config = ConfigParser() devnet_config.read(os.path.join(os.path.dirname(__file__), 'denoms_devnet.ini')) @@ -14,6 +18,13 @@ mainnet_config = ConfigParser() mainnet_config.read(os.path.join(os.path.dirname(__file__), 'denoms_mainnet.ini')) +CONFIGS = { + "devnet": devnet_config, + "testnet": testnet_config, + "mainnet": mainnet_config, +} + + class Denom: def __init__( self, @@ -23,6 +34,9 @@ def __init__( min_price_tick_size: float, min_quantity_tick_size: float ): + """This throws a deprecation warning on initialization.""" + warn(f'{self.__class__.__name__} will be deprecated.', DeprecationWarning, stacklevel=2) + self.description = description self.base = base self.quote = quote diff --git a/pyinjective/core/market.py b/pyinjective/core/market.py index c17ce795..d28ba462 100644 --- a/pyinjective/core/market.py +++ b/pyinjective/core/market.py @@ -1,11 +1,13 @@ from dataclasses import dataclass from decimal import Decimal +from typing import Optional +from constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS, Denom from pyinjective.core.token import Token @dataclass -class Market: +class SpotMarket: id: str status: str ticker: str @@ -15,4 +17,135 @@ class Market: taker_fee_rate: Decimal service_provider_fee: Decimal min_price_tick_size: Decimal - min_quantity_tick_size: Decimal \ No newline at end of file + min_quantity_tick_size: Decimal + + def quantity_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + chain_formatted_value = human_readable_value * Decimal(f"1e{self.base_token.decimals}") + quantized_value = chain_formatted_value // self.min_quantity_tick_size * self.min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def price_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + decimals = self.quote_token.decimals - self.base_token.decimals + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // self.min_price_tick_size) * self.min_price_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + +@dataclass +class DerivativeMarket: + id: str + status: str + ticker: str + oracle_base: str + oracle_quote: str + oracle_type: str + oracle_scale_factor: int + initial_margin_ratio: Decimal + maintenance_margin_ratio: Decimal + quote_token: Token + maker_fee_rate: Decimal + taker_fee_rate: Decimal + service_provider_fee: Decimal + min_price_tick_size: Decimal + min_quantity_tick_size: Decimal + + def quantity_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + # Derivative markets do not have a base market to provide the number of decimals + chain_formatted_value = human_readable_value + quantized_value = chain_formatted_value // self.min_quantity_tick_size * self.min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def price_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + decimals = self.quote_token.decimals + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // self.min_price_tick_size) * self.min_price_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def margin_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + decimals = self.quote_token.decimals + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // self.min_quantity_tick_size) * self.min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def calculate_margin_in_chain_format( + self, + human_readable_quantity: Decimal, + human_readable_price: Decimal, + leverage: Decimal + ) -> Decimal: + chain_formatted_quantity = human_readable_quantity + chain_formatted_price = human_readable_price * Decimal(f"1e{self.quote_token.decimals}") + margin = (chain_formatted_price * chain_formatted_quantity) / leverage + # We are using the min_quantity_tick_size to quantize the margin because that is the way margin is validated + # in the chain (it might be changed to a min_notional in the future) + quantized_margin = (margin // self.min_quantity_tick_size) * self.min_quantity_tick_size + extended_chain_formatted_margin = quantized_margin * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_margin + +@dataclass +class BinaryOptionMarket: + id: str + status: str + ticker: str + oracle_symbol: str + oracle_provider: str + oracle_type: str + oracle_scale_factor: int + expiration_timestamp: int + settlement_timestamp: int + quote_token: Token + maker_fee_rate: Decimal + taker_fee_rate: Decimal + service_provider_fee: Decimal + min_price_tick_size: Decimal + min_quantity_tick_size: Decimal + + def quantity_to_chain_format(self, human_readable_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal: + # Binary option markets do not have a base market to provide the number of decimals + decimals = 0 if special_denom is None else special_denom.base + min_quantity_tick_size = self.min_quantity_tick_size if special_denom is None else special_denom.min_quantity_tick_size + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = chain_formatted_value // min_quantity_tick_size * min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def price_to_chain_format(self, human_readable_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal: + decimals = self.quote_token.decimals if special_denom is None else special_denom.quote + min_price_tick_size = self.min_price_tick_size if special_denom is None else special_denom.min_price_tick_size + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // min_price_tick_size) * min_price_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def calculate_margin_in_chain_format( + self, + human_readable_quantity: Decimal, + human_readable_price: Decimal, + is_buy: bool, + special_denom: Optional[Denom] = None, + ) -> Decimal: + quantity_decimals = 0 if special_denom is None else special_denom.base + price_decimals = self.quote_token.decimals if special_denom is None else special_denom.quote + min_quantity_tick_size = self.min_quantity_tick_size if special_denom is None else special_denom.min_quantity_tick_size + price = human_readable_price if is_buy else 1 - human_readable_price + chain_formatted_quantity = human_readable_quantity * Decimal(f"1e{quantity_decimals}") + chain_formatted_price = price * Decimal(f"1e{price_decimals}") + margin = (chain_formatted_price * chain_formatted_quantity) + # We are using the min_quantity_tick_size to quantize the margin because that is the way margin is validated + # in the chain (it might be changed to a min_notional in the future) + quantized_margin = (margin // min_quantity_tick_size) * min_quantity_tick_size + extended_chain_formatted_margin = quantized_margin * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_margin \ No newline at end of file diff --git a/pyinjective/core/token.py b/pyinjective/core/token.py index c80d8e89..59bac41e 100644 --- a/pyinjective/core/token.py +++ b/pyinjective/core/token.py @@ -1,21 +1,4 @@ -from typing import Dict - - -class TokenSource: - - def __init__( - self, - denom: str, - symbol: str, - address: str, - decimals: int, - updated: int, - ): - self.denom = denom - self.symbol = symbol - self.address = address - self.decimals = decimals - self.updated = updated +from decimal import Decimal class Token: @@ -24,23 +7,19 @@ def __init__( self, name: str, symbol: str, + denom: str, + address: str, decimals: int, logo: str, + updated: int, ): self.name = name self.symbol = symbol + self.denom = denom + self.address = address self.decimals = decimals self.logo = logo + self.updated = updated - self._sources = Dict[str, TokenSource] - - def add_source(self, denom: str, symbol: str, address: str, decimals: int, updated: int): - if denom not in self._sources: - token_source = TokenSource( - denom=denom, - symbol=symbol, - address=address, - decimals=decimals, - updated=updated, - ) - self._sources[denom] = token_source \ No newline at end of file + def chain_formatted_value(self, human_readable_value: Decimal) -> Decimal: + return human_readable_value * Decimal(f"1e{self.decimals}") diff --git a/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py b/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py index ac68f1ce..202fd9e4 100644 --- a/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py +++ b/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py @@ -22,7 +22,7 @@ def __init__(self, channel): response_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsResponse.FromString, ) self.Market = channel.unary_unary( - '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/Market', + '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/SpotMarket', request_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.SerializeToString, response_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.FromString, ) @@ -156,7 +156,7 @@ def Markets(self, request, context): raise NotImplementedError('Method not implemented!') def Market(self, request, context): - """Market gets details of a single derivative market + """SpotMarket gets details of a single derivative market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -184,14 +184,14 @@ def BinaryOptionsMarket(self, request, context): raise NotImplementedError('Method not implemented!') def Orderbook(self, request, context): - """Orderbook gets the Orderbook of a Derivative Market + """Orderbook gets the Orderbook of a Derivative SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def OrderbookV2(self, request, context): - """Orderbook gets the Orderbook of a Derivative Market + """Orderbook gets the Orderbook of a Derivative SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -233,7 +233,7 @@ def StreamOrderbookUpdate(self, request, context): raise NotImplementedError('Method not implemented!') def Orders(self, request, context): - """DerivativeLimitOrders gets the limit orders of a derivative Market. + """DerivativeLimitOrders gets the limit orders of a derivative SpotMarket. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -275,21 +275,21 @@ def StreamPositions(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrders(self, request, context): - """StreamOrders streams updates to individual orders of a Derivative Market. + """StreamOrders streams updates to individual orders of a Derivative SpotMarket. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Trades(self, request, context): - """Trades gets the trades of a Derivative Market. + """Trades gets the trades of a Derivative SpotMarket. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamTrades(self, request, context): - """StreamTrades streams newly executed trades from Derivative Market. + """StreamTrades streams newly executed trades from Derivative SpotMarket. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -318,7 +318,7 @@ def OrdersHistory(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrdersHistory(self, request, context): - """Stream updates to historical orders of a derivative Market + """Stream updates to historical orders of a derivative SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -332,8 +332,8 @@ def add_InjectiveDerivativeExchangeRPCServicer_to_server(servicer, server): request_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsRequest.FromString, response_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsResponse.SerializeToString, ), - 'Market': grpc.unary_unary_rpc_method_handler( - servicer.Market, + 'SpotMarket': grpc.unary_unary_rpc_method_handler( + servicer.SpotMarket, request_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.FromString, response_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.SerializeToString, ), @@ -492,7 +492,7 @@ def Market(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/Market', + return grpc.experimental.unary_unary(request, target, '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/SpotMarket', exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.SerializeToString, exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.FromString, options, channel_credentials, diff --git a/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py b/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py index 2ba568f1..5ca50005 100644 --- a/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py +++ b/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py @@ -21,7 +21,7 @@ def __init__(self, channel): response_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsResponse.FromString, ) self.Market = channel.unary_unary( - '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/Market', + '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/SpotMarket', request_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.SerializeToString, response_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.FromString, ) @@ -133,14 +133,14 @@ def StreamMarkets(self, request, context): raise NotImplementedError('Method not implemented!') def Orderbook(self, request, context): - """Orderbook of a Spot Market + """Orderbook of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def OrderbookV2(self, request, context): - """Orderbook of a Spot Market + """Orderbook of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -182,28 +182,28 @@ def StreamOrderbookUpdate(self, request, context): raise NotImplementedError('Method not implemented!') def Orders(self, request, context): - """Orders of a Spot Market + """Orders of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamOrders(self, request, context): - """Stream updates to individual orders of a Spot Market + """Stream updates to individual orders of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Trades(self, request, context): - """Trades of a Spot Market + """Trades of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamTrades(self, request, context): - """Stream newly executed trades from Spot Market + """Stream newly executed trades from Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -231,7 +231,7 @@ def OrdersHistory(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrdersHistory(self, request, context): - """Stream updates to historical orders of a spot Market + """Stream updates to historical orders of a spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -245,8 +245,8 @@ def add_InjectiveSpotExchangeRPCServicer_to_server(servicer, server): request_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsRequest.FromString, response_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsResponse.SerializeToString, ), - 'Market': grpc.unary_unary_rpc_method_handler( - servicer.Market, + 'SpotMarket': grpc.unary_unary_rpc_method_handler( + servicer.SpotMarket, request_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.FromString, response_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.SerializeToString, ), @@ -369,7 +369,7 @@ def Market(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/Market', + return grpc.experimental.unary_unary(request, target, '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/SpotMarket', exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.SerializeToString, exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.FromString, options, channel_credentials, diff --git a/pyinjective/utils/utils.py b/pyinjective/utils/utils.py deleted file mode 100644 index 61a02472..00000000 --- a/pyinjective/utils/utils.py +++ /dev/null @@ -1,108 +0,0 @@ -from decimal import Decimal -from math import floor -from typing import Union - -""" -One thing you may need to pay more attention to is how to deal with decimals on the Injective Exchange. -Different cryptocurrencies may require different decimal precisions. More specifically, ERC-20 tokens(e.g. INJ) have 18 decimals whereas USDT/USC have 6 decimals. -So in our system that means ** having 1 INJ is 1e18 inj ** and that ** 1 USDT is actually 100000 peggy0xdac17f958d2ee523a2206206994597c13d831ec7**. - -For spot markets, a price reflects the ** relative exchange rate ** between two tokens. -If the tokens have the same decimal scale, that's great since the prices become interpretable e.g. USDT/USDC (both have 6 decimals e.g. for USDT https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#readContract) -or MATIC/INJ (both have 18 decimals) since the decimals cancel out. -Prices however start to look wonky once you have exchanges between two tokens of different decimals, which unfortunately is most pairs with USDT or USDC denominations e.g. INJ/USDT. -As such, I've created some simple utility functions by keeping a hardcoded dictionary in injective-py and you can also achieve such utilities by yourself -(e.g. you can use external API like Alchemy's getTokenMetadata to fetch decimal of base and quote asset). - -So for INJ/USDT of 6.9, the price you end up getting is 6.9*10 ^ (6 - 18) = 6.9e-12. Note that this market also happens to have a MinPriceTickSize of 1e-15. -This makes sense since since it's defining th3e minimum price increment of the relative exchange of INJ to USDT. - -Note that this market also happens to have a MinQuantityTickSize of 1e15. -This also makes sense since it refers to the minimum INJ quantity tick size each order must have, which is 1e15/1e18 = 0.001 INJ. - -""" - -def spot_price_to_backend(price, denom) -> int: - price_tick_size = denom.min_price_tick_size - scale_price = Decimal(18 + denom.quote - denom.base) - exchange_price = floor_to(price, price_tick_size) * pow(Decimal(10), scale_price) - return int(exchange_price) - -def spot_quantity_to_backend(quantity, denom) -> int: - quantity_tick_size = float(denom.min_quantity_tick_size) / pow(10, denom.base) - scale_quantity = Decimal(18 + denom.base) - exchange_quantity = floor_to(quantity, quantity_tick_size) * pow(Decimal(10), scale_quantity) - return int(exchange_quantity) - -def derivative_price_to_backend(price, denom) -> int: - price_tick_size = Decimal(denom.min_price_tick_size) / pow(10, denom.quote) - exchange_price = floor_to(price, float(price_tick_size)) * pow(10, 18 + denom.quote) - return int(exchange_price) - -def binary_options_price_to_backend(price, denom) -> int: - price_tick_size = Decimal(denom.min_price_tick_size) / pow(10, denom.quote) - exchange_price = floor_to(price, float(price_tick_size)) * pow(10, 18 + denom.quote) - return int(exchange_price) - -def derivative_quantity_to_backend(quantity, denom) -> int: - quantity_tick_size = float(denom.min_quantity_tick_size) / pow(10, denom.base) - scale_quantity = Decimal(18 + denom.base) - exchange_quantity = floor_to(quantity, quantity_tick_size) * pow(Decimal(10), scale_quantity) - return int(exchange_quantity) - -def binary_options_quantity_to_backend(quantity, denom) -> int: - quantity_tick_size = float(denom.min_quantity_tick_size) / pow(10, denom.base) - scale_quantity = Decimal(18 + denom.base) - exchange_quantity = floor_to(quantity, quantity_tick_size) * pow(Decimal(10), scale_quantity) - return int(exchange_quantity) - -def derivative_margin_to_backend(price, quantity, leverage, denom) -> int: - chain_format_price = Decimal(str(price)) * Decimal(f"1e{denom.quote}") - chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{denom.base}") - decimal_leverage = Decimal(str(leverage)) - margin = (chain_format_price * chain_format_quantity) / decimal_leverage - # We are using the min_quantity_tick_size to quantize the margin because that is the way margin is validated - # in the chain (it might be changed to a min_notional in the future) - exchange_margin = floor_to(margin, denom.min_quantity_tick_size) * Decimal(f"1e18") - return int(exchange_margin) - -def binary_options_buy_margin_to_backend(price, quantity, denom) -> int: - price_tick_size = Decimal(denom.min_price_tick_size) / pow(10, denom.quote) - margin = Decimal(str(price)) * Decimal(str(quantity)) - exchange_margin = floor_to(margin, float(price_tick_size)) * pow(10, 18 + denom.quote) - return int(exchange_margin) - -def binary_options_sell_margin_to_backend(price, quantity, denom) -> int: - price_tick_size = Decimal(denom.min_price_tick_size) / pow(10, denom.quote) - margin = (1 - (Decimal(str(price)))) * (Decimal(str(quantity))) - exchange_margin = floor_to(margin, float(price_tick_size)) * pow(10, 18 + denom.quote) - return int(exchange_margin) - -def derivative_additional_margin_to_backend(amount, denom) -> int: - price_tick_size = float(denom.min_price_tick_size) / pow(10, denom.quote) - additional_margin = floor_to(amount, price_tick_size) * pow(10, 18 + denom.quote) - return int(additional_margin) - -def amount_to_backend(amount, decimals) -> int: - be_amount = amount * pow(10, decimals) - return int(be_amount) - -def floor_to(value: Union[float, Decimal], target: Union[float, Decimal]) -> Decimal: - value_tmp = Decimal(str(value)) - target_tmp = Decimal(str(target)) - result = int(floor(value_tmp / target_tmp)) * target_tmp - return result - -def spot_price_from_backend(price, denom) -> float: - scale = float(denom.quote - denom.base) - return float(price) / pow(10, scale) - -def spot_quantity_from_backend(quantity, denom) -> Decimal: - scale = float(denom.base) - quantity_tick_size = float(denom.min_quantity_tick_size) / pow(10, scale) - quantity = float(quantity) / pow(10, scale) - return floor_to(quantity, quantity_tick_size) - -def derivative_price_from_backend(price, denom) -> float: - scale = float(denom.quote) - return float(price) / pow(10, scale) diff --git a/setup.py b/setup.py index af998e2a..52777c1c 100755 --- a/setup.py +++ b/setup.py @@ -40,7 +40,6 @@ DEV_REQUIRED = [ "pytest", "pytest-asyncio", - "pytest-grpc", ] # The rest you shouldn't have to touch too much :) diff --git a/tests/composer_tests.py b/tests/composer_tests.py deleted file mode 100644 index eabef128..00000000 --- a/tests/composer_tests.py +++ /dev/null @@ -1,183 +0,0 @@ -import logging - -import pytest - -from pyinjective.composer import Composer -from pyinjective.constant import Denom, Network - - -class TestComposer: - - @pytest.fixture - def inj_usdt_market_id(self): - return "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0" - - def test_spot_order_creation_logs_market_data_loaded_info(self, caplog, inj_usdt_market_id): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.SpotOrder( - market_id=inj_usdt_market_id, - subaccount_id="", - fee_recipient="", - price=1.0, - quantity=1.0, - ) - - expected_log_message_prefix = "Loaded market metadata for: 'Devnet Spot INJ/USDT'" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_derivative_order_creation_logs_market_data_loaded_info(self, caplog, inj_usdt_market_id): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.DerivativeOrder( - market_id=inj_usdt_market_id, - subaccount_id="", - fee_recipient="", - price=1.0, - quantity=1.0, - leverage=1.0, - ) - - expected_log_message_prefix = "Loaded market metadata for: 'Devnet Spot INJ/USDT'" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_binary_order_creation_logs_market_data_loaded_info(self, caplog, inj_usdt_market_id): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.BinaryOptionsOrder( - market_id=inj_usdt_market_id, - subaccount_id="", - fee_recipient="", - price=1.0, - quantity=1.0, - ) - - expected_log_message_prefix = "Loaded market metadata for: 'Devnet Spot INJ/USDT'" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_send_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgSend( - from_address="", - to_address="", - amount=1.0, - denom="INJ", - ) - - expected_log_message_prefix = f"Loaded send symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_deposit_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgDeposit( - sender="", - subaccount_id="", - amount=1.0, - denom="INJ", - ) - - expected_log_message_prefix = f"Loaded deposit symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_withdraw_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgWithdraw( - sender="", - subaccount_id="", - amount=1.0, - denom="INJ", - ) - - expected_log_message_prefix = f"Loaded withdrawal symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_external_transfer_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgExternalTransfer( - sender="", - source_subaccount_id="", - destination_subaccount_id="", - amount=1.0, - denom="INJ", - ) - - expected_log_message_prefix = f"Loaded send symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_send_to_eth_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgSendToEth( - denom="INJ", - sender="", - eth_dest="", - amount=1.0, - bridge_fee=1.0, - ) - - expected_log_message_prefix = f"Loaded withdrawal symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_create_insurance_fund_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgCreateInsuranceFund( - sender="", - ticker="", - quote_denom="INJ", - oracle_base="", - oracle_quote="", - oracle_type=1, - expiry=1, - initial_deposit=1, - ) - - expected_log_message_prefix = f"Loaded send symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_underwrite_logs_market_data_loaded_info(self, caplog, inj_usdt_market_id): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgUnderwrite( - sender="", - market_id=inj_usdt_market_id, - quote_denom="INJ", - amount=1, - ) - - expected_log_message_prefix = f"Loaded send symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) diff --git a/tests/__init__.py b/tests/core/__init__.py similarity index 100% rename from tests/__init__.py rename to tests/core/__init__.py diff --git a/tests/core/test_market.py b/tests/core/test_market.py new file mode 100644 index 00000000..1038c51b --- /dev/null +++ b/tests/core/test_market.py @@ -0,0 +1,213 @@ +import pytest +from decimal import Decimal + +from pyinjective.constant import Denom + +from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from tests.model_fixtures.markets_fixtures import ( + first_match_bet_market, + inj_token, + usdt_token, + usdt_perp_token, + inj_usdt_spot_market, + btc_usdt_perp_market, +) + + +class TestSpotMarket: + + def test_convert_quantity_to_chain_format(self, inj_usdt_spot_market: SpotMarket): + original_quantity = Decimal("123.456789") + + chain_value = inj_usdt_spot_market.quantity_to_chain_format(human_readable_value=original_quantity) + expected_value = original_quantity * Decimal(f"1e{inj_usdt_spot_market.base_token.decimals}") + quantized_value = ((expected_value // inj_usdt_spot_market.min_quantity_tick_size) + * inj_usdt_spot_market.min_quantity_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_price_to_chain_format(self, inj_usdt_spot_market: SpotMarket): + original_quantity = Decimal("123.456789") + + chain_value = inj_usdt_spot_market.price_to_chain_format(human_readable_value=original_quantity) + price_decimals = inj_usdt_spot_market.quote_token.decimals - inj_usdt_spot_market.base_token.decimals + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ((expected_value // inj_usdt_spot_market.min_price_tick_size) + * inj_usdt_spot_market.min_price_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + +class TestDerivativeMarket: + + def test_convert_quantity_to_chain_format(self, btc_usdt_perp_market: DerivativeMarket): + original_quantity = Decimal("123.456789") + + chain_value = btc_usdt_perp_market.quantity_to_chain_format(human_readable_value=original_quantity) + quantized_value = ((original_quantity // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_price_to_chain_format(self, btc_usdt_perp_market: DerivativeMarket): + original_quantity = Decimal("123.456789") + + chain_value = btc_usdt_perp_market.price_to_chain_format(human_readable_value=original_quantity) + price_decimals = btc_usdt_perp_market.quote_token.decimals + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ((expected_value // btc_usdt_perp_market.min_price_tick_size) + * btc_usdt_perp_market.min_price_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_margin_to_chain_format(self, btc_usdt_perp_market: DerivativeMarket): + original_quantity = Decimal("123.456789") + + chain_value = btc_usdt_perp_market.margin_to_chain_format(human_readable_value=original_quantity) + margin_decimals = btc_usdt_perp_market.quote_token.decimals + expected_value = original_quantity * Decimal(f"1e{margin_decimals}") + quantized_value = ((expected_value // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + +class TestBinaryOptionMarket: + + def test_convert_quantity_to_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=4, + min_quantity_tick_size=100, + min_price_tick_size=10000, + ) + + chain_value = first_match_bet_market.quantity_to_chain_format( + human_readable_value=original_quantity, + special_denom=fixed_denom + ) + chain_formatted_quantity = original_quantity * Decimal(f"1e{fixed_denom.base}") + quantized_value = ((chain_formatted_quantity // Decimal(str(fixed_denom.min_quantity_tick_size))) + * Decimal(str(fixed_denom.min_quantity_tick_size))) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_quantity_to_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + + chain_value = first_match_bet_market.quantity_to_chain_format( + human_readable_value=original_quantity, + ) + quantized_value = ((original_quantity // first_match_bet_market.min_quantity_tick_size) + * first_match_bet_market.min_quantity_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_price_to_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=4, + min_quantity_tick_size=100, + min_price_tick_size=10000, + ) + + chain_value = first_match_bet_market.price_to_chain_format( + human_readable_value=original_quantity, + special_denom=fixed_denom, + ) + price_decimals = fixed_denom.quote + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ((expected_value // Decimal(str(fixed_denom.min_price_tick_size))) + * Decimal(str(fixed_denom.min_price_tick_size))) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_price_to_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + + chain_value = first_match_bet_market.price_to_chain_format(human_readable_value=original_quantity) + price_decimals = first_match_bet_market.quote_token.decimals + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ((expected_value // first_match_bet_market.min_price_tick_size) + * first_match_bet_market.min_price_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_calculate_margin_for_buy_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + original_price = Decimal("0.6789") + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=4, + min_quantity_tick_size=100, + min_price_tick_size=10000, + ) + + chain_value = first_match_bet_market.calculate_margin_in_chain_format( + human_readable_quantity=original_quantity, + human_readable_price=original_price, + is_buy=True, + special_denom=fixed_denom, + ) + + quantity_decimals = fixed_denom.base + price_decimals = fixed_denom.quote + expected_quantity = original_quantity * Decimal(f"1e{quantity_decimals}") + expected_price = original_price * Decimal(f"1e{price_decimals}") + expected_margin = expected_quantity * expected_price + quantized_margin = ((expected_margin // Decimal(str(fixed_denom.min_quantity_tick_size))) + * Decimal(str(fixed_denom.min_quantity_tick_size))) + quantized_chain_format_margin = quantized_margin * Decimal(f"1e18") + + assert (quantized_chain_format_margin == chain_value) + + def test_calculate_margin_for_buy_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + original_price = Decimal("0.6789") + + chain_value = first_match_bet_market.calculate_margin_in_chain_format( + human_readable_quantity=original_quantity, + human_readable_price=original_price, + is_buy=True, + ) + + price_decimals = first_match_bet_market.quote_token.decimals + expected_price = original_price * Decimal(f"1e{price_decimals}") + expected_margin = original_quantity * expected_price + quantized_margin = ((expected_margin // Decimal(str(first_match_bet_market.min_quantity_tick_size))) + * Decimal(str(first_match_bet_market.min_quantity_tick_size))) + quantized_chain_format_margin = quantized_margin * Decimal(f"1e18") + + assert (quantized_chain_format_margin == chain_value) + + def test_calculate_margin_for_sell_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + original_price = Decimal("0.6789") + + chain_value = first_match_bet_market.calculate_margin_in_chain_format( + human_readable_quantity=original_quantity, + human_readable_price=original_price, + is_buy=False, + ) + + price_decimals = first_match_bet_market.quote_token.decimals + expected_price = (Decimal(1) - original_price) * Decimal(f"1e{price_decimals}") + expected_margin = original_quantity * expected_price + quantized_margin = ((expected_margin // Decimal(str(first_match_bet_market.min_quantity_tick_size))) + * Decimal(str(first_match_bet_market.min_quantity_tick_size))) + quantized_chain_format_margin = quantized_margin * Decimal(f"1e18") + + assert (quantized_chain_format_margin == chain_value) diff --git a/tests/core/test_token.py b/tests/core/test_token.py new file mode 100644 index 00000000..66cb6cd7 --- /dev/null +++ b/tests/core/test_token.py @@ -0,0 +1,15 @@ +import pytest +from decimal import Decimal + +from tests.model_fixtures.markets_fixtures import inj_token + + +class TestToken: + + def test_chain_formatted_value(self, inj_token): + value = Decimal("1.3456") + + chain_formatted_value = inj_token.chain_formatted_value(human_readable_value=value) + expected_value = value * Decimal(f"1e{inj_token.decimals}") + + assert (chain_formatted_value == expected_value) diff --git a/tests/model_fixtures/__init__.py b/tests/model_fixtures/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/model_fixtures/markets_fixtures.py b/tests/model_fixtures/markets_fixtures.py new file mode 100644 index 00000000..cca40680 --- /dev/null +++ b/tests/model_fixtures/markets_fixtures.py @@ -0,0 +1,113 @@ +import pytest +from decimal import Decimal + +from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from pyinjective.core.token import Token + + +@pytest.fixture +def inj_token(): + token = Token( + name="Injective Protocol", + symbol="INJ", + denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", + address="0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30", + decimals=18, + logo="https://static.alchemyapi.io/images/assets/7226.png", + updated=1681739137644, + ) + + return token + + +@pytest.fixture +def usdt_token(): + token = Token( + name="USDT", + symbol="USDT", + denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + address="0x0000000000000000000000000000000000000000", + decimals=6, + logo="https://static.alchemyapi.io/images/assets/825.png", + updated=1681739137645, + ) + + return token + + +@pytest.fixture +def usdt_perp_token(): + token = Token( + name="USDT PERP", + symbol="USDT", + denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7", + address="0xdAC17F958D2ee523a2206206994597C13D831ec7", + decimals=6, + logo="https://static.alchemyapi.io/images/assets/825.png", + updated=1681739137645, + ) + + return token + + +@pytest.fixture +def inj_usdt_spot_market(inj_token, usdt_token): + market = SpotMarket( + id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", + status="active", + ticker="INJ/USDT", + base_token=inj_token, + quote_token=usdt_token, + maker_fee_rate=Decimal("-0.0001"), + taker_fee_rate=Decimal("0.001"), + service_provider_fee=Decimal("0.4"), + min_price_tick_size=Decimal("0.000000000000001"), + min_quantity_tick_size=Decimal("1000000000000000"), + ) + + return market + + +@pytest.fixture +def btc_usdt_perp_market(usdt_perp_token): + market = DerivativeMarket( + id="0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce", + status="active", + ticker="BTC/USDT PERP", + oracle_base="BTC", + oracle_quote=usdt_perp_token.symbol, + oracle_type="bandibc", + oracle_scale_factor=6, + initial_margin_ratio=Decimal("0.095"), + maintenance_margin_ratio=Decimal("0.025"), + quote_token=usdt_perp_token, + maker_fee_rate=Decimal("-0.0001"), + taker_fee_rate=Decimal("0.001"), + service_provider_fee=Decimal("0.4"), + min_price_tick_size=Decimal("1000000"), + min_quantity_tick_size=Decimal("0.0001"), + ) + + return market + +@pytest.fixture +def first_match_bet_market(usdt_token): + market = BinaryOptionMarket( + id="0x230dcce315364ff6360097838701b14713e2f4007d704df20ed3d81d09eec957", + status="active", + ticker="5fdbe0b1-1707800399-WAS", + oracle_symbol="Frontrunner", + oracle_provider="Frontrunner", + oracle_type="provider", + oracle_scale_factor=6, + expiration_timestamp=1707800399, + settlement_timestamp=1707843599, + quote_token=usdt_token, + maker_fee_rate=Decimal("0"), + taker_fee_rate=Decimal("0"), + service_provider_fee=Decimal("0.4"), + min_price_tick_size=Decimal("10000"), + min_quantity_tick_size=Decimal("1"), + ) + + return market diff --git a/tests/rpc_fixtures/configurable_servicers.py b/tests/rpc_fixtures/configurable_servicers.py index dff625cf..136491ce 100644 --- a/tests/rpc_fixtures/configurable_servicers.py +++ b/tests/rpc_fixtures/configurable_servicers.py @@ -1,8 +1,11 @@ from collections import deque -from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import ( - MarketsRequest, - MarketsResponse, +import pytest +from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2_grpc import InjectiveDerivativeExchangeRPCServicer + +from pyinjective.proto.exchange import ( + injective_spot_exchange_rpc_pb2, + injective_derivative_exchange_rpc_pb2, ) from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import InjectiveSpotExchangeRPCServicer @@ -13,6 +16,23 @@ def __init__(self): super().__init__() self.markets_queue = deque() - def Markets(self, request: MarketsRequest, context): + async def Markets(self, request: injective_spot_exchange_rpc_pb2.MarketsRequest, context=None): + return self.markets_queue.pop() + + +class ConfigurableInjectiveDerivativeExchangeRPCServicer(InjectiveDerivativeExchangeRPCServicer): + + def __init__(self): + super().__init__() + self.markets_queue = deque() + self.binary_option_markets_queue = deque() + + async def Markets(self, request: injective_derivative_exchange_rpc_pb2.MarketsRequest, context=None): return self.markets_queue.pop() + async def BinaryOptionsMarkets( + self, + request: injective_derivative_exchange_rpc_pb2.BinaryOptionsMarketsRequest, + context=None + ): + return self.binary_option_markets_queue.pop() diff --git a/tests/rpc_fixtures/markets_fixtures.py b/tests/rpc_fixtures/markets_fixtures.py index c21cd755..2145e7ba 100644 --- a/tests/rpc_fixtures/markets_fixtures.py +++ b/tests/rpc_fixtures/markets_fixtures.py @@ -46,12 +46,29 @@ def usdt_token_meta(): return token + +@pytest.fixture +def usdt_perp_token_meta(): + from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2 import TokenMeta + + token = TokenMeta( + name="Tether", + address="0xdAC17F958D2ee523a2206206994597C13D831ec7", + symbol="USDTPerp", + logo="https://static.alchemyapi.io/images/assets/825.png", + decimals=6, + updated_at=1683929869866 + ) + + return token + + @pytest.fixture def ape_usdt_spot_market(ape_token_meta, usdt_token_meta): from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo - market_request = SpotMarketInfo( - market_id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", + market = SpotMarketInfo( + market_id="0x8b67e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e000", market_status="active", ticker="APE/USDT", base_denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", @@ -65,13 +82,13 @@ def ape_usdt_spot_market(ape_token_meta, usdt_token_meta): min_quantity_tick_size="1000000000000000", ) - return market_request + return market @pytest.fixture def inj_usdt_spot_market(inj_token_meta, usdt_token_meta): from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo - market_request = SpotMarketInfo( + market = SpotMarketInfo( market_id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", market_status="active", ticker="INJ/USDT", @@ -86,4 +103,72 @@ def inj_usdt_spot_market(inj_token_meta, usdt_token_meta): min_quantity_tick_size="1000000000000000", ) - return market_request + return market + +@pytest.fixture +def btc_usdt_perp_market(usdt_perp_token_meta): + from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2 import ( + DerivativeMarketInfo, + PerpetualMarketInfo, + PerpetualMarketFunding, + ) + + perpetual_market_info = PerpetualMarketInfo( + hourly_funding_rate_cap="0.0000625", + hourly_interest_rate="0.00000416666", + next_funding_timestamp=1684764000, + funding_interval=3600, + ) + perpetual_market_funding = PerpetualMarketFunding( + cumulative_funding="6880500093.266083891331674194", + cumulative_price="-0.952642601240470199", + last_timestamp=1684763442, + ) + + market = DerivativeMarketInfo( + market_id="0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce", + market_status="active", + ticker="BTC/USDT PERP", + oracle_base="BTC", + oracle_quote="USDT", + oracle_type="bandibc", + oracle_scale_factor=6, + initial_margin_ratio="0.095", + maintenance_margin_ratio="0.025", + quote_denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7", + quote_token_meta=usdt_perp_token_meta, + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + service_provider_fee="0.4", + is_perpetual=True, + min_price_tick_size="1000000", + min_quantity_tick_size="0.0001", + perpetual_market_info=perpetual_market_info, + perpetual_market_funding=perpetual_market_funding, + ) + + return market + +@pytest.fixture +def first_match_bet_market(inj_usdt_spot_market): + from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2 import BinaryOptionsMarketInfo + + market = BinaryOptionsMarketInfo( + market_id="0x230dcce315364ff6360097838701b14713e2f4007d704df20ed3d81d09eec957", + market_status="active", + ticker="5fdbe0b1-1707800399-WAS", + oracle_symbol="Frontrunner", + oracle_provider="Frontrunner", + oracle_type="provider", + oracle_scale_factor=6, + expiration_timestamp=1707800399, + settlement_timestamp=1707843599, + quote_denom=inj_usdt_spot_market.quote_denom, + maker_fee_rate="0", + taker_fee_rate="0", + service_provider_fee="0.4", + min_price_tick_size="10000", + min_quantity_tick_size="1", + ) + + return market \ No newline at end of file diff --git a/tests/async_client_tests.py b/tests/test_async_client.py similarity index 55% rename from tests/async_client_tests.py rename to tests/test_async_client.py index 3c2995ba..97532a43 100644 --- a/tests/async_client_tests.py +++ b/tests/test_async_client.py @@ -4,33 +4,33 @@ from pyinjective.constant import Network from pyinjective.async_client import AsyncClient -from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import ( - MarketRequest, - MarketsRequest, - MarketResponse, - MarketsResponse, +from pyinjective.proto.exchange import ( + injective_spot_exchange_rpc_pb2, + injective_derivative_exchange_rpc_pb2, ) -from tests.rpc_fixtures.markets_fixtures import inj_token_meta, ape_token_meta, usdt_token_meta, inj_usdt_spot_market, ape_usdt_spot_market - -@pytest.fixture(scope='module') -def grpc_add_to_server(): - from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import add_InjectiveSpotExchangeRPCServicer_to_server - - return add_InjectiveSpotExchangeRPCServicer_to_server - +from tests.rpc_fixtures.markets_fixtures import ( + inj_token_meta, + ape_token_meta, + usdt_token_meta, + usdt_perp_token_meta, + inj_usdt_spot_market, + ape_usdt_spot_market, + btc_usdt_perp_market, + first_match_bet_market, +) +from tests.rpc_fixtures.configurable_servicers import ConfigurableInjectiveDerivativeExchangeRPCServicer, \ + ConfigurableInjectiveSpotExchangeRPCServicer -@pytest.fixture(scope='module') -def grpc_servicer(): - from tests.rpc_fixtures.configurable_servicers import ConfigurableInjectiveSpotExchangeRPCServicer +@pytest.fixture +def spot_servicer(): return ConfigurableInjectiveSpotExchangeRPCServicer() -@pytest.fixture(scope='module') -def grpc_stub_cls(grpc_channel): - from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import InjectiveSpotExchangeRPCStub +@pytest.fixture +def derivative_servicer(): + return ConfigurableInjectiveDerivativeExchangeRPCServicer() - return InjectiveSpotExchangeRPCStub class TestAsyncClient: @@ -112,29 +112,53 @@ async def test_get_account_logs_exception(self, caplog): @pytest.mark.asyncio async def test_initialize_tokens_and_markets( self, - grpc_stub, - grpc_servicer, + spot_servicer, + derivative_servicer, inj_usdt_spot_market, - ape_usdt_spot_market + ape_usdt_spot_market, + btc_usdt_perp_market, + first_match_bet_market, ): - grpc_servicer.markets_queue.append(MarketsResponse( + spot_servicer.markets_queue.append(injective_spot_exchange_rpc_pb2.MarketsResponse( markets=[inj_usdt_spot_market, ape_usdt_spot_market] )) + derivative_servicer.markets_queue.append(injective_derivative_exchange_rpc_pb2.MarketsResponse( + markets=[btc_usdt_perp_market] + )) + derivative_servicer.binary_option_markets_queue.append( + injective_derivative_exchange_rpc_pb2.BinaryOptionsMarketsResponse( + markets=[first_match_bet_market] + )) client = AsyncClient( network=Network.local(), insecure=False, ) - client.stubSpotExchange = grpc_stub + client.stubSpotExchange = spot_servicer + client.stubDerivativeExchange = derivative_servicer await client._initialize_tokens_and_markets() - assert(3 == len(client.tokens)) - assert(any((inj_usdt_spot_market.base_token_meta.symbol == token.symbol for token in client.tokens))) - assert (any((inj_usdt_spot_market.quote_token_meta.symbol == token.symbol for token in client.tokens))) - assert (any((ape_usdt_spot_market.base_token_meta.symbol == token.symbol for token in client.tokens))) - - assert (2 == len(client.markets)) - assert (any((inj_usdt_spot_market.market_id == market.id for market in client.markets))) - assert (any((ape_usdt_spot_market.market_id == market.id for market in client.markets))) + all_tokens = await client.all_tokens() + assert(4 == len(all_tokens)) + inj_symbol, usdt_symbol = inj_usdt_spot_market.ticker.split("/") + ape_symbol, _ = ape_usdt_spot_market.ticker.split("/") + usdt_perp_symbol = btc_usdt_perp_market.quote_token_meta.symbol + assert(any((inj_symbol == token.symbol for _, token in all_tokens.items()))) + assert (any((usdt_symbol == token.symbol for _, token in all_tokens.items()))) + assert (any((ape_symbol == token.symbol for _, token in all_tokens.items()))) + assert (any((usdt_perp_symbol == token.symbol for _, token in all_tokens.items()))) + + all_spot_markets = await client.all_spot_markets() + assert (2 == len(all_spot_markets)) + assert (any((inj_usdt_spot_market.market_id == market.id for market in all_spot_markets.values()))) + assert (any((ape_usdt_spot_market.market_id == market.id for market in all_spot_markets.values()))) + + all_derivative_markets = await client.all_derivative_markets() + assert (1 == len(all_derivative_markets)) + assert (any((btc_usdt_perp_market.market_id == market.id for market in all_derivative_markets.values()))) + + all_binary_option_markets = await client.all_binary_option_markets() + assert (1 == len(all_binary_option_markets)) + assert (any((first_match_bet_market.market_id == market.id for market in all_binary_option_markets.values()))) diff --git a/tests/test_composer.py b/tests/test_composer.py new file mode 100644 index 00000000..ed936351 --- /dev/null +++ b/tests/test_composer.py @@ -0,0 +1,222 @@ +import logging +import pytest +from decimal import Decimal + +from pyinjective.composer import Composer +from pyinjective.constant import Denom, Network +from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from pyinjective.proto.injective.exchange.v1beta1 import exchange_pb2 +from tests.model_fixtures.markets_fixtures import ( + btc_usdt_perp_market, + first_match_bet_market, + inj_token, + inj_usdt_spot_market, + usdt_token, + usdt_perp_token +) + + +class TestComposer: + + @pytest.fixture + def inj_usdt_market_id(self): + return "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0" + + @pytest.fixture + def basic_composer(self, inj_usdt_spot_market, btc_usdt_perp_market, first_match_bet_market): + composer = Composer( + network=Network.devnet().string(), + spot_markets={inj_usdt_spot_market.id: inj_usdt_spot_market}, + derivative_markets={btc_usdt_perp_market.id: btc_usdt_perp_market}, + binary_option_markets={first_match_bet_market.id: first_match_bet_market}, + tokens={ + inj_usdt_spot_market.base_token.symbol: inj_usdt_spot_market.base_token, + inj_usdt_spot_market.quote_token.symbol: inj_usdt_spot_market.quote_token, + btc_usdt_perp_market.quote_token.symbol: btc_usdt_perp_market.quote_token, + } + ) + + return composer + + def test_buy_spot_order_creation(self, basic_composer: Composer, inj_usdt_spot_market: SpotMarket): + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = 6.869 + quantity = 1587 + order = basic_composer.SpotOrder( + market_id=inj_usdt_spot_market.id, + subaccount_id="1", + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + is_buy=True, + ) + + price_decimals = inj_usdt_spot_market.quote_token.decimals - inj_usdt_spot_market.base_token.decimals + chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") + expected_price = ((chain_format_price // inj_usdt_spot_market.min_price_tick_size) + * inj_usdt_spot_market.min_price_tick_size + * Decimal(f"1e18")) + chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{inj_usdt_spot_market.base_token.decimals}") + expected_quantity = ((chain_format_quantity // inj_usdt_spot_market.min_quantity_tick_size) + * inj_usdt_spot_market.min_quantity_tick_size + * Decimal(f"1e18")) + + assert (order.market_id == inj_usdt_spot_market.id) + assert (order.order_info.subaccount_id == "1") + assert (order.order_info.fee_recipient == fee_recipient) + assert (order.order_info.price == str(int(expected_price))) + assert (order.order_info.quantity == str(int(expected_quantity))) + assert (order.order_type == exchange_pb2.OrderType.BUY) + assert (order.trigger_price == "0") + + def test_buy_derivative_order_creation(self, basic_composer: Composer, btc_usdt_perp_market: DerivativeMarket): + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = 6.869 + quantity = 1587 + leverage = 2 + order = basic_composer.DerivativeOrder( + market_id=btc_usdt_perp_market.id, + subaccount_id="1", + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + is_buy=True, + leverage=leverage, + ) + + price_decimals = btc_usdt_perp_market.quote_token.decimals + chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") + expected_price = ((chain_format_price // btc_usdt_perp_market.min_price_tick_size) + * btc_usdt_perp_market.min_price_tick_size + * Decimal(f"1e18")) + chain_format_quantity = Decimal(str(quantity)) + expected_quantity = ((chain_format_quantity // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size + * Decimal(f"1e18")) + chain_format_margin = (chain_format_quantity * chain_format_price) / Decimal(leverage) + expected_margin = ((chain_format_margin // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size + * Decimal(f"1e18")) + + assert (order.market_id == btc_usdt_perp_market.id) + assert (order.order_info.subaccount_id == "1") + assert (order.order_info.fee_recipient == fee_recipient) + assert (order.order_info.price == str(int(expected_price))) + assert (order.order_info.quantity == str(int(expected_quantity))) + assert (order.order_type == exchange_pb2.OrderType.BUY) + assert (order.margin == str(int(expected_margin))) + assert (order.trigger_price == "0") + + def test_increase_position_margin(self, basic_composer: Composer, btc_usdt_perp_market: DerivativeMarket): + sender = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + amount = 1587.789 + message = basic_composer.MsgIncreasePositionMargin( + sender=sender, + source_subaccount_id="1", + destination_subaccount_id="2", + market_id=btc_usdt_perp_market.id, + amount=amount, + ) + + price_decimals = btc_usdt_perp_market.quote_token.decimals + chain_format_margin = Decimal(str(amount)) * Decimal(f"1e{price_decimals}") + expected_margin = ((chain_format_margin // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size + * Decimal(f"1e18")) + + assert (message.market_id == btc_usdt_perp_market.id) + assert (message.sender == sender) + assert (message.source_subaccount_id == "1") + assert (message.destination_subaccount_id == "2") + assert (message.amount == str(int(expected_margin))) + + def test_buy_binary_option_order_creation_with_fixed_denom( + self, + basic_composer: Composer, + first_match_bet_market: BinaryOptionMarket + ): + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = 6.869 + quantity = 1587 + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=6, + min_price_tick_size=1000, + min_quantity_tick_size=10000, + ) + + order = basic_composer.BinaryOptionsOrder( + market_id=first_match_bet_market.id, + subaccount_id="1", + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + is_buy=True, + denom=fixed_denom, + ) + + price_decimals = fixed_denom.quote + chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") + expected_price = ((chain_format_price // Decimal(str(fixed_denom.min_price_tick_size))) + * Decimal(str(fixed_denom.min_price_tick_size)) + * Decimal(f"1e18")) + quantity_decimals = fixed_denom.base + chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{quantity_decimals}") + expected_quantity = ((chain_format_quantity // Decimal(str(fixed_denom.min_quantity_tick_size))) + * Decimal(str(fixed_denom.min_quantity_tick_size)) + * Decimal(f"1e18")) + chain_format_margin = chain_format_quantity * chain_format_price + expected_margin = ((chain_format_margin // Decimal(str(fixed_denom.min_quantity_tick_size))) + * Decimal(str(fixed_denom.min_quantity_tick_size)) + * Decimal(f"1e18")) + + assert (order.market_id == first_match_bet_market.id) + assert (order.order_info.subaccount_id == "1") + assert (order.order_info.fee_recipient == fee_recipient) + assert (order.order_info.price == str(int(expected_price))) + assert (order.order_info.quantity == str(int(expected_quantity))) + assert (order.order_type == exchange_pb2.OrderType.BUY) + assert (order.margin == str(int(expected_margin))) + assert (order.trigger_price == "0") + + def test_buy_binary_option_order_creation_without_fixed_denom( + self, + basic_composer: Composer, + first_match_bet_market: BinaryOptionMarket, + ): + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = 6.869 + quantity = 1587 + + order = basic_composer.BinaryOptionsOrder( + market_id=first_match_bet_market.id, + subaccount_id="1", + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + is_buy=True, + ) + + price_decimals = first_match_bet_market.quote_token.decimals + chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") + expected_price = ((chain_format_price // first_match_bet_market.min_price_tick_size) + * first_match_bet_market.min_price_tick_size + * Decimal(f"1e18")) + chain_format_quantity = Decimal(str(quantity)) + expected_quantity = ((chain_format_quantity // first_match_bet_market.min_quantity_tick_size) + * first_match_bet_market.min_quantity_tick_size + * Decimal(f"1e18")) + chain_format_margin = (chain_format_quantity * chain_format_price) + expected_margin = ((chain_format_margin // first_match_bet_market.min_quantity_tick_size) + * first_match_bet_market.min_quantity_tick_size + * Decimal(f"1e18")) + + assert (order.market_id == first_match_bet_market.id) + assert (order.order_info.subaccount_id == "1") + assert (order.order_info.fee_recipient == fee_recipient) + assert (order.order_info.price == str(int(expected_price))) + assert (order.order_info.quantity == str(int(expected_quantity))) + assert (order.order_type == exchange_pb2.OrderType.BUY) + assert (order.margin == str(int(expected_margin))) + assert (order.trigger_price == "0") From dd7f18e39fb8b026c1a66c34b63c6e8c03fe4524 Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 26 May 2023 10:12:55 +0200 Subject: [PATCH 03/40] (fix) Remove deprecation warning from Denom class since it is still being used for Binary Options --- examples/chain_client/6_MsgCreateDerivativeLimitOrder.py | 2 +- pyinjective/constant.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py index 4471fb79..c0257b46 100644 --- a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py +++ b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py @@ -23,7 +23,7 @@ async def main() -> None: subaccount_id = address.get_subaccount_id(index=0) # prepare trade info - market_id = "0x90e662193fa29a3a7e6c07be4407c94833e762d9ee82136a2cc712d6b87d7de3" + market_id = "0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74" fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg diff --git a/pyinjective/constant.py b/pyinjective/constant.py index 0774e4b3..35947d89 100644 --- a/pyinjective/constant.py +++ b/pyinjective/constant.py @@ -1,6 +1,5 @@ import os from configparser import ConfigParser -from warnings import warn MAX_CLIENT_ID_LENGTH = 128 MAX_DATA_SIZE = 256 @@ -34,8 +33,6 @@ def __init__( min_price_tick_size: float, min_quantity_tick_size: float ): - """This throws a deprecation warning on initialization.""" - warn(f'{self.__class__.__name__} will be deprecated.', DeprecationWarning, stacklevel=2) self.description = description self.base = base From 78b990fc0ff2193721510a04e5bade214efd1bd6 Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Mon, 29 May 2023 13:39:40 +0200 Subject: [PATCH 04/40] (fix) Undoing rename changes that impacted proto autogenreated components --- ...ective_derivative_exchange_rpc_pb2_grpc.py | 24 +++++++++---------- .../injective_spot_exchange_rpc_pb2_grpc.py | 22 ++++++++--------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py b/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py index 202fd9e4..ac68f1ce 100644 --- a/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py +++ b/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py @@ -22,7 +22,7 @@ def __init__(self, channel): response_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsResponse.FromString, ) self.Market = channel.unary_unary( - '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/SpotMarket', + '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/Market', request_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.SerializeToString, response_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.FromString, ) @@ -156,7 +156,7 @@ def Markets(self, request, context): raise NotImplementedError('Method not implemented!') def Market(self, request, context): - """SpotMarket gets details of a single derivative market + """Market gets details of a single derivative market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -184,14 +184,14 @@ def BinaryOptionsMarket(self, request, context): raise NotImplementedError('Method not implemented!') def Orderbook(self, request, context): - """Orderbook gets the Orderbook of a Derivative SpotMarket + """Orderbook gets the Orderbook of a Derivative Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def OrderbookV2(self, request, context): - """Orderbook gets the Orderbook of a Derivative SpotMarket + """Orderbook gets the Orderbook of a Derivative Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -233,7 +233,7 @@ def StreamOrderbookUpdate(self, request, context): raise NotImplementedError('Method not implemented!') def Orders(self, request, context): - """DerivativeLimitOrders gets the limit orders of a derivative SpotMarket. + """DerivativeLimitOrders gets the limit orders of a derivative Market. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -275,21 +275,21 @@ def StreamPositions(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrders(self, request, context): - """StreamOrders streams updates to individual orders of a Derivative SpotMarket. + """StreamOrders streams updates to individual orders of a Derivative Market. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Trades(self, request, context): - """Trades gets the trades of a Derivative SpotMarket. + """Trades gets the trades of a Derivative Market. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamTrades(self, request, context): - """StreamTrades streams newly executed trades from Derivative SpotMarket. + """StreamTrades streams newly executed trades from Derivative Market. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -318,7 +318,7 @@ def OrdersHistory(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrdersHistory(self, request, context): - """Stream updates to historical orders of a derivative SpotMarket + """Stream updates to historical orders of a derivative Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -332,8 +332,8 @@ def add_InjectiveDerivativeExchangeRPCServicer_to_server(servicer, server): request_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsRequest.FromString, response_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsResponse.SerializeToString, ), - 'SpotMarket': grpc.unary_unary_rpc_method_handler( - servicer.SpotMarket, + 'Market': grpc.unary_unary_rpc_method_handler( + servicer.Market, request_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.FromString, response_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.SerializeToString, ), @@ -492,7 +492,7 @@ def Market(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/SpotMarket', + return grpc.experimental.unary_unary(request, target, '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/Market', exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.SerializeToString, exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.FromString, options, channel_credentials, diff --git a/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py b/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py index 5ca50005..2ba568f1 100644 --- a/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py +++ b/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py @@ -21,7 +21,7 @@ def __init__(self, channel): response_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsResponse.FromString, ) self.Market = channel.unary_unary( - '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/SpotMarket', + '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/Market', request_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.SerializeToString, response_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.FromString, ) @@ -133,14 +133,14 @@ def StreamMarkets(self, request, context): raise NotImplementedError('Method not implemented!') def Orderbook(self, request, context): - """Orderbook of a Spot SpotMarket + """Orderbook of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def OrderbookV2(self, request, context): - """Orderbook of a Spot SpotMarket + """Orderbook of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -182,28 +182,28 @@ def StreamOrderbookUpdate(self, request, context): raise NotImplementedError('Method not implemented!') def Orders(self, request, context): - """Orders of a Spot SpotMarket + """Orders of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamOrders(self, request, context): - """Stream updates to individual orders of a Spot SpotMarket + """Stream updates to individual orders of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Trades(self, request, context): - """Trades of a Spot SpotMarket + """Trades of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamTrades(self, request, context): - """Stream newly executed trades from Spot SpotMarket + """Stream newly executed trades from Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -231,7 +231,7 @@ def OrdersHistory(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrdersHistory(self, request, context): - """Stream updates to historical orders of a spot SpotMarket + """Stream updates to historical orders of a spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -245,8 +245,8 @@ def add_InjectiveSpotExchangeRPCServicer_to_server(servicer, server): request_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsRequest.FromString, response_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsResponse.SerializeToString, ), - 'SpotMarket': grpc.unary_unary_rpc_method_handler( - servicer.SpotMarket, + 'Market': grpc.unary_unary_rpc_method_handler( + servicer.Market, request_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.FromString, response_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.SerializeToString, ), @@ -369,7 +369,7 @@ def Market(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/SpotMarket', + return grpc.experimental.unary_unary(request, target, '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/Market', exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.SerializeToString, exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.FromString, options, channel_credentials, From 68972ac7d9c336b63a91e37eff6de2c740ce4a1c Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 26 May 2023 22:25:29 +0200 Subject: [PATCH 05/40] (fix) Solved issue preventing executing historical orders request both for spot and derivative markets --- pyinjective/async_client.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 25d9f2ce..e29bcbe9 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -701,12 +701,15 @@ async def get_spot_orders(self, market_id: str, **kwargs): ) return await self.stubSpotExchange.Orders(req) - async def get_historical_spot_orders(self, market_id: str, **kwargs): + async def get_historical_spot_orders(self, market_id: Optional[str] = None, **kwargs): + market_ids = kwargs.get("market_ids", []) + if market_id is not None: + market_ids.append(market_id) req = spot_exchange_rpc_pb.OrdersHistoryRequest( - market_id=market_id, + market_ids=kwargs.get("market_ids", []), direction=kwargs.get("direction"), - order_types=kwargs.get("order_types"), - execution_types=kwargs.get("execution_types"), + order_types=kwargs.get("order_types", []), + execution_types=kwargs.get("execution_types", []), subaccount_id=kwargs.get("subaccount_id"), skip=kwargs.get("skip"), limit=kwargs.get("limit"), @@ -861,14 +864,19 @@ async def get_derivative_orders(self, market_id: str, **kwargs): ) return await self.stubDerivativeExchange.Orders(req) - async def get_historical_derivative_orders(self, market_id: str, **kwargs): + async def get_historical_derivative_orders(self, market_id: Optional[str] = None, **kwargs): + market_ids = kwargs.get("market_ids", []) + if market_id is not None: + market_ids.append(market_id) + order_types = kwargs.get("order_types", []) + order_type = kwargs.get("order_type") + if order_type is not None: + order_types.append(market_id) req = derivative_exchange_rpc_pb.OrdersHistoryRequest( - market_id=market_id, - market_ids=kwargs.get("market_ids"), + market_ids=market_ids, direction=kwargs.get("direction"), - order_type=kwargs.get("order_type"), - order_types=kwargs.get("order_types"), - execution_types=kwargs.get("execution_types"), + order_types=order_types, + execution_types=kwargs.get("execution_types", []), subaccount_id=kwargs.get("subaccount_id"), is_conditional=kwargs.get("is_conditional"), skip=kwargs.get("skip"), From 2dad92983140d36fe7b461aa965139a8f4007827 Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 26 May 2023 22:37:42 +0200 Subject: [PATCH 06/40] (fix) Add bugfix description in the changelog in README file --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f3c37feb..c4a7a6f6 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ make tests ### Changelogs **0.7**(change before release) * Change logging logic to use different loggers for each module and class +* Solved issue preventing requesting spot and derivative historical orders for more than one market_id * Refactor Composer to be created with all the markets and tokens. The Composer now uses the real markets and tokens to convert human-readable values to chain format * The Composer can still be instantiated without markets and tokens. When markets and tokens are not provided the Composer loads the required information from the Denoms used in previous versions * Change in AsyncClient to be able to create Composer instances for the client network, markets and tokens From 2e0de164285d01687c27b1f5dafbcfc461262bba Mon Sep 17 00:00:00 2001 From: abel Date: Thu, 25 May 2023 18:21:05 +0200 Subject: [PATCH 07/40] (feat) Refactor Composer to use actual markets and tokens to translate human-readable values into chain format --- pyinjective/constant.py | 1 + ...ective_derivative_exchange_rpc_pb2_grpc.py | 24 +++++++++---------- .../injective_spot_exchange_rpc_pb2_grpc.py | 22 ++++++++--------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/pyinjective/constant.py b/pyinjective/constant.py index 35947d89..0e074e62 100644 --- a/pyinjective/constant.py +++ b/pyinjective/constant.py @@ -1,5 +1,6 @@ import os from configparser import ConfigParser +from warnings import warn MAX_CLIENT_ID_LENGTH = 128 MAX_DATA_SIZE = 256 diff --git a/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py b/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py index ac68f1ce..202fd9e4 100644 --- a/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py +++ b/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py @@ -22,7 +22,7 @@ def __init__(self, channel): response_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsResponse.FromString, ) self.Market = channel.unary_unary( - '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/Market', + '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/SpotMarket', request_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.SerializeToString, response_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.FromString, ) @@ -156,7 +156,7 @@ def Markets(self, request, context): raise NotImplementedError('Method not implemented!') def Market(self, request, context): - """Market gets details of a single derivative market + """SpotMarket gets details of a single derivative market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -184,14 +184,14 @@ def BinaryOptionsMarket(self, request, context): raise NotImplementedError('Method not implemented!') def Orderbook(self, request, context): - """Orderbook gets the Orderbook of a Derivative Market + """Orderbook gets the Orderbook of a Derivative SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def OrderbookV2(self, request, context): - """Orderbook gets the Orderbook of a Derivative Market + """Orderbook gets the Orderbook of a Derivative SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -233,7 +233,7 @@ def StreamOrderbookUpdate(self, request, context): raise NotImplementedError('Method not implemented!') def Orders(self, request, context): - """DerivativeLimitOrders gets the limit orders of a derivative Market. + """DerivativeLimitOrders gets the limit orders of a derivative SpotMarket. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -275,21 +275,21 @@ def StreamPositions(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrders(self, request, context): - """StreamOrders streams updates to individual orders of a Derivative Market. + """StreamOrders streams updates to individual orders of a Derivative SpotMarket. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Trades(self, request, context): - """Trades gets the trades of a Derivative Market. + """Trades gets the trades of a Derivative SpotMarket. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamTrades(self, request, context): - """StreamTrades streams newly executed trades from Derivative Market. + """StreamTrades streams newly executed trades from Derivative SpotMarket. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -318,7 +318,7 @@ def OrdersHistory(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrdersHistory(self, request, context): - """Stream updates to historical orders of a derivative Market + """Stream updates to historical orders of a derivative SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -332,8 +332,8 @@ def add_InjectiveDerivativeExchangeRPCServicer_to_server(servicer, server): request_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsRequest.FromString, response_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsResponse.SerializeToString, ), - 'Market': grpc.unary_unary_rpc_method_handler( - servicer.Market, + 'SpotMarket': grpc.unary_unary_rpc_method_handler( + servicer.SpotMarket, request_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.FromString, response_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.SerializeToString, ), @@ -492,7 +492,7 @@ def Market(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/Market', + return grpc.experimental.unary_unary(request, target, '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/SpotMarket', exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.SerializeToString, exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.FromString, options, channel_credentials, diff --git a/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py b/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py index 2ba568f1..5ca50005 100644 --- a/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py +++ b/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py @@ -21,7 +21,7 @@ def __init__(self, channel): response_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsResponse.FromString, ) self.Market = channel.unary_unary( - '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/Market', + '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/SpotMarket', request_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.SerializeToString, response_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.FromString, ) @@ -133,14 +133,14 @@ def StreamMarkets(self, request, context): raise NotImplementedError('Method not implemented!') def Orderbook(self, request, context): - """Orderbook of a Spot Market + """Orderbook of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def OrderbookV2(self, request, context): - """Orderbook of a Spot Market + """Orderbook of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -182,28 +182,28 @@ def StreamOrderbookUpdate(self, request, context): raise NotImplementedError('Method not implemented!') def Orders(self, request, context): - """Orders of a Spot Market + """Orders of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamOrders(self, request, context): - """Stream updates to individual orders of a Spot Market + """Stream updates to individual orders of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Trades(self, request, context): - """Trades of a Spot Market + """Trades of a Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamTrades(self, request, context): - """Stream newly executed trades from Spot Market + """Stream newly executed trades from Spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -231,7 +231,7 @@ def OrdersHistory(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrdersHistory(self, request, context): - """Stream updates to historical orders of a spot Market + """Stream updates to historical orders of a spot SpotMarket """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -245,8 +245,8 @@ def add_InjectiveSpotExchangeRPCServicer_to_server(servicer, server): request_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsRequest.FromString, response_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsResponse.SerializeToString, ), - 'Market': grpc.unary_unary_rpc_method_handler( - servicer.Market, + 'SpotMarket': grpc.unary_unary_rpc_method_handler( + servicer.SpotMarket, request_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.FromString, response_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.SerializeToString, ), @@ -369,7 +369,7 @@ def Market(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/Market', + return grpc.experimental.unary_unary(request, target, '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/SpotMarket', exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.SerializeToString, exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.FromString, options, channel_credentials, From 44f5c40aff8e3859b0585efa3c283bc456289d1e Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Mon, 29 May 2023 18:22:31 +0200 Subject: [PATCH 08/40] (fix) Turned market classes and token class into dataclass with eq and hash support --- pyinjective/core/market.py | 8 ++++---- pyinjective/core/token.py | 28 +++++++++------------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/pyinjective/core/market.py b/pyinjective/core/market.py index d28ba462..9a42b88c 100644 --- a/pyinjective/core/market.py +++ b/pyinjective/core/market.py @@ -2,11 +2,11 @@ from decimal import Decimal from typing import Optional -from constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS, Denom +from pyinjective.constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS, Denom from pyinjective.core.token import Token -@dataclass +@dataclass(eq=True, frozen=True) class SpotMarket: id: str status: str @@ -34,7 +34,7 @@ def price_to_chain_format(self, human_readable_value: Decimal) -> Decimal: return extended_chain_formatted_value -@dataclass +@dataclass(eq=True, frozen=True) class DerivativeMarket: id: str status: str @@ -92,7 +92,7 @@ def calculate_margin_in_chain_format( return extended_chain_formatted_margin -@dataclass +@dataclass(eq=True, frozen=True) class BinaryOptionMarket: id: str status: str diff --git a/pyinjective/core/token.py b/pyinjective/core/token.py index 59bac41e..c6af6c0d 100644 --- a/pyinjective/core/token.py +++ b/pyinjective/core/token.py @@ -1,25 +1,15 @@ +from dataclasses import dataclass from decimal import Decimal - +@dataclass(eq=True, frozen=True) class Token: - - def __init__( - self, - name: str, - symbol: str, - denom: str, - address: str, - decimals: int, - logo: str, - updated: int, - ): - self.name = name - self.symbol = symbol - self.denom = denom - self.address = address - self.decimals = decimals - self.logo = logo - self.updated = updated + name: str + symbol: str + denom: str + address: str + decimals: int + logo: str + updated: int def chain_formatted_value(self, human_readable_value: Decimal) -> Decimal: return human_readable_value * Decimal(f"1e{self.decimals}") From 6fc81f4d763940d90a01cc1f64c28c5438566488 Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Mon, 29 May 2023 18:28:35 +0200 Subject: [PATCH 09/40] (fix) Undoing impact of rename of Market to SpotMarket in grpc autogenerated elements --- ...ective_derivative_exchange_rpc_pb2_grpc.py | 24 +++++++++---------- .../injective_spot_exchange_rpc_pb2_grpc.py | 22 ++++++++--------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py b/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py index 202fd9e4..ac68f1ce 100644 --- a/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py +++ b/pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2_grpc.py @@ -22,7 +22,7 @@ def __init__(self, channel): response_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsResponse.FromString, ) self.Market = channel.unary_unary( - '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/SpotMarket', + '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/Market', request_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.SerializeToString, response_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.FromString, ) @@ -156,7 +156,7 @@ def Markets(self, request, context): raise NotImplementedError('Method not implemented!') def Market(self, request, context): - """SpotMarket gets details of a single derivative market + """Market gets details of a single derivative market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -184,14 +184,14 @@ def BinaryOptionsMarket(self, request, context): raise NotImplementedError('Method not implemented!') def Orderbook(self, request, context): - """Orderbook gets the Orderbook of a Derivative SpotMarket + """Orderbook gets the Orderbook of a Derivative Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def OrderbookV2(self, request, context): - """Orderbook gets the Orderbook of a Derivative SpotMarket + """Orderbook gets the Orderbook of a Derivative Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -233,7 +233,7 @@ def StreamOrderbookUpdate(self, request, context): raise NotImplementedError('Method not implemented!') def Orders(self, request, context): - """DerivativeLimitOrders gets the limit orders of a derivative SpotMarket. + """DerivativeLimitOrders gets the limit orders of a derivative Market. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -275,21 +275,21 @@ def StreamPositions(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrders(self, request, context): - """StreamOrders streams updates to individual orders of a Derivative SpotMarket. + """StreamOrders streams updates to individual orders of a Derivative Market. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Trades(self, request, context): - """Trades gets the trades of a Derivative SpotMarket. + """Trades gets the trades of a Derivative Market. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamTrades(self, request, context): - """StreamTrades streams newly executed trades from Derivative SpotMarket. + """StreamTrades streams newly executed trades from Derivative Market. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -318,7 +318,7 @@ def OrdersHistory(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrdersHistory(self, request, context): - """Stream updates to historical orders of a derivative SpotMarket + """Stream updates to historical orders of a derivative Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -332,8 +332,8 @@ def add_InjectiveDerivativeExchangeRPCServicer_to_server(servicer, server): request_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsRequest.FromString, response_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketsResponse.SerializeToString, ), - 'SpotMarket': grpc.unary_unary_rpc_method_handler( - servicer.SpotMarket, + 'Market': grpc.unary_unary_rpc_method_handler( + servicer.Market, request_deserializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.FromString, response_serializer=exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.SerializeToString, ), @@ -492,7 +492,7 @@ def Market(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/SpotMarket', + return grpc.experimental.unary_unary(request, target, '/injective_derivative_exchange_rpc.InjectiveDerivativeExchangeRPC/Market', exchange_dot_injective__derivative__exchange__rpc__pb2.MarketRequest.SerializeToString, exchange_dot_injective__derivative__exchange__rpc__pb2.MarketResponse.FromString, options, channel_credentials, diff --git a/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py b/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py index 5ca50005..2ba568f1 100644 --- a/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py +++ b/pyinjective/proto/exchange/injective_spot_exchange_rpc_pb2_grpc.py @@ -21,7 +21,7 @@ def __init__(self, channel): response_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsResponse.FromString, ) self.Market = channel.unary_unary( - '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/SpotMarket', + '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/Market', request_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.SerializeToString, response_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.FromString, ) @@ -133,14 +133,14 @@ def StreamMarkets(self, request, context): raise NotImplementedError('Method not implemented!') def Orderbook(self, request, context): - """Orderbook of a Spot SpotMarket + """Orderbook of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def OrderbookV2(self, request, context): - """Orderbook of a Spot SpotMarket + """Orderbook of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -182,28 +182,28 @@ def StreamOrderbookUpdate(self, request, context): raise NotImplementedError('Method not implemented!') def Orders(self, request, context): - """Orders of a Spot SpotMarket + """Orders of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamOrders(self, request, context): - """Stream updates to individual orders of a Spot SpotMarket + """Stream updates to individual orders of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Trades(self, request, context): - """Trades of a Spot SpotMarket + """Trades of a Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def StreamTrades(self, request, context): - """Stream newly executed trades from Spot SpotMarket + """Stream newly executed trades from Spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -231,7 +231,7 @@ def OrdersHistory(self, request, context): raise NotImplementedError('Method not implemented!') def StreamOrdersHistory(self, request, context): - """Stream updates to historical orders of a spot SpotMarket + """Stream updates to historical orders of a spot Market """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -245,8 +245,8 @@ def add_InjectiveSpotExchangeRPCServicer_to_server(servicer, server): request_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsRequest.FromString, response_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketsResponse.SerializeToString, ), - 'SpotMarket': grpc.unary_unary_rpc_method_handler( - servicer.SpotMarket, + 'Market': grpc.unary_unary_rpc_method_handler( + servicer.Market, request_deserializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.FromString, response_serializer=exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.SerializeToString, ), @@ -369,7 +369,7 @@ def Market(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/SpotMarket', + return grpc.experimental.unary_unary(request, target, '/injective_spot_exchange_rpc.InjectiveSpotExchangeRPC/Market', exchange_dot_injective__spot__exchange__rpc__pb2.MarketRequest.SerializeToString, exchange_dot_injective__spot__exchange__rpc__pb2.MarketResponse.FromString, options, channel_credentials, From 05f6d91a998ea7fabf880e1a30a32ee39ef087fd Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Mon, 29 May 2023 19:32:28 +0200 Subject: [PATCH 10/40] (feat) Included logic to validate INI files metadata against indexer info in the `utils` module --- pyinjective/{ => utils}/fetch_metadata.py | 4 +- pyinjective/utils/metadata_validation.py | 105 ++++++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) rename pyinjective/{ => utils}/fetch_metadata.py (97%) create mode 100644 pyinjective/utils/metadata_validation.py diff --git a/pyinjective/fetch_metadata.py b/pyinjective/utils/fetch_metadata.py similarity index 97% rename from pyinjective/fetch_metadata.py rename to pyinjective/utils/fetch_metadata.py index 1abbd815..a1a00c51 100644 --- a/pyinjective/fetch_metadata.py +++ b/pyinjective/utils/fetch_metadata.py @@ -96,12 +96,12 @@ async def fetch_denom(network) -> str: async def main() -> None: testnet = Network.testnet() data = await fetch_denom(testnet) - with open("denoms_testnet.ini", "w") as text_file: + with open("../denoms_testnet.ini", "w") as text_file: text_file.write(data) mainnet = Network.mainnet() data = await fetch_denom(mainnet) - with open("denoms_mainnet.ini", "w") as text_file: + with open("../denoms_mainnet.ini", "w") as text_file: text_file.write(data) if __name__ == '__main__': diff --git a/pyinjective/utils/metadata_validation.py b/pyinjective/utils/metadata_validation.py new file mode 100644 index 00000000..79befd40 --- /dev/null +++ b/pyinjective/utils/metadata_validation.py @@ -0,0 +1,105 @@ +import asyncio +from decimal import Decimal +from typing import Any, List, Tuple + +import pyinjective.constant as constant +from pyinjective.async_client import AsyncClient +from pyinjective.constant import Network +from pyinjective.core.market import SpotMarket, DerivativeMarket, BinaryOptionMarket + + +def find_metadata_inconsistencies(network: Network) -> Tuple[List[Any]]: + client = AsyncClient(network, insecure=False) + + spot_markets = asyncio.get_event_loop().run_until_complete(client.all_spot_markets()) + derivative_markets = asyncio.get_event_loop().run_until_complete(client.all_derivative_markets()) + binary_option_markets = asyncio.get_event_loop().run_until_complete(client.all_binary_option_markets()) + all_tokens = asyncio.get_event_loop().run_until_complete(client.all_tokens()) + + markets_not_found = [] + markets_with_diffs = [] + peggy_denoms_not_found = [] + peggy_denoms_with_diffs = [] + + for config_key in constant.mainnet_config: + if config_key.startswith("0x"): + denom = constant.Denom.load_market(network=network.string(), market_id=config_key) + if config_key in spot_markets: + market: SpotMarket = spot_markets[config_key] + if (market.base_token.decimals != denom.base + or market.quote_token.decimals != denom.quote + or market.min_price_tick_size != Decimal(str(denom.min_price_tick_size)) + or market.min_quantity_tick_size != Decimal(str(denom.min_quantity_tick_size))): + markets_with_diffs.append([ + {"denom-market": config_key, "base_decimals": denom.base, "quote_decimals": denom.quote, + "min_quantity_tick_size": denom.min_quantity_tick_size, + "min_price_tick_size": denom.min_price_tick_size}, + {"newer-market": market.id, "base_decimals": market.base_token.decimals, + "quote_decimals": market.quote_token.decimals, + "min_quantity_tick_size": float(market.min_quantity_tick_size), + "min_price_tick_size": float(market.min_price_tick_size), "ticker": market.ticker}, + ]) + elif config_key in derivative_markets: + market: DerivativeMarket = derivative_markets[config_key] + if (market.quote_token.decimals != denom.quote + or market.min_price_tick_size != Decimal(str(denom.min_price_tick_size)) + or market.min_quantity_tick_size != Decimal(str(denom.min_quantity_tick_size))): + markets_with_diffs.append([ + {"denom-market": config_key, "quote_decimals": denom.quote, + "min_quantity_tick_size": denom.min_quantity_tick_size, + "min_price_tick_size": denom.min_price_tick_size}, + {"newer-market": market.id, "quote_decimals": market.quote_token.decimals, + "min_quantity_tick_size": float(market.min_quantity_tick_size), + "min_price_tick_size": float(market.min_price_tick_size), "ticker": market.ticker}, + ]) + elif config_key in binary_option_markets: + market: BinaryOptionMarket = binary_option_markets[config_key] + if (market.quote_token.decimals != denom.quote + or market.min_price_tick_size != Decimal(str(denom.min_price_tick_size)) + or market.min_quantity_tick_size != Decimal(str(denom.min_quantity_tick_size))): + markets_with_diffs.append([ + {"denom-market": config_key, "quote_decimals": denom.quote, + "min_quantity_tick_size": denom.min_quantity_tick_size, + "min_price_tick_size": denom.min_price_tick_size}, + {"newer-market": market.id, "quote_decimals": market.quote_token.decimals, + "min_quantity_tick_size": float(market.min_quantity_tick_size), + "min_price_tick_size": float(market.min_price_tick_size), "ticker": market.ticker}, + ]) + else: + markets_not_found.append({"denom-market": config_key, "description": denom.description}) + + elif config_key == "DEFAULT": + continue + else: + # the configuration is a token + peggy_denom, decimals = constant.Denom.load_peggy_denom(network=network.string(), symbol=config_key) + if config_key in all_tokens: + token = all_tokens[config_key] + if (token.denom != peggy_denom + or token.decimals != decimals): + peggy_denoms_with_diffs.append([ + {"denom_token": config_key, "peggy_denom": peggy_denom, "decimals": decimals}, + {"newer_token": token.symbol, "peggy_denom": token.denom, "decimals": token.decimals} + ]) + else: + peggy_denoms_not_found.append( + {"denom_token": config_key, "peggy_denom": peggy_denom, "decimals": decimals}) + + return markets_with_diffs, markets_not_found, peggy_denoms_with_diffs, peggy_denoms_not_found + + +def print_metadata_mismatches(network: Network): + markets_with_diffs, markets_not_found, peggy_denoms_with_diffs, peggy_denoms_not_found = find_metadata_inconsistencies( + network=network) + + for diff_pair in markets_with_diffs: + print(f"{diff_pair[0]}\n{diff_pair[1]}") + print(f"\n\n") + for missing_market in markets_not_found: + print(f"{missing_market}") + print(f"\n\n") + for diff_token in peggy_denoms_with_diffs: + print(f"{diff_token[0]}\n{diff_token[1]}") + print(f"\n\n") + for missing_peggy in peggy_denoms_not_found: + print(f"{missing_peggy}") From 79c722eef187ea20860bb1546d1484d152e22868 Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Tue, 30 May 2023 01:45:06 +0200 Subject: [PATCH 11/40] (fix) Fixed INI files to synchronize them with the information for the markets in the chain --- pyinjective/denoms_devnet.ini | 2 +- pyinjective/denoms_mainnet.ini | 28 +++++----------------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/pyinjective/denoms_devnet.ini b/pyinjective/denoms_devnet.ini index 7b2df629..4e4f2797 100644 --- a/pyinjective/denoms_devnet.ini +++ b/pyinjective/denoms_devnet.ini @@ -92,7 +92,7 @@ min_display_quantity_tick_size = 0.001 description = 'Devnet Spot GF/USDT' base = 18 quote = 6 -min_price_tick_size = 0.000000000000001 +min_price_tick_size = 0.0000000000000001 min_display_price_tick_size = 0.001 min_quantity_tick_size = 100000 min_display_quantity_tick_size = 1e-13 diff --git a/pyinjective/denoms_mainnet.ini b/pyinjective/denoms_mainnet.ini index e714f3e6..6ef26207 100644 --- a/pyinjective/denoms_mainnet.ini +++ b/pyinjective/denoms_mainnet.ini @@ -200,7 +200,7 @@ min_display_quantity_tick_size = 0.01 description = 'Mainnet Spot GF/USDT' base = 18 quote = 6 -min_price_tick_size = 0.000000000000001 +min_price_tick_size = 0.0000000000000001 min_display_price_tick_size = 0.001 min_quantity_tick_size = 1000000000000000 min_display_quantity_tick_size = 0.001 @@ -317,7 +317,7 @@ min_display_quantity_tick_size = 100.0 description = 'Mainnet Spot STRD/USDT' base = 6 quote = 6 -min_price_tick_size = 0.001 +min_price_tick_size = 0.0001 min_display_price_tick_size = 1e-09 min_quantity_tick_size = 1000 min_display_quantity_tick_size = 1000.0 @@ -328,7 +328,7 @@ base = 6 quote = 6 min_price_tick_size = 0.0001 min_display_price_tick_size = 0.0001 -min_quantity_tick_size = 10000000 +min_quantity_tick_size = 1000000 min_display_quantity_tick_size = 10.0 [0x4fa0bd2c2adbfe077f58395c18a72f5cbf89532743e3bddf43bc7aba706b0b74] @@ -443,7 +443,7 @@ min_display_quantity_tick_size = 0.01 description = 'Mainnet Derivative STX/USDT PERP' base = 0 quote = 6 -min_price_tick_size = 1000 +min_price_tick_size = 100 min_display_price_tick_size = 0.001 min_quantity_tick_size = 0.1 min_display_quantity_tick_size = 0.1 @@ -484,15 +484,6 @@ min_display_price_tick_size = 0.01 min_quantity_tick_size = 0.1 min_display_quantity_tick_size = 0.1 -[0x5e7be7948c78f0c7fb1170655b5faa0a519ee0801250dde0b50308791474e61c] -description = 'Mainnet Derivative ETH/USDT 19SEP22' -base = 0 -quote = 6 -min_price_tick_size = 100000 -min_display_price_tick_size = 0.1 -min_quantity_tick_size = 0.01 -min_display_quantity_tick_size = 0.01 - [0x3b7fb1d9351f7fa2e6e0e5a11b3639ee5e0486c33a6a74f629c3fc3c3043efd5] description = 'Mainnet Derivative BONK/USDT PERP' base = 0 @@ -502,15 +493,6 @@ min_display_price_tick_size = 1e-10 min_quantity_tick_size = 0.1 min_display_quantity_tick_size = 0.1 -[0x0db3e97a9d57dc802c8598ef6fe24e77aeb3ba0ddd20d9d96bbf43c30de0163a] -description = 'Mainnet Derivative 1000PEPE/USDT PERP' -base = 0 -quote = 6 -min_price_tick_size = 0.000001 -min_display_price_tick_size = 1e-06 -min_quantity_tick_size = 1000 -min_display_quantity_tick_size = 1000 - [WETH] peggy_denom = peggy0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 decimals = 18 @@ -655,7 +637,7 @@ decimals = 8 peggy_denom = factory/inj14ejqjyq8um4p3xfqj74yld5waqljf88f9eneuk/inj1d5vz0uzwlpfvgwrwulxg6syy82axa58y4fuszd decimals = 8 -[wMATIC] +[WMATIC] peggy_denom = factory/inj14ejqjyq8um4p3xfqj74yld5waqljf88f9eneuk/inj1dxv423h8ygzgxmxnvrf33ws3k94aedfdevxd8h decimals = 8 From 541b01ac21580add11029e4912eab7940c05c9b6 Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Tue, 30 May 2023 13:15:35 +0200 Subject: [PATCH 12/40] (fix) Updated examples and the `run-examples.sh` script to enable the execution off all examples with the new code base --- .../spot_exchange_rpc/14_Orderbooks.py | 2 +- .../spot_exchange_rpc/16_OrderbooksV2.py | 19 ------------------- .../spot_exchange_rpc/4_Orderbook.py | 2 +- pyinjective/async_client.py | 8 -------- pyinjective/composer.py | 11 ++++++++--- pyinjective/denoms_testnet.ini | 2 +- run-examples.sh | 6 ++++-- tests/test_composer.py | 13 +++++++++++++ 8 files changed, 28 insertions(+), 35 deletions(-) delete mode 100644 examples/exchange_client/spot_exchange_rpc/16_OrderbooksV2.py diff --git a/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py b/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py index 0e792d5a..59d23047 100644 --- a/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py +++ b/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py @@ -11,7 +11,7 @@ async def main() -> None: "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0" ] - orderbooks = await client.get_spot_orderbooks(market_ids=market_ids) + orderbooks = await client.get_spot_orderbooksV2(market_ids=market_ids) print(orderbooks) if __name__ == '__main__': diff --git a/examples/exchange_client/spot_exchange_rpc/16_OrderbooksV2.py b/examples/exchange_client/spot_exchange_rpc/16_OrderbooksV2.py deleted file mode 100644 index 6a28009e..00000000 --- a/examples/exchange_client/spot_exchange_rpc/16_OrderbooksV2.py +++ /dev/null @@ -1,19 +0,0 @@ -import asyncio -import logging - -from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network - -async def main() -> None: - # select network: local, testnet, mainnet - network = Network.testnet() - client = AsyncClient(network, insecure=False) - market_ids = [ - "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", - "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0" - ] - orderbooks = await client.get_spot_orderbooksV2(market_ids=market_ids) - print(orderbooks) - -if __name__ == '__main__': - asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py b/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py index 44522fbc..19b58933 100644 --- a/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py +++ b/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py @@ -8,7 +8,7 @@ async def main() -> None: network = Network.testnet() client = AsyncClient(network, insecure=False) market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" - orderbook = await client.get_spot_orderbook(market_id=market_id) + orderbook = await client.get_spot_orderbookV2(market_id=market_id) print(orderbook) if __name__ == '__main__': diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index e29bcbe9..429b73ef 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -675,14 +675,6 @@ async def stream_spot_markets(self, **kwargs): metadata = await self.load_cookie(type="exchange") return self.stubSpotExchange.StreamMarkets.__call__(req, metadata=metadata) - async def get_spot_orderbook(self, market_id: str): - req = spot_exchange_rpc_pb.OrderbookRequest(market_id=market_id) - return await self.stubSpotExchange.Orderbook(req) - - async def get_spot_orderbooks(self, market_ids: List): - req = spot_exchange_rpc_pb.OrderbooksRequest(market_ids=market_ids) - return await self.stubSpotExchange.Orderbooks(req) - async def get_spot_orderbookV2(self, market_id: str): req = spot_exchange_rpc_pb.OrderbookV2Request(market_id=market_id) return await self.stubSpotExchange.OrderbookV2(req) diff --git a/pyinjective/composer.py b/pyinjective/composer.py index 4af1eb63..38e0e508 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -69,6 +69,10 @@ def __init__( """ self.network = network + self.spot_markets = dict() + self.derivative_markets = dict() + self.binary_option_markets = dict() + self.tokens = dict() if spot_markets is None or derivative_markets is None or binary_option_markets is None or tokens is None: self._initialize_markets_and_tokens_from_files() else: @@ -1004,7 +1008,7 @@ def _initialize_markets_and_tokens_from_files(self): min_price_tick_size=Decimal(str(configuration_section["min_price_tick_size"])), min_quantity_tick_size=Decimal(str(configuration_section["min_quantity_tick_size"])) ) - spot_markets[description] = market + spot_markets[market.id] = market else: market = DerivativeMarket( id=section_name, @@ -1024,7 +1028,7 @@ def _initialize_markets_and_tokens_from_files(self): min_quantity_tick_size=Decimal(str(configuration_section["min_quantity_tick_size"])), ) - derivative_markets[description] = market + derivative_markets[market.id] = market elif section_name != "DEFAULT": token = Token( @@ -1037,8 +1041,9 @@ def _initialize_markets_and_tokens_from_files(self): updated=-1, ) - tokens[token.symbol] = Token + tokens[token.symbol] = token self.tokens = tokens self.spot_markets = spot_markets self.derivative_markets = derivative_markets + self.binary_option_markets = dict() diff --git a/pyinjective/denoms_testnet.ini b/pyinjective/denoms_testnet.ini index 71cce2aa..ed076763 100644 --- a/pyinjective/denoms_testnet.ini +++ b/pyinjective/denoms_testnet.ini @@ -52,7 +52,7 @@ min_display_price_tick_size = 1e-05 min_quantity_tick_size = 100000 min_display_quantity_tick_size = 0.1 -[0xe112199d9ee44ceb2697ea0edd1cd422223c105f3ed2bdf85223d3ca59f5909a] +[0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6] description = 'Testnet Derivative INJ/USDT PERP' base = 0 quote = 6 diff --git a/run-examples.sh b/run-examples.sh index 8196e9d9..4b376ce9 100755 --- a/run-examples.sh +++ b/run-examples.sh @@ -1,5 +1,5 @@ runChainExamples(){ - examples=$(find -s examples/chain_client_examples -type f -mindepth 1 -name '*.py') + examples=$(find -s examples/chain_client -type f -mindepth 1 -name '*.py') echo "Running all chain examples..." for example in $examples do @@ -10,7 +10,7 @@ runChainExamples(){ } runExchangeExamples(){ - dirs=$(find -s examples/exchange_api_examples -type d -mindepth 1) + dirs=$(find -s examples/exchange_client -type d -mindepth 1) for dir in $dirs do examples=$(find -s $dir -type f -name '*.py') @@ -26,6 +26,8 @@ runExchangeExamples(){ done } +export PYTHONPATH=$PYTHONPATH:$(pwd) + TYPE=$1 case $TYPE in "chain") diff --git a/tests/test_composer.py b/tests/test_composer.py index ed936351..9c5426e5 100644 --- a/tests/test_composer.py +++ b/tests/test_composer.py @@ -38,6 +38,19 @@ def basic_composer(self, inj_usdt_spot_market, btc_usdt_perp_market, first_match return composer + def test_composer_initialization_from_ini_files(self): + composer = Composer(network=Network.devnet().string()) + + inj_token = composer.tokens["INJ"] + inj_usdt_spot_market = next((market for market in composer.spot_markets.values() if market.ticker == "'Devnet Spot INJ/USDT'")) + inj_usdt_perp_market = next((market for market in composer.derivative_markets.values() if market.ticker == "'Devnet Derivative INJ/USDT PERP'")) + + assert (18 == inj_token.decimals) + assert (18 == inj_usdt_spot_market.base_token.decimals) + assert (6 == inj_usdt_spot_market.quote_token.decimals) + assert (6 == inj_usdt_perp_market.quote_token.decimals) + + def test_buy_spot_order_creation(self, basic_composer: Composer, inj_usdt_spot_market: SpotMarket): fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" price = 6.869 From 6e837a8071d86bfc8e5dc30848c192ffde62f9ec Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Tue, 30 May 2023 20:42:41 +0200 Subject: [PATCH 13/40] (fix) Remove pysha3 requirement from Pipfile.lock since it is not required and is causing problems during `pipenv install` --- Pipfile.lock | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 5114fcbf..32dd8a9a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -873,32 +873,6 @@ ], "version": "==2.21" }, - "pysha3": { - "hashes": [ - "sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0", - "sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48", - "sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4", - "sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d", - "sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9", - "sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603", - "sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f", - "sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f", - "sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77", - "sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5", - "sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9", - "sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d", - "sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24", - "sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608", - "sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b", - "sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030", - "sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8", - "sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef", - "sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf", - "sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07", - "sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e" - ], - "version": "==1.0.2" - }, "python-dateutil": { "hashes": [ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", From 747ff34963e46fd1f9f26756e35944ded36287aa Mon Sep 17 00:00:00 2001 From: abel Date: Mon, 22 May 2023 12:32:31 +0200 Subject: [PATCH 14/40] (feat) Add pytest-grpc plugin to mock grpc iteractions --- Pipfile | 1 + pyinjective/async_client.py | 69 ++++++++++++++- pyinjective/core/__init__.py | 0 pyinjective/core/market.py | 18 ++++ pyinjective/core/token.py | 46 ++++++++++ setup.py | 1 + tests/async_client_tests.py | 58 ++++++++++++- tests/rpc_fixtures/__init__.py | 0 tests/rpc_fixtures/configurable_servicers.py | 18 ++++ tests/rpc_fixtures/markets_fixtures.py | 89 ++++++++++++++++++++ 10 files changed, 295 insertions(+), 5 deletions(-) create mode 100644 pyinjective/core/__init__.py create mode 100644 pyinjective/core/market.py create mode 100644 pyinjective/core/token.py create mode 100644 tests/rpc_fixtures/__init__.py create mode 100644 tests/rpc_fixtures/configurable_servicers.py create mode 100644 tests/rpc_fixtures/markets_fixtures.py diff --git a/Pipfile b/Pipfile index f07ae931..97f04274 100644 --- a/Pipfile +++ b/Pipfile @@ -25,6 +25,7 @@ websockets = "*" [dev-packages] pytest = "*" pytest-asyncio = "*" +pytest-grpc = "*" requests-mock = "*" [requires] diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 889cd038..72019f69 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -1,12 +1,14 @@ -import os +import asyncio import time import grpc import aiocron -import logging import datetime +from decimal import Decimal from http.cookies import SimpleCookie -from typing import List, Optional, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union +from .core.market import Market +from .core.token import Token from .exceptions import NotFoundError, EmptyMsgError from .proto.cosmos.base.abci.v1beta1 import abci_pb2 as abci_type @@ -179,6 +181,11 @@ def __init__( start=True, ) + self._tokens_and_markets_initialization_lock = asyncio.Lock() + self._tokens: Optional[Dict[str, Token]] = None + self._spot_markets: Optional[Dict[str, Market]] = None + self._derivative_markets: Optional[Dict] + def get_sequence(self): current_seq = self.sequence self.sequence += 1 @@ -984,7 +991,7 @@ async def get_funding_rates(self, market_id: str, **kwargs): skip=kwargs.get("skip"), limit=kwargs.get("limit"), end_time=kwargs.get("end_time"), -) + ) return await self.stubDerivativeExchange.FundingRates(req) async def get_binary_options_markets(self, **kwargs): @@ -1014,3 +1021,57 @@ async def stream_account_portfolio(self, account_address: str, **kwargs): ) metadata = await self.load_cookie(type="exchange") return self.stubPortfolio.StreamAccountPortfolio.__call__(req, metadata=metadata) + + async def _initialize_tokens_and_markets(self): + markets = dict() + tokens = dict() + markets_info = (await self.get_spot_markets()).markets + + for market_info in markets_info: + base_token = tokens.get(market_info.base_token.symbol) + if base_token is None: + base_token = Token( + name=market_info.base_token.name, + symbol=market_info.base_token.symbol, + decimals=market_info.base_token.decimals, + logo=market_info.base_token.logo, + ) + tokens[base_token.symbol] = base_token + base_token.add_source( + denom=market_info.base_denom, + symbol=market_info.base_token.symbol, + address=market_info.base_token.address, + decimals=market_info.base_token.decimals, + updated=market_info.base_token.updated_at, + ) + + quote_token = tokens.get(market_info.base_token.symbol) + if quote_token is None: + quote_token = Token( + name=market_info.quote_token.name, + symbol=market_info.quote_token.symbol, + decimals=market_info.quote_token.decimals, + logo=market_info.quote_token.logo, + ) + quote_token.add_source( + denom=market_info.quote_denom, + symbol=market_info.quote_token.symbol, + address=market_info.quote_token.address, + decimals=market_info.quote_token.decimals, + updated=market_info.quote_token.updated_at, + ) + + market = Market( + id=market_info.market_id, + status=market_info.market_status, + ticker=market_info.ticker, + base_token=base_token, + quote_token=quote_token, + maker_fee_rate=Decimal(market_info.maker_fee_rate), + taker_fee_rate=Decimal(market_info.taker_fee_rate), + service_provider_fee=Decimal(market_info.service_provider_fee), + min_price_tick_size=Decimal(market_info.min_price_tick_size), + min_quantity_tick_size=Decimal(market_info.min_quantity_tick_size), + ) + + markets[market.id] = market diff --git a/pyinjective/core/__init__.py b/pyinjective/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pyinjective/core/market.py b/pyinjective/core/market.py new file mode 100644 index 00000000..c17ce795 --- /dev/null +++ b/pyinjective/core/market.py @@ -0,0 +1,18 @@ +from dataclasses import dataclass +from decimal import Decimal + +from pyinjective.core.token import Token + + +@dataclass +class Market: + id: str + status: str + ticker: str + base_token: Token + quote_token: Token + maker_fee_rate: Decimal + taker_fee_rate: Decimal + service_provider_fee: Decimal + min_price_tick_size: Decimal + min_quantity_tick_size: Decimal \ No newline at end of file diff --git a/pyinjective/core/token.py b/pyinjective/core/token.py new file mode 100644 index 00000000..c80d8e89 --- /dev/null +++ b/pyinjective/core/token.py @@ -0,0 +1,46 @@ +from typing import Dict + + +class TokenSource: + + def __init__( + self, + denom: str, + symbol: str, + address: str, + decimals: int, + updated: int, + ): + self.denom = denom + self.symbol = symbol + self.address = address + self.decimals = decimals + self.updated = updated + + +class Token: + + def __init__( + self, + name: str, + symbol: str, + decimals: int, + logo: str, + ): + self.name = name + self.symbol = symbol + self.decimals = decimals + self.logo = logo + + self._sources = Dict[str, TokenSource] + + def add_source(self, denom: str, symbol: str, address: str, decimals: int, updated: int): + if denom not in self._sources: + token_source = TokenSource( + denom=denom, + symbol=symbol, + address=address, + decimals=decimals, + updated=updated, + ) + self._sources[denom] = token_source \ No newline at end of file diff --git a/setup.py b/setup.py index 6d3572b7..cfd728b4 100755 --- a/setup.py +++ b/setup.py @@ -41,6 +41,7 @@ DEV_REQUIRED = [ "pytest", "pytest-asyncio", + "pytest-grpc", "request-mock", ] diff --git a/tests/async_client_tests.py b/tests/async_client_tests.py index 0446d9ec..3c2995ba 100644 --- a/tests/async_client_tests.py +++ b/tests/async_client_tests.py @@ -4,7 +4,33 @@ from pyinjective.constant import Network from pyinjective.async_client import AsyncClient +from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import ( + MarketRequest, + MarketsRequest, + MarketResponse, + MarketsResponse, +) +from tests.rpc_fixtures.markets_fixtures import inj_token_meta, ape_token_meta, usdt_token_meta, inj_usdt_spot_market, ape_usdt_spot_market +@pytest.fixture(scope='module') +def grpc_add_to_server(): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import add_InjectiveSpotExchangeRPCServicer_to_server + + return add_InjectiveSpotExchangeRPCServicer_to_server + + +@pytest.fixture(scope='module') +def grpc_servicer(): + from tests.rpc_fixtures.configurable_servicers import ConfigurableInjectiveSpotExchangeRPCServicer + + return ConfigurableInjectiveSpotExchangeRPCServicer() + + +@pytest.fixture(scope='module') +def grpc_stub_cls(grpc_channel): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import InjectiveSpotExchangeRPCStub + + return InjectiveSpotExchangeRPCStub class TestAsyncClient: @@ -81,4 +107,34 @@ async def test_get_account_logs_exception(self, caplog): ) assert (found_log is not None) assert (found_log[0] == "pyinjective.async_client.AsyncClient") - assert (found_log[1] == logging.DEBUG) \ No newline at end of file + assert (found_log[1] == logging.DEBUG) + + @pytest.mark.asyncio + async def test_initialize_tokens_and_markets( + self, + grpc_stub, + grpc_servicer, + inj_usdt_spot_market, + ape_usdt_spot_market + ): + grpc_servicer.markets_queue.append(MarketsResponse( + markets=[inj_usdt_spot_market, ape_usdt_spot_market] + )) + + client = AsyncClient( + network=Network.local(), + insecure=False, + ) + + client.stubSpotExchange = grpc_stub + + await client._initialize_tokens_and_markets() + + assert(3 == len(client.tokens)) + assert(any((inj_usdt_spot_market.base_token_meta.symbol == token.symbol for token in client.tokens))) + assert (any((inj_usdt_spot_market.quote_token_meta.symbol == token.symbol for token in client.tokens))) + assert (any((ape_usdt_spot_market.base_token_meta.symbol == token.symbol for token in client.tokens))) + + assert (2 == len(client.markets)) + assert (any((inj_usdt_spot_market.market_id == market.id for market in client.markets))) + assert (any((ape_usdt_spot_market.market_id == market.id for market in client.markets))) diff --git a/tests/rpc_fixtures/__init__.py b/tests/rpc_fixtures/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/rpc_fixtures/configurable_servicers.py b/tests/rpc_fixtures/configurable_servicers.py new file mode 100644 index 00000000..dff625cf --- /dev/null +++ b/tests/rpc_fixtures/configurable_servicers.py @@ -0,0 +1,18 @@ +from collections import deque + +from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import ( + MarketsRequest, + MarketsResponse, +) +from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import InjectiveSpotExchangeRPCServicer + + +class ConfigurableInjectiveSpotExchangeRPCServicer(InjectiveSpotExchangeRPCServicer): + + def __init__(self): + super().__init__() + self.markets_queue = deque() + + def Markets(self, request: MarketsRequest, context): + return self.markets_queue.pop() + diff --git a/tests/rpc_fixtures/markets_fixtures.py b/tests/rpc_fixtures/markets_fixtures.py new file mode 100644 index 00000000..c21cd755 --- /dev/null +++ b/tests/rpc_fixtures/markets_fixtures.py @@ -0,0 +1,89 @@ +import pytest + + +@pytest.fixture +def inj_token_meta(): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import TokenMeta + + token = TokenMeta( + name="Injective Protocol", + address="0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30", + symbol="INJ", + logo="https://static.alchemyapi.io/images/assets/7226.png", + decimals=18, + updated_at=1681739137644 + ) + + return token + +@pytest.fixture +def ape_token_meta(): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import TokenMeta + + token = TokenMeta( + name="APE", + address="0x0000000000000000000000000000000000000000", + symbol="APE", + logo="https://assets.coingecko.com/coins/images/24383/small/apecoin.jpg?1647476455", + decimals=18, + updated_at=1681739137646 + ) + + return token + +@pytest.fixture +def usdt_token_meta(): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import TokenMeta + + token = TokenMeta( + name="USDT", + address="0x0000000000000000000000000000000000000000", + symbol="USDT", + logo="https://static.alchemyapi.io/images/assets/825.png", + decimals=6, + updated_at=1681739137645 + ) + + return token + +@pytest.fixture +def ape_usdt_spot_market(ape_token_meta, usdt_token_meta): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo + + market_request = SpotMarketInfo( + market_id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", + market_status="active", + ticker="APE/USDT", + base_denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", + base_token_meta=ape_token_meta, + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + quote_token_meta=usdt_token_meta, + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + service_provider_fee="0.4", + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + + return market_request + +@pytest.fixture +def inj_usdt_spot_market(inj_token_meta, usdt_token_meta): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo + + market_request = SpotMarketInfo( + market_id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", + market_status="active", + ticker="INJ/USDT", + base_denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", + base_token_meta=inj_token_meta, + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + quote_token_meta=usdt_token_meta, + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + service_provider_fee="0.4", + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + + return market_request From 1b52ba46667a3f72f2bbc0559fa95e4eceb62e42 Mon Sep 17 00:00:00 2001 From: abel Date: Thu, 25 May 2023 18:21:05 +0200 Subject: [PATCH 15/40] (feat) Refactor Composer to use actual markets and tokens to translate human-readable values into chain format --- README.md | 6 + examples/chain_client/0_LocalOrderHash.py | 4 +- .../13_MsgIncreasePositionMargin.py | 4 +- examples/chain_client/15_MsgWithdraw.py | 4 +- .../chain_client/16_MsgSubaccountTransfer.py | 4 +- .../chain_client/17_MsgBatchUpdateOrders.py | 6 +- examples/chain_client/18_MsgBid.py | 4 +- examples/chain_client/19_MsgGrant.py | 4 +- examples/chain_client/1_MsgSend.py | 4 +- examples/chain_client/20_MsgExec.py | 8 +- examples/chain_client/21_MsgRevoke.py | 4 +- examples/chain_client/22_MsgSendToEth.py | 4 +- .../chain_client/23_MsgRelayPriceFeedPrice.py | 4 +- examples/chain_client/24_MsgRewardsOptOut.py | 4 +- examples/chain_client/25_MsgDelegate.py | 4 +- .../26_MsgWithdrawDelegatorReward.py | 4 +- examples/chain_client/2_MsgDeposit.py | 4 +- examples/chain_client/30_ExternalTransfer.py | 4 +- .../31_MsgCreateBinaryOptionsLimitOrder.py | 6 +- .../32_MsgCreateBinaryOptionsMarketOrder.py | 6 +- .../33_MsgCancelBinaryOptionsOrder.py | 6 +- .../34_MsgAdminUpdateBinaryOptionsMarket.py | 6 +- .../35_MsgInstantBinaryOptionsMarketLaunch.py | 6 +- .../chain_client/36_MsgRelayProviderPrices.py | 6 +- .../chain_client/3_MsgCreateSpotLimitOrder.py | 6 +- .../chain_client/40_MsgExecuteContract.py | 4 +- .../chain_client/41_MsgCreateInsuranceFund.py | 4 +- examples/chain_client/42_MsgUnderwrite.py | 4 +- .../chain_client/43_MsgRequestRedemption.py | 4 +- .../4_MsgCreateSpotMarketOrder.py | 6 +- examples/chain_client/5_MsgCancelSpotOrder.py | 4 +- .../6_MsgCreateDerivativeLimitOrder.py | 6 +- .../7_MsgCreateDerivativeMarketOrder.py | 6 +- .../8_MsgCancelDerivativeOrder.py | 4 +- pyinjective/async_client.py | 171 ++++++++-- pyinjective/client.py | 2 +- pyinjective/composer.py | 315 +++++++++++------- pyinjective/constant.py | 14 + pyinjective/core/market.py | 137 +++++++- pyinjective/core/token.py | 39 +-- pyinjective/utils/utils.py | 108 ------ setup.py | 2 +- tests/composer_tests.py | 183 ---------- tests/{ => core}/__init__.py | 0 tests/core/test_market.py | 213 ++++++++++++ tests/core/test_token.py | 15 + tests/model_fixtures/__init__.py | 0 tests/model_fixtures/markets_fixtures.py | 113 +++++++ tests/rpc_fixtures/configurable_servicers.py | 28 +- tests/rpc_fixtures/markets_fixtures.py | 95 +++++- ...c_client_tests.py => test_async_client.py} | 90 +++-- tests/test_composer.py | 222 ++++++++++++ 52 files changed, 1286 insertions(+), 625 deletions(-) delete mode 100644 pyinjective/utils/utils.py delete mode 100644 tests/composer_tests.py rename tests/{ => core}/__init__.py (100%) create mode 100644 tests/core/test_market.py create mode 100644 tests/core/test_token.py create mode 100644 tests/model_fixtures/__init__.py create mode 100644 tests/model_fixtures/markets_fixtures.py rename tests/{async_client_tests.py => test_async_client.py} (55%) create mode 100644 tests/test_composer.py diff --git a/README.md b/README.md index e7b151a3..dffcb5da 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,12 @@ make tests ``` ### Changelogs +**0.7**(change before release) +* Refactor Composer to be created with all the markets and tokens. The Composer now uses the real markets and tokens to convert human-readable values to chain format +* The Composer can still be instantiated without markets and tokens. When markets and tokens are not provided the Composer loads the required information from the Denoms used in previous versions +* Change in AsyncClient to be able to create Composer instances for the client network, markets and tokens +* Examples have been adapted to create Composer instances using the AsyncClient + **0.6.4** * Change logging logic to use different loggers for each module and class * Solved issue preventing requesting spot and derivative historical orders for more than one market_id diff --git a/examples/chain_client/0_LocalOrderHash.py b/examples/chain_client/0_LocalOrderHash.py index a43cffee..12f6e448 100644 --- a/examples/chain_client/0_LocalOrderHash.py +++ b/examples/chain_client/0_LocalOrderHash.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/13_MsgIncreasePositionMargin.py b/examples/chain_client/13_MsgIncreasePositionMargin.py index 6d3926ec..1f89b287 100644 --- a/examples/chain_client/13_MsgIncreasePositionMargin.py +++ b/examples/chain_client/13_MsgIncreasePositionMargin.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/15_MsgWithdraw.py b/examples/chain_client/15_MsgWithdraw.py index 74fc8bce..5694ae46 100644 --- a/examples/chain_client/15_MsgWithdraw.py +++ b/examples/chain_client/15_MsgWithdraw.py @@ -13,9 +13,7 @@ # limitations under the License. import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -25,10 +23,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/16_MsgSubaccountTransfer.py b/examples/chain_client/16_MsgSubaccountTransfer.py index 6d02e5c2..7ec93b4c 100644 --- a/examples/chain_client/16_MsgSubaccountTransfer.py +++ b/examples/chain_client/16_MsgSubaccountTransfer.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/17_MsgBatchUpdateOrders.py b/examples/chain_client/17_MsgBatchUpdateOrders.py index 7ec36bd0..797e0a6c 100644 --- a/examples/chain_client/17_MsgBatchUpdateOrders.py +++ b/examples/chain_client/17_MsgBatchUpdateOrders.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -132,7 +130,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/18_MsgBid.py b/examples/chain_client/18_MsgBid.py index 35ab0256..e48ef1fa 100644 --- a/examples/chain_client/18_MsgBid.py +++ b/examples/chain_client/18_MsgBid.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -10,10 +8,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/19_MsgGrant.py b/examples/chain_client/19_MsgGrant.py index da9fbbb5..2b0bbb7b 100644 --- a/examples/chain_client/19_MsgGrant.py +++ b/examples/chain_client/19_MsgGrant.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/1_MsgSend.py b/examples/chain_client/1_MsgSend.py index f3a48769..0a37afc1 100644 --- a/examples/chain_client/1_MsgSend.py +++ b/examples/chain_client/1_MsgSend.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,11 +9,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False, chain_cookie_location="/tmp/.chain_cookie") + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/20_MsgExec.py b/examples/chain_client/20_MsgExec.py index 8aafd5d4..231a939f 100644 --- a/examples/chain_client/20_MsgExec.py +++ b/examples/chain_client/20_MsgExec.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -63,9 +61,9 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) data=sim_res_msg[0] - unpacked_msg_res = ProtoMsgComposer.UnpackMsgExecResponse( + unpacked_msg_res = composer.UnpackMsgExecResponse( msg_type=msg0.__class__.__name__, data=data ) diff --git a/examples/chain_client/21_MsgRevoke.py b/examples/chain_client/21_MsgRevoke.py index b01d799c..e6d35bd2 100644 --- a/examples/chain_client/21_MsgRevoke.py +++ b/examples/chain_client/21_MsgRevoke.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/22_MsgSendToEth.py b/examples/chain_client/22_MsgSendToEth.py index 91ecceb3..3b9abfc8 100644 --- a/examples/chain_client/22_MsgSendToEth.py +++ b/examples/chain_client/22_MsgSendToEth.py @@ -1,8 +1,6 @@ import asyncio -import logging import requests -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/23_MsgRelayPriceFeedPrice.py b/examples/chain_client/23_MsgRelayPriceFeedPrice.py index 592e993e..1f9bfc53 100644 --- a/examples/chain_client/23_MsgRelayPriceFeedPrice.py +++ b/examples/chain_client/23_MsgRelayPriceFeedPrice.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/24_MsgRewardsOptOut.py b/examples/chain_client/24_MsgRewardsOptOut.py index eb413004..34c48bc7 100644 --- a/examples/chain_client/24_MsgRewardsOptOut.py +++ b/examples/chain_client/24_MsgRewardsOptOut.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/25_MsgDelegate.py b/examples/chain_client/25_MsgDelegate.py index fb78dba8..d040dfd2 100644 --- a/examples/chain_client/25_MsgDelegate.py +++ b/examples/chain_client/25_MsgDelegate.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/26_MsgWithdrawDelegatorReward.py b/examples/chain_client/26_MsgWithdrawDelegatorReward.py index a1b955a7..c133f0ec 100644 --- a/examples/chain_client/26_MsgWithdrawDelegatorReward.py +++ b/examples/chain_client/26_MsgWithdrawDelegatorReward.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/2_MsgDeposit.py b/examples/chain_client/2_MsgDeposit.py index bcb6f78e..a1684ddc 100644 --- a/examples/chain_client/2_MsgDeposit.py +++ b/examples/chain_client/2_MsgDeposit.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/30_ExternalTransfer.py b/examples/chain_client/30_ExternalTransfer.py index 26defc09..1fcef982 100644 --- a/examples/chain_client/30_ExternalTransfer.py +++ b/examples/chain_client/30_ExternalTransfer.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py index ab79d52a..0d33b93d 100644 --- a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py +++ b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network, Denom @@ -10,10 +8,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -62,7 +60,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py index 31d9cf04..12b808c4 100644 --- a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py +++ b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -57,7 +55,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py index ca51d084..7a4d1197 100644 --- a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py +++ b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -53,7 +51,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py index 2f665919..5037c899 100644 --- a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py +++ b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -58,7 +56,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py index 3b12ab87..e20e54b9 100644 --- a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py +++ b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -60,7 +58,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/36_MsgRelayProviderPrices.py b/examples/chain_client/36_MsgRelayProviderPrices.py index a579fb6a..bd88d650 100644 --- a/examples/chain_client/36_MsgRelayProviderPrices.py +++ b/examples/chain_client/36_MsgRelayProviderPrices.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -53,7 +51,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/3_MsgCreateSpotLimitOrder.py b/examples/chain_client/3_MsgCreateSpotLimitOrder.py index 04cb0ffa..5501b01b 100644 --- a/examples/chain_client/3_MsgCreateSpotLimitOrder.py +++ b/examples/chain_client/3_MsgCreateSpotLimitOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -58,7 +56,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/40_MsgExecuteContract.py b/examples/chain_client/40_MsgExecuteContract.py index 4661f4b4..d3ab1dda 100644 --- a/examples/chain_client/40_MsgExecuteContract.py +++ b/examples/chain_client/40_MsgExecuteContract.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,11 +9,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/41_MsgCreateInsuranceFund.py b/examples/chain_client/41_MsgCreateInsuranceFund.py index 255419b0..1a511f05 100644 --- a/examples/chain_client/41_MsgCreateInsuranceFund.py +++ b/examples/chain_client/41_MsgCreateInsuranceFund.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -10,11 +8,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/42_MsgUnderwrite.py b/examples/chain_client/42_MsgUnderwrite.py index 49aa7313..d7d04fb3 100644 --- a/examples/chain_client/42_MsgUnderwrite.py +++ b/examples/chain_client/42_MsgUnderwrite.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -10,11 +8,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/43_MsgRequestRedemption.py b/examples/chain_client/43_MsgRequestRedemption.py index a37a774d..640a42d2 100644 --- a/examples/chain_client/43_MsgRequestRedemption.py +++ b/examples/chain_client/43_MsgRequestRedemption.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -10,11 +8,11 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client # set custom cookie location (optional) - defaults to current dir client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/4_MsgCreateSpotMarketOrder.py b/examples/chain_client/4_MsgCreateSpotMarketOrder.py index d851517c..0f234d0b 100644 --- a/examples/chain_client/4_MsgCreateSpotMarketOrder.py +++ b/examples/chain_client/4_MsgCreateSpotMarketOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -57,7 +55,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/5_MsgCancelSpotOrder.py b/examples/chain_client/5_MsgCancelSpotOrder.py index a347a54b..ced2467f 100644 --- a/examples/chain_client/5_MsgCancelSpotOrder.py +++ b/examples/chain_client/5_MsgCancelSpotOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py index f53667b3..5a3c3e36 100644 --- a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py +++ b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -59,7 +57,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py index a8d456d1..edcfb6c4 100644 --- a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py +++ b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account @@ -58,7 +56,7 @@ async def main() -> None: print(sim_res) return - sim_res_msg = ProtoMsgComposer.MsgResponses(sim_res, simulation=True) + sim_res_msg = composer.MsgResponses(sim_res, simulation=True) print("---Simulation Response---") print(sim_res_msg) diff --git a/examples/chain_client/8_MsgCancelDerivativeOrder.py b/examples/chain_client/8_MsgCancelDerivativeOrder.py index 7abbf16a..66afe95d 100644 --- a/examples/chain_client/8_MsgCancelDerivativeOrder.py +++ b/examples/chain_client/8_MsgCancelDerivativeOrder.py @@ -1,7 +1,5 @@ import asyncio -import logging -from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.constant import Network @@ -11,10 +9,10 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) # initialize grpc client client = AsyncClient(network, insecure=False) + composer = await client.composer() await client.sync_timeout_height() # load account diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 72019f69..e29bcbe9 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -1,5 +1,7 @@ import asyncio import time +from copy import deepcopy + import grpc import aiocron import datetime @@ -7,9 +9,12 @@ from http.cookies import SimpleCookie from typing import Dict, List, Optional, Tuple, Union -from .core.market import Market +from pyinjective.composer import Composer + +from . import constant +from .core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket from .core.token import Token -from .exceptions import NotFoundError, EmptyMsgError +from .exceptions import NotFoundError from .proto.cosmos.base.abci.v1beta1 import abci_pb2 as abci_type @@ -183,8 +188,37 @@ def __init__( self._tokens_and_markets_initialization_lock = asyncio.Lock() self._tokens: Optional[Dict[str, Token]] = None - self._spot_markets: Optional[Dict[str, Market]] = None - self._derivative_markets: Optional[Dict] + 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: + async with self._tokens_and_markets_initialization_lock: + if self._tokens is None: + await self._initialize_tokens_and_markets() + return deepcopy(self._tokens) + + async def all_spot_markets(self) -> Dict[str, SpotMarket]: + if self._spot_markets is None: + async with self._tokens_and_markets_initialization_lock: + if self._spot_markets is None: + await self._initialize_tokens_and_markets() + return deepcopy(self._spot_markets) + + async def all_derivative_markets(self) -> Dict[str, DerivativeMarket]: + if self._derivative_markets is None: + async with self._tokens_and_markets_initialization_lock: + if self._derivative_markets is None: + await self._initialize_tokens_and_markets() + return deepcopy(self._derivative_markets) + + async def all_binary_option_markets(self) -> Dict[str, BinaryOptionMarket]: + if self._binary_option_markets is None: + async with self._tokens_and_markets_initialization_lock: + if self._binary_option_markets is None: + await self._initialize_tokens_and_markets() + return deepcopy(self._binary_option_markets) def get_sequence(self): current_seq = self.sequence @@ -1022,50 +1056,120 @@ async def stream_account_portfolio(self, account_address: str, **kwargs): metadata = await self.load_cookie(type="exchange") return self.stubPortfolio.StreamAccountPortfolio.__call__(req, metadata=metadata) + async def composer(self): + return Composer( + network=self.network.string(), + spot_markets=await self.all_spot_markets(), + derivative_markets=await self.all_derivative_markets(), + binary_option_markets=await self.all_binary_option_markets(), + tokens=await self.all_tokens(), + ) + async def _initialize_tokens_and_markets(self): - markets = dict() + spot_markets = dict() + derivative_markets = dict() + binary_option_markets = dict() tokens = dict() + tokens_by_denom = dict() markets_info = (await self.get_spot_markets()).markets for market_info in markets_info: - base_token = tokens.get(market_info.base_token.symbol) + base_token_symbol, quote_token_symbol = market_info.ticker.split(constant.TICKER_TOKENS_SEPARATOR) + base_token = tokens.get(base_token_symbol, None) if base_token is None: base_token = Token( - name=market_info.base_token.name, - symbol=market_info.base_token.symbol, - decimals=market_info.base_token.decimals, - logo=market_info.base_token.logo, + name=market_info.base_token_meta.name, + symbol=base_token_symbol, + denom=market_info.base_denom, + address=market_info.base_token_meta.address, + decimals=market_info.base_token_meta.decimals, + logo=market_info.base_token_meta.logo, + updated=market_info.base_token_meta.updated_at, ) - tokens[base_token.symbol] = base_token - base_token.add_source( - denom=market_info.base_denom, - symbol=market_info.base_token.symbol, - address=market_info.base_token.address, - decimals=market_info.base_token.decimals, - updated=market_info.base_token.updated_at, + tokens[base_token_symbol] = base_token + tokens_by_denom[base_token.denom] = base_token + + quote_token = tokens.get(quote_token_symbol, None) + if quote_token is None: + quote_token = Token( + name=market_info.quote_token_meta.name, + symbol=quote_token_symbol, + denom=market_info.quote_denom, + address=market_info.quote_token_meta.address, + decimals=market_info.quote_token_meta.decimals, + logo=market_info.quote_token_meta.logo, + updated=market_info.quote_token_meta.updated_at, + ) + tokens[quote_token_symbol] = quote_token + tokens_by_denom[quote_token.denom] = quote_token + + market = SpotMarket( + id=market_info.market_id, + status=market_info.market_status, + ticker=market_info.ticker, + base_token=base_token, + quote_token=quote_token, + maker_fee_rate=Decimal(market_info.maker_fee_rate), + taker_fee_rate=Decimal(market_info.taker_fee_rate), + service_provider_fee=Decimal(market_info.service_provider_fee), + min_price_tick_size=Decimal(market_info.min_price_tick_size), + min_quantity_tick_size=Decimal(market_info.min_quantity_tick_size), ) - quote_token = tokens.get(market_info.base_token.symbol) + spot_markets[market.id] = market + + markets_info = (await self.get_derivative_markets()).markets + for market_info in markets_info: + quote_token_symbol = market_info.quote_token_meta.symbol + + quote_token = tokens.get(quote_token_symbol, None) if quote_token is None: quote_token = Token( - name=market_info.quote_token.name, - symbol=market_info.quote_token.symbol, - decimals=market_info.quote_token.decimals, - logo=market_info.quote_token.logo, + name=market_info.quote_token_meta.name, + symbol=quote_token_symbol, + denom=market_info.quote_denom, + address=market_info.quote_token_meta.address, + decimals=market_info.quote_token_meta.decimals, + logo=market_info.quote_token_meta.logo, + updated=market_info.quote_token_meta.updated_at, ) - quote_token.add_source( - denom=market_info.quote_denom, - symbol=market_info.quote_token.symbol, - address=market_info.quote_token.address, - decimals=market_info.quote_token.decimals, - updated=market_info.quote_token.updated_at, + tokens[quote_token_symbol] = quote_token + tokens_by_denom[quote_token.denom] = quote_token + + market = DerivativeMarket( + id=market_info.market_id, + status=market_info.market_status, + ticker=market_info.ticker, + oracle_base=market_info.oracle_base, + oracle_quote=market_info.oracle_quote, + oracle_type=market_info.oracle_type, + oracle_scale_factor=market_info.oracle_scale_factor, + initial_margin_ratio=Decimal(market_info.initial_margin_ratio), + maintenance_margin_ratio=Decimal(market_info.maintenance_margin_ratio), + quote_token=quote_token, + maker_fee_rate=Decimal(market_info.maker_fee_rate), + taker_fee_rate = Decimal(market_info.taker_fee_rate), + service_provider_fee = Decimal(market_info.service_provider_fee), + min_price_tick_size = Decimal(market_info.min_price_tick_size), + min_quantity_tick_size = Decimal(market_info.min_quantity_tick_size), ) - market = Market( + derivative_markets[market.id] = market + + markets_info = (await self.get_binary_options_markets()).markets + for market_info in markets_info: + quote_token = tokens_by_denom.get(market_info.quote_denom, None) + + market = BinaryOptionMarket( id=market_info.market_id, status=market_info.market_status, ticker=market_info.ticker, - base_token=base_token, + oracle_symbol=market_info.oracle_symbol, + oracle_provider=market_info.oracle_provider, + oracle_type=market_info.oracle_type, + oracle_scale_factor=market_info.oracle_scale_factor, + expiration_timestamp=market_info.expiration_timestamp, + settlement_timestamp=market_info.settlement_timestamp, quote_token=quote_token, maker_fee_rate=Decimal(market_info.maker_fee_rate), taker_fee_rate=Decimal(market_info.taker_fee_rate), @@ -1074,4 +1178,9 @@ async def _initialize_tokens_and_markets(self): min_quantity_tick_size=Decimal(market_info.min_quantity_tick_size), ) - markets[market.id] = market + binary_option_markets[market.id] = market + + self._tokens = tokens + self._spot_markets = spot_markets + self._derivative_markets = derivative_markets + self._binary_option_markets = binary_option_markets diff --git a/pyinjective/client.py b/pyinjective/client.py index 662d9840..10b82329 100644 --- a/pyinjective/client.py +++ b/pyinjective/client.py @@ -6,7 +6,7 @@ from http.cookies import SimpleCookie from typing import List, Optional, Tuple, Union -from .exceptions import NotFoundError, EmptyMsgError +from .exceptions import NotFoundError from .proto.cosmos.base.abci.v1beta1 import abci_pb2 as abci_type diff --git a/pyinjective/composer.py b/pyinjective/composer.py index b7f09bb7..bbb9bcbf 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -1,9 +1,11 @@ +from configparser import ConfigParser +from decimal import Decimal from time import time -import json -import logging -from google.protobuf import any_pb2, message, timestamp_pb2 +from google.protobuf import any_pb2, timestamp_pb2 +from .core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from .core.token import Token from .proto.cosmos.authz.v1beta1 import authz_pb2 as cosmos_authz_pb from .proto.cosmos.authz.v1beta1 import tx_pb2 as cosmos_authz_tx_pb @@ -33,16 +35,47 @@ from .proto.cosmwasm.wasm.v1 import tx_pb2 as wasm_tx_pb -from .constant import Denom -from .utils.utils import * -from typing import List +from .constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS, INJ_DENOM +from typing import Dict, List, Optional -from pyinjective.utils.logger import LoggerProvider +from pyinjective import constant class Composer: - def __init__(self, network: str): + def __init__( + self, + network: str, + spot_markets: Optional[Dict[str, SpotMarket]] = None, + derivative_markets: Optional[Dict[str, DerivativeMarket]] = None, + binary_option_markets: Optional[Dict[str, BinaryOptionMarket]] = None, + tokens: Optional[Dict[str, Token]] = None): + """ Composer is used to create the requests to send to the nodes using the Client + + :param network: the name of the network to use (mainnet, testnet, devnet) + :type network: str + + :param spot_markets: a dictionary containing all spot markets + :type spot_markets: Dictionary + + :param derivative_markets: a dictionary containing all derivative markets + :type derivative_markets: Dictionary + + :param binary_option_markets: a dictionary containing all derivative markets + :type binary_option_markets: Dictionary + + :param tokens: a dictionary with all the possible tokens + :type tokens: Dictionary + + + """ self.network = network + if spot_markets is None or derivative_markets is None or binary_option_markets is None or tokens is None: + self._initialize_markets_and_tokens_from_files() + else: + self.spot_markets = spot_markets + self.derivative_markets = derivative_markets + self.binary_option_markets = binary_option_markets + self.tokens = tokens def Coin(self, amount: int, denom: str): return cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin(amount=str(amount), denom=denom) @@ -92,15 +125,12 @@ def SpotOrder( quantity: float, **kwargs, ): - # load denom metadata - denom = Denom.load_market(self.network, market_id) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded market metadata for: {denom.description}") + market = self.spot_markets[market_id] # prepare values - quantity = spot_quantity_to_backend(quantity, denom) - price = spot_price_to_backend(price, denom) - trigger_price = spot_price_to_backend(0, denom) + quantity = market.quantity_to_chain_format(human_readable_value=Decimal(str(quantity))) + price = market.price_to_chain_format(human_readable_value=Decimal(str(price))) + trigger_price = market.price_to_chain_format(human_readable_value=Decimal(0)) if kwargs.get("is_buy") and not kwargs.get("is_po"): order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY @@ -119,11 +149,11 @@ def SpotOrder( order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=str(price), - quantity=str(quantity), + price=str(int(price)), + quantity=str(int(quantity)), ), order_type=order_type, - trigger_price=str(trigger_price), + trigger_price=str(int(trigger_price)), ) def DerivativeOrder( @@ -136,26 +166,21 @@ def DerivativeOrder( trigger_price: float = 0, **kwargs, ): - # load denom metadata - denom = Denom.load_market(self.network, market_id) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded market metadata for: {denom.description}") - - if kwargs.get("is_reduce_only") is None: - margin = derivative_margin_to_backend( - price, quantity, kwargs.get("leverage"), denom - ) - elif kwargs.get("is_reduce_only", True): + market = self.derivative_markets[market_id] + + if kwargs.get("is_reduce_only", False): margin = 0 else: - margin = derivative_margin_to_backend( - price, quantity, kwargs.get("leverage"), denom + margin = market.calculate_margin_in_chain_format( + human_readable_quantity=Decimal(str(quantity)), + human_readable_price=Decimal(str(price)), + leverage=Decimal(str(kwargs["leverage"])), ) # prepare values - price = derivative_price_to_backend(price, denom) - trigger_price = derivative_price_to_backend(trigger_price, denom) - quantity = derivative_quantity_to_backend(quantity, denom) + quantity = market.quantity_to_chain_format(human_readable_value=Decimal(str(quantity))) + price = market.price_to_chain_format(human_readable_value=Decimal(str(price))) + trigger_price = market.price_to_chain_format(human_readable_value=Decimal(str(trigger_price))) if kwargs.get("is_buy") and not kwargs.get("is_po"): order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY @@ -186,12 +211,12 @@ def DerivativeOrder( order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=str(price), - quantity=str(quantity), + price=str(int(price)), + quantity=str(int(quantity)), ), - margin=str(margin), + margin=str(int(margin)), order_type=order_type, - trigger_price=str(trigger_price), + trigger_price=str(int(trigger_price)), ) def BinaryOptionsOrder( @@ -204,30 +229,23 @@ def BinaryOptionsOrder( **kwargs, ): - if "denom" in kwargs: - denom = kwargs.get("denom") - else: - denom = Denom.load_market(self.network, market_id) - - # load denom metadata - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded market metadata for: {denom.description}") - - if kwargs.get("is_reduce_only") is None and kwargs.get("is_buy"): - margin = binary_options_buy_margin_to_backend(price, quantity, denom) - elif kwargs.get("is_reduce_only") is None and not kwargs.get("is_buy"): - margin = binary_options_sell_margin_to_backend(price, quantity, denom) - elif kwargs.get("is_reduce_only") is False and kwargs.get("is_buy"): - margin = binary_options_buy_margin_to_backend(price, quantity, denom) - elif kwargs.get("is_reduce_only") is False and not kwargs.get("is_buy"): - margin = binary_options_sell_margin_to_backend(price, quantity, denom) - elif kwargs.get("is_reduce_only", True): + market = self.binary_option_markets[market_id] + denom = kwargs.get("denom", None) + + if kwargs.get("is_reduce_only", False): margin = 0 + else: + margin = market.calculate_margin_in_chain_format( + human_readable_quantity=Decimal(str(quantity)), + human_readable_price=Decimal(str(price)), + is_buy=kwargs["is_buy"], + special_denom=denom, + ) # prepare values - price = binary_options_price_to_backend(price, denom) - trigger_price = binary_options_price_to_backend(0, denom) - quantity = binary_options_quantity_to_backend(quantity, denom) + price = market.price_to_chain_format(human_readable_value=Decimal(str(price)), special_denom=denom) + trigger_price = market.price_to_chain_format(human_readable_value=Decimal(str(0)), special_denom=denom) + quantity = market.quantity_to_chain_format(human_readable_value=Decimal(str(quantity)), special_denom=denom) if kwargs.get("is_buy") and not kwargs.get("is_po"): order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY @@ -246,25 +264,22 @@ def BinaryOptionsOrder( order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=str(price), - quantity=str(quantity), + price=str(int(price)), + quantity=str(int(quantity)), ), - margin=str(margin), + margin=str(int(margin)), order_type=order_type, - trigger_price=str(trigger_price), + trigger_price=str(int(trigger_price)), ) def MsgSend(self, from_address: str, to_address: str, amount: float, denom: str): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded send symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return cosmos_bank_tx_pb.MsgSend( from_address=from_address, to_address=to_address, - amount=[self.Coin(amount=be_amount, denom=peggy_denom)], + amount=[self.Coin(amount=int(be_amount), denom=token.denom)], ) def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): @@ -276,16 +291,13 @@ def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): ) def MsgDeposit(self, sender: str, subaccount_id: str, amount: float, denom: str): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded deposit symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return injective_exchange_tx_pb.MsgDeposit( sender=sender, subaccount_id=subaccount_id, - amount=self.Coin(amount=be_amount, denom=peggy_denom), + amount=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgCreateSpotLimitOrder( @@ -608,14 +620,15 @@ def MsgIncreasePositionMargin( market_id: str, amount: float, ): - denom = Denom.load_market(self.network, market_id) - additional_margin = derivative_additional_margin_to_backend(amount, denom) + market = self.derivative_markets[market_id] + + additional_margin = market.margin_to_chain_format(human_readable_value=Decimal(str(amount))) return injective_exchange_tx_pb.MsgIncreasePositionMargin( sender=sender, source_subaccount_id=source_subaccount_id, destination_subaccount_id=destination_subaccount_id, market_id=market_id, - amount=str(additional_margin), + amount=str(int(additional_margin)), ) def MsgSubaccountTransfer( @@ -635,16 +648,13 @@ def MsgSubaccountTransfer( ) def MsgWithdraw(self, sender: str, subaccount_id: str, amount: float, denom: str): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded withdrawal symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return injective_exchange_tx_pb.MsgWithdraw( sender=sender, subaccount_id=subaccount_id, - amount=self.Coin(amount=be_amount, denom=peggy_denom), + amount=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgExternalTransfer( @@ -655,27 +665,24 @@ def MsgExternalTransfer( amount: int, denom: str, ): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded send symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return injective_exchange_tx_pb.MsgExternalTransfer( sender=sender, source_subaccount_id=source_subaccount_id, destination_subaccount_id=destination_subaccount_id, - amount=self.Coin(amount=be_amount, denom=peggy_denom), + amount=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgBid(self, sender: str, bid_amount: float, round: float): - be_amount = amount_to_backend(bid_amount, 18) + be_amount = Decimal(str(bid_amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") return injective_auction_tx_pb.MsgBid( sender=sender, round=round, - bid_amount=self.Coin(amount=be_amount, denom="inj"), + bid_amount=self.Coin(amount=int(be_amount), denom=INJ_DENOM), ) def MsgGrantGeneric( @@ -788,31 +795,27 @@ def MsgRelayPriceFeedPrice( def MsgSendToEth( self, denom: str, sender: str, eth_dest: str, amount: float, bridge_fee: float ): - - peggy_denom, decimals = Denom.load_peggy_denom(self.network, denom) - be_amount = amount_to_backend(amount, decimals) - be_bridge_fee = amount_to_backend(bridge_fee, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded withdrawal symbol {denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) + be_bridge_fee = token.chain_formatted_value(human_readable_value=Decimal(str(bridge_fee))) return injective_peggy_tx_pb.MsgSendToEth( sender=sender, eth_dest=eth_dest, - amount=self.Coin(amount=be_amount, denom=peggy_denom), - bridge_fee=self.Coin(amount=be_bridge_fee, denom=peggy_denom), + amount=self.Coin(amount=int(be_amount), denom=token.denom), + bridge_fee=self.Coin(amount=int(be_bridge_fee), denom=token.denom), ) def MsgDelegate( self, delegator_address: str, validator_address: str, amount: float ): - be_amount = amount_to_backend(amount, 18) + be_amount = Decimal(str(amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") return cosmos_staking_tx_pb.MsgDelegate( delegator_address=delegator_address, validator_address=validator_address, - amount=self.Coin(amount=be_amount, denom="inj"), + amount=self.Coin(amount=int(be_amount), denom=INJ_DENOM), ) def MsgCreateInsuranceFund( @@ -826,15 +829,18 @@ def MsgCreateInsuranceFund( expiry: int, initial_deposit: int ): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, quote_denom) - be_amount = amount_to_backend(initial_deposit, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded send symbol {quote_denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[quote_denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(initial_deposit))) return injective_insurance_tx_pb.MsgCreateInsuranceFund( - sender=sender, ticker=ticker, quote_denom=peggy_denom, oracle_base=oracle_base, oracle_quote=oracle_quote, - oracle_type=oracle_type, expiry=expiry, initial_deposit=self.Coin(amount=be_amount, denom=peggy_denom), + sender=sender, + ticker=ticker, + quote_denom=token.denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_type=oracle_type, + expiry=expiry, + initial_deposit=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgUnderwrite( @@ -844,14 +850,11 @@ def MsgUnderwrite( quote_denom: str, amount: int, ): - peggy_denom, decimals = Denom.load_peggy_denom(self.network, quote_denom) - be_amount = amount_to_backend(amount, decimals) - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"Loaded send symbol {quote_denom} ({peggy_denom}) with decimals = {decimals}" - ) + token = self.tokens[quote_denom] + be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) return injective_insurance_tx_pb.MsgUnderwrite( - sender=sender, market_id=market_id, deposit=self.Coin(amount=be_amount, denom=peggy_denom), + sender=sender, market_id=market_id, deposit=self.Coin(amount=int(be_amount), denom=token.denom), ) def MsgRequestRedemption( @@ -958,3 +961,85 @@ def UnpackMsgExecResponse(msg_type, data): responses = [header_map[msg_type].FromString(result) for result in data.results] return responses + + def _initialize_markets_and_tokens_from_files(self): + config: ConfigParser = constant.CONFIGS[self.network] + spot_markets = dict() + derivative_markets = dict() + tokens = dict() + + for section_name, configuration_section in config.items(): + if section_name.startswith("0x"): + description = configuration_section["description"] + + quote_token = Token( + name="", + symbol="", + denom="", + address="", + decimals=int(configuration_section["quote"]), + logo="", + updated=-1, + ) + + if "Spot" in description: + base_token = Token( + name="", + symbol="", + denom="", + address="", + decimals=int(configuration_section["base"]), + logo="", + updated=-1, + ) + + market = SpotMarket( + id=section_name, + status="", + ticker=description, + base_token=base_token, + quote_token=quote_token, + maker_fee_rate=None, + taker_fee_rate=None, + service_provider_fee=None, + min_price_tick_size=Decimal(str(configuration_section["min_price_tick_size"])), + min_quantity_tick_size=Decimal(str(configuration_section["min_quantity_tick_size"])) + ) + spot_markets[description] = market + else: + market = DerivativeMarket( + id=section_name, + status="", + ticker=description, + oracle_base="", + oracle_quote="", + oracle_type="", + oracle_scale_factor=1, + initial_margin_ratio=None, + maintenance_margin_ratio=None, + quote_token=quote_token, + maker_fee_rate=None, + taker_fee_rate=None, + service_provider_fee=None, + min_price_tick_size=Decimal(str(configuration_section["min_price_tick_size"])), + min_quantity_tick_size=Decimal(str(configuration_section["min_quantity_tick_size"])), + ) + + derivative_markets[description] = market + + elif section_name != "DEFAULT": + token = Token( + name=section_name, + symbol=section_name, + denom=configuration_section["peggy_denom"], + address="", + decimals=int(configuration_section["decimals"]), + logo="", + updated=-1, + ) + + tokens[token.symbol] = Token + + self.tokens = tokens + self.spot_markets = spot_markets + self.derivative_markets = derivative_markets diff --git a/pyinjective/constant.py b/pyinjective/constant.py index 72bbf2ec..0774e4b3 100644 --- a/pyinjective/constant.py +++ b/pyinjective/constant.py @@ -1,9 +1,13 @@ import os from configparser import ConfigParser +from warnings import warn MAX_CLIENT_ID_LENGTH = 128 MAX_DATA_SIZE = 256 MAX_MEMO_CHARACTERS = 256 +ADDITIONAL_CHAIN_FORMAT_DECIMALS = 18 +TICKER_TOKENS_SEPARATOR = "/" +INJ_DENOM = "inj" devnet_config = ConfigParser() devnet_config.read(os.path.join(os.path.dirname(__file__), 'denoms_devnet.ini')) @@ -14,6 +18,13 @@ mainnet_config = ConfigParser() mainnet_config.read(os.path.join(os.path.dirname(__file__), 'denoms_mainnet.ini')) +CONFIGS = { + "devnet": devnet_config, + "testnet": testnet_config, + "mainnet": mainnet_config, +} + + class Denom: def __init__( self, @@ -23,6 +34,9 @@ def __init__( min_price_tick_size: float, min_quantity_tick_size: float ): + """This throws a deprecation warning on initialization.""" + warn(f'{self.__class__.__name__} will be deprecated.', DeprecationWarning, stacklevel=2) + self.description = description self.base = base self.quote = quote diff --git a/pyinjective/core/market.py b/pyinjective/core/market.py index c17ce795..d28ba462 100644 --- a/pyinjective/core/market.py +++ b/pyinjective/core/market.py @@ -1,11 +1,13 @@ from dataclasses import dataclass from decimal import Decimal +from typing import Optional +from constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS, Denom from pyinjective.core.token import Token @dataclass -class Market: +class SpotMarket: id: str status: str ticker: str @@ -15,4 +17,135 @@ class Market: taker_fee_rate: Decimal service_provider_fee: Decimal min_price_tick_size: Decimal - min_quantity_tick_size: Decimal \ No newline at end of file + min_quantity_tick_size: Decimal + + def quantity_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + chain_formatted_value = human_readable_value * Decimal(f"1e{self.base_token.decimals}") + quantized_value = chain_formatted_value // self.min_quantity_tick_size * self.min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def price_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + decimals = self.quote_token.decimals - self.base_token.decimals + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // self.min_price_tick_size) * self.min_price_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + +@dataclass +class DerivativeMarket: + id: str + status: str + ticker: str + oracle_base: str + oracle_quote: str + oracle_type: str + oracle_scale_factor: int + initial_margin_ratio: Decimal + maintenance_margin_ratio: Decimal + quote_token: Token + maker_fee_rate: Decimal + taker_fee_rate: Decimal + service_provider_fee: Decimal + min_price_tick_size: Decimal + min_quantity_tick_size: Decimal + + def quantity_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + # Derivative markets do not have a base market to provide the number of decimals + chain_formatted_value = human_readable_value + quantized_value = chain_formatted_value // self.min_quantity_tick_size * self.min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def price_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + decimals = self.quote_token.decimals + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // self.min_price_tick_size) * self.min_price_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def margin_to_chain_format(self, human_readable_value: Decimal) -> Decimal: + decimals = self.quote_token.decimals + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // self.min_quantity_tick_size) * self.min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def calculate_margin_in_chain_format( + self, + human_readable_quantity: Decimal, + human_readable_price: Decimal, + leverage: Decimal + ) -> Decimal: + chain_formatted_quantity = human_readable_quantity + chain_formatted_price = human_readable_price * Decimal(f"1e{self.quote_token.decimals}") + margin = (chain_formatted_price * chain_formatted_quantity) / leverage + # We are using the min_quantity_tick_size to quantize the margin because that is the way margin is validated + # in the chain (it might be changed to a min_notional in the future) + quantized_margin = (margin // self.min_quantity_tick_size) * self.min_quantity_tick_size + extended_chain_formatted_margin = quantized_margin * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_margin + +@dataclass +class BinaryOptionMarket: + id: str + status: str + ticker: str + oracle_symbol: str + oracle_provider: str + oracle_type: str + oracle_scale_factor: int + expiration_timestamp: int + settlement_timestamp: int + quote_token: Token + maker_fee_rate: Decimal + taker_fee_rate: Decimal + service_provider_fee: Decimal + min_price_tick_size: Decimal + min_quantity_tick_size: Decimal + + def quantity_to_chain_format(self, human_readable_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal: + # Binary option markets do not have a base market to provide the number of decimals + decimals = 0 if special_denom is None else special_denom.base + min_quantity_tick_size = self.min_quantity_tick_size if special_denom is None else special_denom.min_quantity_tick_size + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = chain_formatted_value // min_quantity_tick_size * min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def price_to_chain_format(self, human_readable_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal: + decimals = self.quote_token.decimals if special_denom is None else special_denom.quote + min_price_tick_size = self.min_price_tick_size if special_denom is None else special_denom.min_price_tick_size + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // min_price_tick_size) * min_price_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + + def calculate_margin_in_chain_format( + self, + human_readable_quantity: Decimal, + human_readable_price: Decimal, + is_buy: bool, + special_denom: Optional[Denom] = None, + ) -> Decimal: + quantity_decimals = 0 if special_denom is None else special_denom.base + price_decimals = self.quote_token.decimals if special_denom is None else special_denom.quote + min_quantity_tick_size = self.min_quantity_tick_size if special_denom is None else special_denom.min_quantity_tick_size + price = human_readable_price if is_buy else 1 - human_readable_price + chain_formatted_quantity = human_readable_quantity * Decimal(f"1e{quantity_decimals}") + chain_formatted_price = price * Decimal(f"1e{price_decimals}") + margin = (chain_formatted_price * chain_formatted_quantity) + # We are using the min_quantity_tick_size to quantize the margin because that is the way margin is validated + # in the chain (it might be changed to a min_notional in the future) + quantized_margin = (margin // min_quantity_tick_size) * min_quantity_tick_size + extended_chain_formatted_margin = quantized_margin * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_margin \ No newline at end of file diff --git a/pyinjective/core/token.py b/pyinjective/core/token.py index c80d8e89..59bac41e 100644 --- a/pyinjective/core/token.py +++ b/pyinjective/core/token.py @@ -1,21 +1,4 @@ -from typing import Dict - - -class TokenSource: - - def __init__( - self, - denom: str, - symbol: str, - address: str, - decimals: int, - updated: int, - ): - self.denom = denom - self.symbol = symbol - self.address = address - self.decimals = decimals - self.updated = updated +from decimal import Decimal class Token: @@ -24,23 +7,19 @@ def __init__( self, name: str, symbol: str, + denom: str, + address: str, decimals: int, logo: str, + updated: int, ): self.name = name self.symbol = symbol + self.denom = denom + self.address = address self.decimals = decimals self.logo = logo + self.updated = updated - self._sources = Dict[str, TokenSource] - - def add_source(self, denom: str, symbol: str, address: str, decimals: int, updated: int): - if denom not in self._sources: - token_source = TokenSource( - denom=denom, - symbol=symbol, - address=address, - decimals=decimals, - updated=updated, - ) - self._sources[denom] = token_source \ No newline at end of file + def chain_formatted_value(self, human_readable_value: Decimal) -> Decimal: + return human_readable_value * Decimal(f"1e{self.decimals}") diff --git a/pyinjective/utils/utils.py b/pyinjective/utils/utils.py deleted file mode 100644 index 61a02472..00000000 --- a/pyinjective/utils/utils.py +++ /dev/null @@ -1,108 +0,0 @@ -from decimal import Decimal -from math import floor -from typing import Union - -""" -One thing you may need to pay more attention to is how to deal with decimals on the Injective Exchange. -Different cryptocurrencies may require different decimal precisions. More specifically, ERC-20 tokens(e.g. INJ) have 18 decimals whereas USDT/USC have 6 decimals. -So in our system that means ** having 1 INJ is 1e18 inj ** and that ** 1 USDT is actually 100000 peggy0xdac17f958d2ee523a2206206994597c13d831ec7**. - -For spot markets, a price reflects the ** relative exchange rate ** between two tokens. -If the tokens have the same decimal scale, that's great since the prices become interpretable e.g. USDT/USDC (both have 6 decimals e.g. for USDT https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#readContract) -or MATIC/INJ (both have 18 decimals) since the decimals cancel out. -Prices however start to look wonky once you have exchanges between two tokens of different decimals, which unfortunately is most pairs with USDT or USDC denominations e.g. INJ/USDT. -As such, I've created some simple utility functions by keeping a hardcoded dictionary in injective-py and you can also achieve such utilities by yourself -(e.g. you can use external API like Alchemy's getTokenMetadata to fetch decimal of base and quote asset). - -So for INJ/USDT of 6.9, the price you end up getting is 6.9*10 ^ (6 - 18) = 6.9e-12. Note that this market also happens to have a MinPriceTickSize of 1e-15. -This makes sense since since it's defining th3e minimum price increment of the relative exchange of INJ to USDT. - -Note that this market also happens to have a MinQuantityTickSize of 1e15. -This also makes sense since it refers to the minimum INJ quantity tick size each order must have, which is 1e15/1e18 = 0.001 INJ. - -""" - -def spot_price_to_backend(price, denom) -> int: - price_tick_size = denom.min_price_tick_size - scale_price = Decimal(18 + denom.quote - denom.base) - exchange_price = floor_to(price, price_tick_size) * pow(Decimal(10), scale_price) - return int(exchange_price) - -def spot_quantity_to_backend(quantity, denom) -> int: - quantity_tick_size = float(denom.min_quantity_tick_size) / pow(10, denom.base) - scale_quantity = Decimal(18 + denom.base) - exchange_quantity = floor_to(quantity, quantity_tick_size) * pow(Decimal(10), scale_quantity) - return int(exchange_quantity) - -def derivative_price_to_backend(price, denom) -> int: - price_tick_size = Decimal(denom.min_price_tick_size) / pow(10, denom.quote) - exchange_price = floor_to(price, float(price_tick_size)) * pow(10, 18 + denom.quote) - return int(exchange_price) - -def binary_options_price_to_backend(price, denom) -> int: - price_tick_size = Decimal(denom.min_price_tick_size) / pow(10, denom.quote) - exchange_price = floor_to(price, float(price_tick_size)) * pow(10, 18 + denom.quote) - return int(exchange_price) - -def derivative_quantity_to_backend(quantity, denom) -> int: - quantity_tick_size = float(denom.min_quantity_tick_size) / pow(10, denom.base) - scale_quantity = Decimal(18 + denom.base) - exchange_quantity = floor_to(quantity, quantity_tick_size) * pow(Decimal(10), scale_quantity) - return int(exchange_quantity) - -def binary_options_quantity_to_backend(quantity, denom) -> int: - quantity_tick_size = float(denom.min_quantity_tick_size) / pow(10, denom.base) - scale_quantity = Decimal(18 + denom.base) - exchange_quantity = floor_to(quantity, quantity_tick_size) * pow(Decimal(10), scale_quantity) - return int(exchange_quantity) - -def derivative_margin_to_backend(price, quantity, leverage, denom) -> int: - chain_format_price = Decimal(str(price)) * Decimal(f"1e{denom.quote}") - chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{denom.base}") - decimal_leverage = Decimal(str(leverage)) - margin = (chain_format_price * chain_format_quantity) / decimal_leverage - # We are using the min_quantity_tick_size to quantize the margin because that is the way margin is validated - # in the chain (it might be changed to a min_notional in the future) - exchange_margin = floor_to(margin, denom.min_quantity_tick_size) * Decimal(f"1e18") - return int(exchange_margin) - -def binary_options_buy_margin_to_backend(price, quantity, denom) -> int: - price_tick_size = Decimal(denom.min_price_tick_size) / pow(10, denom.quote) - margin = Decimal(str(price)) * Decimal(str(quantity)) - exchange_margin = floor_to(margin, float(price_tick_size)) * pow(10, 18 + denom.quote) - return int(exchange_margin) - -def binary_options_sell_margin_to_backend(price, quantity, denom) -> int: - price_tick_size = Decimal(denom.min_price_tick_size) / pow(10, denom.quote) - margin = (1 - (Decimal(str(price)))) * (Decimal(str(quantity))) - exchange_margin = floor_to(margin, float(price_tick_size)) * pow(10, 18 + denom.quote) - return int(exchange_margin) - -def derivative_additional_margin_to_backend(amount, denom) -> int: - price_tick_size = float(denom.min_price_tick_size) / pow(10, denom.quote) - additional_margin = floor_to(amount, price_tick_size) * pow(10, 18 + denom.quote) - return int(additional_margin) - -def amount_to_backend(amount, decimals) -> int: - be_amount = amount * pow(10, decimals) - return int(be_amount) - -def floor_to(value: Union[float, Decimal], target: Union[float, Decimal]) -> Decimal: - value_tmp = Decimal(str(value)) - target_tmp = Decimal(str(target)) - result = int(floor(value_tmp / target_tmp)) * target_tmp - return result - -def spot_price_from_backend(price, denom) -> float: - scale = float(denom.quote - denom.base) - return float(price) / pow(10, scale) - -def spot_quantity_from_backend(quantity, denom) -> Decimal: - scale = float(denom.base) - quantity_tick_size = float(denom.min_quantity_tick_size) / pow(10, scale) - quantity = float(quantity) / pow(10, scale) - return floor_to(quantity, quantity_tick_size) - -def derivative_price_from_backend(price, denom) -> float: - scale = float(denom.quote) - return float(price) / pow(10, scale) diff --git a/setup.py b/setup.py index cfd728b4..a7fb618f 100755 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ EMAIL = "achilleas@injectivelabs.com" AUTHOR = "Injective Labs" REQUIRES_PYTHON = ">=3.9" -VERSION = "0.6.4" +VERSION = "0.7-pre" REQUIRED = [ "aiohttp", diff --git a/tests/composer_tests.py b/tests/composer_tests.py deleted file mode 100644 index eabef128..00000000 --- a/tests/composer_tests.py +++ /dev/null @@ -1,183 +0,0 @@ -import logging - -import pytest - -from pyinjective.composer import Composer -from pyinjective.constant import Denom, Network - - -class TestComposer: - - @pytest.fixture - def inj_usdt_market_id(self): - return "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0" - - def test_spot_order_creation_logs_market_data_loaded_info(self, caplog, inj_usdt_market_id): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.SpotOrder( - market_id=inj_usdt_market_id, - subaccount_id="", - fee_recipient="", - price=1.0, - quantity=1.0, - ) - - expected_log_message_prefix = "Loaded market metadata for: 'Devnet Spot INJ/USDT'" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_derivative_order_creation_logs_market_data_loaded_info(self, caplog, inj_usdt_market_id): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.DerivativeOrder( - market_id=inj_usdt_market_id, - subaccount_id="", - fee_recipient="", - price=1.0, - quantity=1.0, - leverage=1.0, - ) - - expected_log_message_prefix = "Loaded market metadata for: 'Devnet Spot INJ/USDT'" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_binary_order_creation_logs_market_data_loaded_info(self, caplog, inj_usdt_market_id): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.BinaryOptionsOrder( - market_id=inj_usdt_market_id, - subaccount_id="", - fee_recipient="", - price=1.0, - quantity=1.0, - ) - - expected_log_message_prefix = "Loaded market metadata for: 'Devnet Spot INJ/USDT'" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_send_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgSend( - from_address="", - to_address="", - amount=1.0, - denom="INJ", - ) - - expected_log_message_prefix = f"Loaded send symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_deposit_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgDeposit( - sender="", - subaccount_id="", - amount=1.0, - denom="INJ", - ) - - expected_log_message_prefix = f"Loaded deposit symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_withdraw_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgWithdraw( - sender="", - subaccount_id="", - amount=1.0, - denom="INJ", - ) - - expected_log_message_prefix = f"Loaded withdrawal symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_external_transfer_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgExternalTransfer( - sender="", - source_subaccount_id="", - destination_subaccount_id="", - amount=1.0, - denom="INJ", - ) - - expected_log_message_prefix = f"Loaded send symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_send_to_eth_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgSendToEth( - denom="INJ", - sender="", - eth_dest="", - amount=1.0, - bridge_fee=1.0, - ) - - expected_log_message_prefix = f"Loaded withdrawal symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_create_insurance_fund_logs_market_data_loaded_info(self, caplog): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgCreateInsuranceFund( - sender="", - ticker="", - quote_denom="INJ", - oracle_base="", - oracle_quote="", - oracle_type=1, - expiry=1, - initial_deposit=1, - ) - - expected_log_message_prefix = f"Loaded send symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) - - def test_msg_underwrite_logs_market_data_loaded_info(self, caplog, inj_usdt_market_id): - caplog.set_level(logging.INFO) - - composer = Composer(network=Network.devnet().string()) - - composer.MsgUnderwrite( - sender="", - market_id=inj_usdt_market_id, - quote_denom="INJ", - amount=1, - ) - - expected_log_message_prefix = f"Loaded send symbol INJ (inj) with decimals = 18" - expected_log_record = ("pyinjective.composer.Composer", logging.INFO, expected_log_message_prefix) - assert(expected_log_record in caplog.record_tuples) diff --git a/tests/__init__.py b/tests/core/__init__.py similarity index 100% rename from tests/__init__.py rename to tests/core/__init__.py diff --git a/tests/core/test_market.py b/tests/core/test_market.py new file mode 100644 index 00000000..1038c51b --- /dev/null +++ b/tests/core/test_market.py @@ -0,0 +1,213 @@ +import pytest +from decimal import Decimal + +from pyinjective.constant import Denom + +from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from tests.model_fixtures.markets_fixtures import ( + first_match_bet_market, + inj_token, + usdt_token, + usdt_perp_token, + inj_usdt_spot_market, + btc_usdt_perp_market, +) + + +class TestSpotMarket: + + def test_convert_quantity_to_chain_format(self, inj_usdt_spot_market: SpotMarket): + original_quantity = Decimal("123.456789") + + chain_value = inj_usdt_spot_market.quantity_to_chain_format(human_readable_value=original_quantity) + expected_value = original_quantity * Decimal(f"1e{inj_usdt_spot_market.base_token.decimals}") + quantized_value = ((expected_value // inj_usdt_spot_market.min_quantity_tick_size) + * inj_usdt_spot_market.min_quantity_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_price_to_chain_format(self, inj_usdt_spot_market: SpotMarket): + original_quantity = Decimal("123.456789") + + chain_value = inj_usdt_spot_market.price_to_chain_format(human_readable_value=original_quantity) + price_decimals = inj_usdt_spot_market.quote_token.decimals - inj_usdt_spot_market.base_token.decimals + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ((expected_value // inj_usdt_spot_market.min_price_tick_size) + * inj_usdt_spot_market.min_price_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + +class TestDerivativeMarket: + + def test_convert_quantity_to_chain_format(self, btc_usdt_perp_market: DerivativeMarket): + original_quantity = Decimal("123.456789") + + chain_value = btc_usdt_perp_market.quantity_to_chain_format(human_readable_value=original_quantity) + quantized_value = ((original_quantity // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_price_to_chain_format(self, btc_usdt_perp_market: DerivativeMarket): + original_quantity = Decimal("123.456789") + + chain_value = btc_usdt_perp_market.price_to_chain_format(human_readable_value=original_quantity) + price_decimals = btc_usdt_perp_market.quote_token.decimals + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ((expected_value // btc_usdt_perp_market.min_price_tick_size) + * btc_usdt_perp_market.min_price_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_margin_to_chain_format(self, btc_usdt_perp_market: DerivativeMarket): + original_quantity = Decimal("123.456789") + + chain_value = btc_usdt_perp_market.margin_to_chain_format(human_readable_value=original_quantity) + margin_decimals = btc_usdt_perp_market.quote_token.decimals + expected_value = original_quantity * Decimal(f"1e{margin_decimals}") + quantized_value = ((expected_value // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + +class TestBinaryOptionMarket: + + def test_convert_quantity_to_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=4, + min_quantity_tick_size=100, + min_price_tick_size=10000, + ) + + chain_value = first_match_bet_market.quantity_to_chain_format( + human_readable_value=original_quantity, + special_denom=fixed_denom + ) + chain_formatted_quantity = original_quantity * Decimal(f"1e{fixed_denom.base}") + quantized_value = ((chain_formatted_quantity // Decimal(str(fixed_denom.min_quantity_tick_size))) + * Decimal(str(fixed_denom.min_quantity_tick_size))) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_quantity_to_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + + chain_value = first_match_bet_market.quantity_to_chain_format( + human_readable_value=original_quantity, + ) + quantized_value = ((original_quantity // first_match_bet_market.min_quantity_tick_size) + * first_match_bet_market.min_quantity_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_price_to_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=4, + min_quantity_tick_size=100, + min_price_tick_size=10000, + ) + + chain_value = first_match_bet_market.price_to_chain_format( + human_readable_value=original_quantity, + special_denom=fixed_denom, + ) + price_decimals = fixed_denom.quote + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ((expected_value // Decimal(str(fixed_denom.min_price_tick_size))) + * Decimal(str(fixed_denom.min_price_tick_size))) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_convert_price_to_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + + chain_value = first_match_bet_market.price_to_chain_format(human_readable_value=original_quantity) + price_decimals = first_match_bet_market.quote_token.decimals + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ((expected_value // first_match_bet_market.min_price_tick_size) + * first_match_bet_market.min_price_tick_size) + quantized_chain_format_value = quantized_value * Decimal(f"1e18") + + assert (quantized_chain_format_value == chain_value) + + def test_calculate_margin_for_buy_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + original_price = Decimal("0.6789") + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=4, + min_quantity_tick_size=100, + min_price_tick_size=10000, + ) + + chain_value = first_match_bet_market.calculate_margin_in_chain_format( + human_readable_quantity=original_quantity, + human_readable_price=original_price, + is_buy=True, + special_denom=fixed_denom, + ) + + quantity_decimals = fixed_denom.base + price_decimals = fixed_denom.quote + expected_quantity = original_quantity * Decimal(f"1e{quantity_decimals}") + expected_price = original_price * Decimal(f"1e{price_decimals}") + expected_margin = expected_quantity * expected_price + quantized_margin = ((expected_margin // Decimal(str(fixed_denom.min_quantity_tick_size))) + * Decimal(str(fixed_denom.min_quantity_tick_size))) + quantized_chain_format_margin = quantized_margin * Decimal(f"1e18") + + assert (quantized_chain_format_margin == chain_value) + + def test_calculate_margin_for_buy_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + original_price = Decimal("0.6789") + + chain_value = first_match_bet_market.calculate_margin_in_chain_format( + human_readable_quantity=original_quantity, + human_readable_price=original_price, + is_buy=True, + ) + + price_decimals = first_match_bet_market.quote_token.decimals + expected_price = original_price * Decimal(f"1e{price_decimals}") + expected_margin = original_quantity * expected_price + quantized_margin = ((expected_margin // Decimal(str(first_match_bet_market.min_quantity_tick_size))) + * Decimal(str(first_match_bet_market.min_quantity_tick_size))) + quantized_chain_format_margin = quantized_margin * Decimal(f"1e18") + + assert (quantized_chain_format_margin == chain_value) + + def test_calculate_margin_for_sell_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + original_price = Decimal("0.6789") + + chain_value = first_match_bet_market.calculate_margin_in_chain_format( + human_readable_quantity=original_quantity, + human_readable_price=original_price, + is_buy=False, + ) + + price_decimals = first_match_bet_market.quote_token.decimals + expected_price = (Decimal(1) - original_price) * Decimal(f"1e{price_decimals}") + expected_margin = original_quantity * expected_price + quantized_margin = ((expected_margin // Decimal(str(first_match_bet_market.min_quantity_tick_size))) + * Decimal(str(first_match_bet_market.min_quantity_tick_size))) + quantized_chain_format_margin = quantized_margin * Decimal(f"1e18") + + assert (quantized_chain_format_margin == chain_value) diff --git a/tests/core/test_token.py b/tests/core/test_token.py new file mode 100644 index 00000000..66cb6cd7 --- /dev/null +++ b/tests/core/test_token.py @@ -0,0 +1,15 @@ +import pytest +from decimal import Decimal + +from tests.model_fixtures.markets_fixtures import inj_token + + +class TestToken: + + def test_chain_formatted_value(self, inj_token): + value = Decimal("1.3456") + + chain_formatted_value = inj_token.chain_formatted_value(human_readable_value=value) + expected_value = value * Decimal(f"1e{inj_token.decimals}") + + assert (chain_formatted_value == expected_value) diff --git a/tests/model_fixtures/__init__.py b/tests/model_fixtures/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/model_fixtures/markets_fixtures.py b/tests/model_fixtures/markets_fixtures.py new file mode 100644 index 00000000..cca40680 --- /dev/null +++ b/tests/model_fixtures/markets_fixtures.py @@ -0,0 +1,113 @@ +import pytest +from decimal import Decimal + +from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from pyinjective.core.token import Token + + +@pytest.fixture +def inj_token(): + token = Token( + name="Injective Protocol", + symbol="INJ", + denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", + address="0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30", + decimals=18, + logo="https://static.alchemyapi.io/images/assets/7226.png", + updated=1681739137644, + ) + + return token + + +@pytest.fixture +def usdt_token(): + token = Token( + name="USDT", + symbol="USDT", + denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + address="0x0000000000000000000000000000000000000000", + decimals=6, + logo="https://static.alchemyapi.io/images/assets/825.png", + updated=1681739137645, + ) + + return token + + +@pytest.fixture +def usdt_perp_token(): + token = Token( + name="USDT PERP", + symbol="USDT", + denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7", + address="0xdAC17F958D2ee523a2206206994597C13D831ec7", + decimals=6, + logo="https://static.alchemyapi.io/images/assets/825.png", + updated=1681739137645, + ) + + return token + + +@pytest.fixture +def inj_usdt_spot_market(inj_token, usdt_token): + market = SpotMarket( + id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", + status="active", + ticker="INJ/USDT", + base_token=inj_token, + quote_token=usdt_token, + maker_fee_rate=Decimal("-0.0001"), + taker_fee_rate=Decimal("0.001"), + service_provider_fee=Decimal("0.4"), + min_price_tick_size=Decimal("0.000000000000001"), + min_quantity_tick_size=Decimal("1000000000000000"), + ) + + return market + + +@pytest.fixture +def btc_usdt_perp_market(usdt_perp_token): + market = DerivativeMarket( + id="0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce", + status="active", + ticker="BTC/USDT PERP", + oracle_base="BTC", + oracle_quote=usdt_perp_token.symbol, + oracle_type="bandibc", + oracle_scale_factor=6, + initial_margin_ratio=Decimal("0.095"), + maintenance_margin_ratio=Decimal("0.025"), + quote_token=usdt_perp_token, + maker_fee_rate=Decimal("-0.0001"), + taker_fee_rate=Decimal("0.001"), + service_provider_fee=Decimal("0.4"), + min_price_tick_size=Decimal("1000000"), + min_quantity_tick_size=Decimal("0.0001"), + ) + + return market + +@pytest.fixture +def first_match_bet_market(usdt_token): + market = BinaryOptionMarket( + id="0x230dcce315364ff6360097838701b14713e2f4007d704df20ed3d81d09eec957", + status="active", + ticker="5fdbe0b1-1707800399-WAS", + oracle_symbol="Frontrunner", + oracle_provider="Frontrunner", + oracle_type="provider", + oracle_scale_factor=6, + expiration_timestamp=1707800399, + settlement_timestamp=1707843599, + quote_token=usdt_token, + maker_fee_rate=Decimal("0"), + taker_fee_rate=Decimal("0"), + service_provider_fee=Decimal("0.4"), + min_price_tick_size=Decimal("10000"), + min_quantity_tick_size=Decimal("1"), + ) + + return market diff --git a/tests/rpc_fixtures/configurable_servicers.py b/tests/rpc_fixtures/configurable_servicers.py index dff625cf..136491ce 100644 --- a/tests/rpc_fixtures/configurable_servicers.py +++ b/tests/rpc_fixtures/configurable_servicers.py @@ -1,8 +1,11 @@ from collections import deque -from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import ( - MarketsRequest, - MarketsResponse, +import pytest +from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2_grpc import InjectiveDerivativeExchangeRPCServicer + +from pyinjective.proto.exchange import ( + injective_spot_exchange_rpc_pb2, + injective_derivative_exchange_rpc_pb2, ) from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import InjectiveSpotExchangeRPCServicer @@ -13,6 +16,23 @@ def __init__(self): super().__init__() self.markets_queue = deque() - def Markets(self, request: MarketsRequest, context): + async def Markets(self, request: injective_spot_exchange_rpc_pb2.MarketsRequest, context=None): + return self.markets_queue.pop() + + +class ConfigurableInjectiveDerivativeExchangeRPCServicer(InjectiveDerivativeExchangeRPCServicer): + + def __init__(self): + super().__init__() + self.markets_queue = deque() + self.binary_option_markets_queue = deque() + + async def Markets(self, request: injective_derivative_exchange_rpc_pb2.MarketsRequest, context=None): return self.markets_queue.pop() + async def BinaryOptionsMarkets( + self, + request: injective_derivative_exchange_rpc_pb2.BinaryOptionsMarketsRequest, + context=None + ): + return self.binary_option_markets_queue.pop() diff --git a/tests/rpc_fixtures/markets_fixtures.py b/tests/rpc_fixtures/markets_fixtures.py index c21cd755..2145e7ba 100644 --- a/tests/rpc_fixtures/markets_fixtures.py +++ b/tests/rpc_fixtures/markets_fixtures.py @@ -46,12 +46,29 @@ def usdt_token_meta(): return token + +@pytest.fixture +def usdt_perp_token_meta(): + from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2 import TokenMeta + + token = TokenMeta( + name="Tether", + address="0xdAC17F958D2ee523a2206206994597C13D831ec7", + symbol="USDTPerp", + logo="https://static.alchemyapi.io/images/assets/825.png", + decimals=6, + updated_at=1683929869866 + ) + + return token + + @pytest.fixture def ape_usdt_spot_market(ape_token_meta, usdt_token_meta): from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo - market_request = SpotMarketInfo( - market_id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", + market = SpotMarketInfo( + market_id="0x8b67e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e000", market_status="active", ticker="APE/USDT", base_denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", @@ -65,13 +82,13 @@ def ape_usdt_spot_market(ape_token_meta, usdt_token_meta): min_quantity_tick_size="1000000000000000", ) - return market_request + return market @pytest.fixture def inj_usdt_spot_market(inj_token_meta, usdt_token_meta): from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo - market_request = SpotMarketInfo( + market = SpotMarketInfo( market_id="0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0", market_status="active", ticker="INJ/USDT", @@ -86,4 +103,72 @@ def inj_usdt_spot_market(inj_token_meta, usdt_token_meta): min_quantity_tick_size="1000000000000000", ) - return market_request + return market + +@pytest.fixture +def btc_usdt_perp_market(usdt_perp_token_meta): + from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2 import ( + DerivativeMarketInfo, + PerpetualMarketInfo, + PerpetualMarketFunding, + ) + + perpetual_market_info = PerpetualMarketInfo( + hourly_funding_rate_cap="0.0000625", + hourly_interest_rate="0.00000416666", + next_funding_timestamp=1684764000, + funding_interval=3600, + ) + perpetual_market_funding = PerpetualMarketFunding( + cumulative_funding="6880500093.266083891331674194", + cumulative_price="-0.952642601240470199", + last_timestamp=1684763442, + ) + + market = DerivativeMarketInfo( + market_id="0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce", + market_status="active", + ticker="BTC/USDT PERP", + oracle_base="BTC", + oracle_quote="USDT", + oracle_type="bandibc", + oracle_scale_factor=6, + initial_margin_ratio="0.095", + maintenance_margin_ratio="0.025", + quote_denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7", + quote_token_meta=usdt_perp_token_meta, + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + service_provider_fee="0.4", + is_perpetual=True, + min_price_tick_size="1000000", + min_quantity_tick_size="0.0001", + perpetual_market_info=perpetual_market_info, + perpetual_market_funding=perpetual_market_funding, + ) + + return market + +@pytest.fixture +def first_match_bet_market(inj_usdt_spot_market): + from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2 import BinaryOptionsMarketInfo + + market = BinaryOptionsMarketInfo( + market_id="0x230dcce315364ff6360097838701b14713e2f4007d704df20ed3d81d09eec957", + market_status="active", + ticker="5fdbe0b1-1707800399-WAS", + oracle_symbol="Frontrunner", + oracle_provider="Frontrunner", + oracle_type="provider", + oracle_scale_factor=6, + expiration_timestamp=1707800399, + settlement_timestamp=1707843599, + quote_denom=inj_usdt_spot_market.quote_denom, + maker_fee_rate="0", + taker_fee_rate="0", + service_provider_fee="0.4", + min_price_tick_size="10000", + min_quantity_tick_size="1", + ) + + return market \ No newline at end of file diff --git a/tests/async_client_tests.py b/tests/test_async_client.py similarity index 55% rename from tests/async_client_tests.py rename to tests/test_async_client.py index 3c2995ba..97532a43 100644 --- a/tests/async_client_tests.py +++ b/tests/test_async_client.py @@ -4,33 +4,33 @@ from pyinjective.constant import Network from pyinjective.async_client import AsyncClient -from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import ( - MarketRequest, - MarketsRequest, - MarketResponse, - MarketsResponse, +from pyinjective.proto.exchange import ( + injective_spot_exchange_rpc_pb2, + injective_derivative_exchange_rpc_pb2, ) -from tests.rpc_fixtures.markets_fixtures import inj_token_meta, ape_token_meta, usdt_token_meta, inj_usdt_spot_market, ape_usdt_spot_market - -@pytest.fixture(scope='module') -def grpc_add_to_server(): - from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import add_InjectiveSpotExchangeRPCServicer_to_server - - return add_InjectiveSpotExchangeRPCServicer_to_server - +from tests.rpc_fixtures.markets_fixtures import ( + inj_token_meta, + ape_token_meta, + usdt_token_meta, + usdt_perp_token_meta, + inj_usdt_spot_market, + ape_usdt_spot_market, + btc_usdt_perp_market, + first_match_bet_market, +) +from tests.rpc_fixtures.configurable_servicers import ConfigurableInjectiveDerivativeExchangeRPCServicer, \ + ConfigurableInjectiveSpotExchangeRPCServicer -@pytest.fixture(scope='module') -def grpc_servicer(): - from tests.rpc_fixtures.configurable_servicers import ConfigurableInjectiveSpotExchangeRPCServicer +@pytest.fixture +def spot_servicer(): return ConfigurableInjectiveSpotExchangeRPCServicer() -@pytest.fixture(scope='module') -def grpc_stub_cls(grpc_channel): - from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc import InjectiveSpotExchangeRPCStub +@pytest.fixture +def derivative_servicer(): + return ConfigurableInjectiveDerivativeExchangeRPCServicer() - return InjectiveSpotExchangeRPCStub class TestAsyncClient: @@ -112,29 +112,53 @@ async def test_get_account_logs_exception(self, caplog): @pytest.mark.asyncio async def test_initialize_tokens_and_markets( self, - grpc_stub, - grpc_servicer, + spot_servicer, + derivative_servicer, inj_usdt_spot_market, - ape_usdt_spot_market + ape_usdt_spot_market, + btc_usdt_perp_market, + first_match_bet_market, ): - grpc_servicer.markets_queue.append(MarketsResponse( + spot_servicer.markets_queue.append(injective_spot_exchange_rpc_pb2.MarketsResponse( markets=[inj_usdt_spot_market, ape_usdt_spot_market] )) + derivative_servicer.markets_queue.append(injective_derivative_exchange_rpc_pb2.MarketsResponse( + markets=[btc_usdt_perp_market] + )) + derivative_servicer.binary_option_markets_queue.append( + injective_derivative_exchange_rpc_pb2.BinaryOptionsMarketsResponse( + markets=[first_match_bet_market] + )) client = AsyncClient( network=Network.local(), insecure=False, ) - client.stubSpotExchange = grpc_stub + client.stubSpotExchange = spot_servicer + client.stubDerivativeExchange = derivative_servicer await client._initialize_tokens_and_markets() - assert(3 == len(client.tokens)) - assert(any((inj_usdt_spot_market.base_token_meta.symbol == token.symbol for token in client.tokens))) - assert (any((inj_usdt_spot_market.quote_token_meta.symbol == token.symbol for token in client.tokens))) - assert (any((ape_usdt_spot_market.base_token_meta.symbol == token.symbol for token in client.tokens))) - - assert (2 == len(client.markets)) - assert (any((inj_usdt_spot_market.market_id == market.id for market in client.markets))) - assert (any((ape_usdt_spot_market.market_id == market.id for market in client.markets))) + all_tokens = await client.all_tokens() + assert(4 == len(all_tokens)) + inj_symbol, usdt_symbol = inj_usdt_spot_market.ticker.split("/") + ape_symbol, _ = ape_usdt_spot_market.ticker.split("/") + usdt_perp_symbol = btc_usdt_perp_market.quote_token_meta.symbol + assert(any((inj_symbol == token.symbol for _, token in all_tokens.items()))) + assert (any((usdt_symbol == token.symbol for _, token in all_tokens.items()))) + assert (any((ape_symbol == token.symbol for _, token in all_tokens.items()))) + assert (any((usdt_perp_symbol == token.symbol for _, token in all_tokens.items()))) + + all_spot_markets = await client.all_spot_markets() + assert (2 == len(all_spot_markets)) + assert (any((inj_usdt_spot_market.market_id == market.id for market in all_spot_markets.values()))) + assert (any((ape_usdt_spot_market.market_id == market.id for market in all_spot_markets.values()))) + + all_derivative_markets = await client.all_derivative_markets() + assert (1 == len(all_derivative_markets)) + assert (any((btc_usdt_perp_market.market_id == market.id for market in all_derivative_markets.values()))) + + all_binary_option_markets = await client.all_binary_option_markets() + assert (1 == len(all_binary_option_markets)) + assert (any((first_match_bet_market.market_id == market.id for market in all_binary_option_markets.values()))) diff --git a/tests/test_composer.py b/tests/test_composer.py new file mode 100644 index 00000000..ed936351 --- /dev/null +++ b/tests/test_composer.py @@ -0,0 +1,222 @@ +import logging +import pytest +from decimal import Decimal + +from pyinjective.composer import Composer +from pyinjective.constant import Denom, Network +from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from pyinjective.proto.injective.exchange.v1beta1 import exchange_pb2 +from tests.model_fixtures.markets_fixtures import ( + btc_usdt_perp_market, + first_match_bet_market, + inj_token, + inj_usdt_spot_market, + usdt_token, + usdt_perp_token +) + + +class TestComposer: + + @pytest.fixture + def inj_usdt_market_id(self): + return "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0" + + @pytest.fixture + def basic_composer(self, inj_usdt_spot_market, btc_usdt_perp_market, first_match_bet_market): + composer = Composer( + network=Network.devnet().string(), + spot_markets={inj_usdt_spot_market.id: inj_usdt_spot_market}, + derivative_markets={btc_usdt_perp_market.id: btc_usdt_perp_market}, + binary_option_markets={first_match_bet_market.id: first_match_bet_market}, + tokens={ + inj_usdt_spot_market.base_token.symbol: inj_usdt_spot_market.base_token, + inj_usdt_spot_market.quote_token.symbol: inj_usdt_spot_market.quote_token, + btc_usdt_perp_market.quote_token.symbol: btc_usdt_perp_market.quote_token, + } + ) + + return composer + + def test_buy_spot_order_creation(self, basic_composer: Composer, inj_usdt_spot_market: SpotMarket): + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = 6.869 + quantity = 1587 + order = basic_composer.SpotOrder( + market_id=inj_usdt_spot_market.id, + subaccount_id="1", + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + is_buy=True, + ) + + price_decimals = inj_usdt_spot_market.quote_token.decimals - inj_usdt_spot_market.base_token.decimals + chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") + expected_price = ((chain_format_price // inj_usdt_spot_market.min_price_tick_size) + * inj_usdt_spot_market.min_price_tick_size + * Decimal(f"1e18")) + chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{inj_usdt_spot_market.base_token.decimals}") + expected_quantity = ((chain_format_quantity // inj_usdt_spot_market.min_quantity_tick_size) + * inj_usdt_spot_market.min_quantity_tick_size + * Decimal(f"1e18")) + + assert (order.market_id == inj_usdt_spot_market.id) + assert (order.order_info.subaccount_id == "1") + assert (order.order_info.fee_recipient == fee_recipient) + assert (order.order_info.price == str(int(expected_price))) + assert (order.order_info.quantity == str(int(expected_quantity))) + assert (order.order_type == exchange_pb2.OrderType.BUY) + assert (order.trigger_price == "0") + + def test_buy_derivative_order_creation(self, basic_composer: Composer, btc_usdt_perp_market: DerivativeMarket): + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = 6.869 + quantity = 1587 + leverage = 2 + order = basic_composer.DerivativeOrder( + market_id=btc_usdt_perp_market.id, + subaccount_id="1", + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + is_buy=True, + leverage=leverage, + ) + + price_decimals = btc_usdt_perp_market.quote_token.decimals + chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") + expected_price = ((chain_format_price // btc_usdt_perp_market.min_price_tick_size) + * btc_usdt_perp_market.min_price_tick_size + * Decimal(f"1e18")) + chain_format_quantity = Decimal(str(quantity)) + expected_quantity = ((chain_format_quantity // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size + * Decimal(f"1e18")) + chain_format_margin = (chain_format_quantity * chain_format_price) / Decimal(leverage) + expected_margin = ((chain_format_margin // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size + * Decimal(f"1e18")) + + assert (order.market_id == btc_usdt_perp_market.id) + assert (order.order_info.subaccount_id == "1") + assert (order.order_info.fee_recipient == fee_recipient) + assert (order.order_info.price == str(int(expected_price))) + assert (order.order_info.quantity == str(int(expected_quantity))) + assert (order.order_type == exchange_pb2.OrderType.BUY) + assert (order.margin == str(int(expected_margin))) + assert (order.trigger_price == "0") + + def test_increase_position_margin(self, basic_composer: Composer, btc_usdt_perp_market: DerivativeMarket): + sender = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + amount = 1587.789 + message = basic_composer.MsgIncreasePositionMargin( + sender=sender, + source_subaccount_id="1", + destination_subaccount_id="2", + market_id=btc_usdt_perp_market.id, + amount=amount, + ) + + price_decimals = btc_usdt_perp_market.quote_token.decimals + chain_format_margin = Decimal(str(amount)) * Decimal(f"1e{price_decimals}") + expected_margin = ((chain_format_margin // btc_usdt_perp_market.min_quantity_tick_size) + * btc_usdt_perp_market.min_quantity_tick_size + * Decimal(f"1e18")) + + assert (message.market_id == btc_usdt_perp_market.id) + assert (message.sender == sender) + assert (message.source_subaccount_id == "1") + assert (message.destination_subaccount_id == "2") + assert (message.amount == str(int(expected_margin))) + + def test_buy_binary_option_order_creation_with_fixed_denom( + self, + basic_composer: Composer, + first_match_bet_market: BinaryOptionMarket + ): + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = 6.869 + quantity = 1587 + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=6, + min_price_tick_size=1000, + min_quantity_tick_size=10000, + ) + + order = basic_composer.BinaryOptionsOrder( + market_id=first_match_bet_market.id, + subaccount_id="1", + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + is_buy=True, + denom=fixed_denom, + ) + + price_decimals = fixed_denom.quote + chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") + expected_price = ((chain_format_price // Decimal(str(fixed_denom.min_price_tick_size))) + * Decimal(str(fixed_denom.min_price_tick_size)) + * Decimal(f"1e18")) + quantity_decimals = fixed_denom.base + chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{quantity_decimals}") + expected_quantity = ((chain_format_quantity // Decimal(str(fixed_denom.min_quantity_tick_size))) + * Decimal(str(fixed_denom.min_quantity_tick_size)) + * Decimal(f"1e18")) + chain_format_margin = chain_format_quantity * chain_format_price + expected_margin = ((chain_format_margin // Decimal(str(fixed_denom.min_quantity_tick_size))) + * Decimal(str(fixed_denom.min_quantity_tick_size)) + * Decimal(f"1e18")) + + assert (order.market_id == first_match_bet_market.id) + assert (order.order_info.subaccount_id == "1") + assert (order.order_info.fee_recipient == fee_recipient) + assert (order.order_info.price == str(int(expected_price))) + assert (order.order_info.quantity == str(int(expected_quantity))) + assert (order.order_type == exchange_pb2.OrderType.BUY) + assert (order.margin == str(int(expected_margin))) + assert (order.trigger_price == "0") + + def test_buy_binary_option_order_creation_without_fixed_denom( + self, + basic_composer: Composer, + first_match_bet_market: BinaryOptionMarket, + ): + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = 6.869 + quantity = 1587 + + order = basic_composer.BinaryOptionsOrder( + market_id=first_match_bet_market.id, + subaccount_id="1", + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + is_buy=True, + ) + + price_decimals = first_match_bet_market.quote_token.decimals + chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") + expected_price = ((chain_format_price // first_match_bet_market.min_price_tick_size) + * first_match_bet_market.min_price_tick_size + * Decimal(f"1e18")) + chain_format_quantity = Decimal(str(quantity)) + expected_quantity = ((chain_format_quantity // first_match_bet_market.min_quantity_tick_size) + * first_match_bet_market.min_quantity_tick_size + * Decimal(f"1e18")) + chain_format_margin = (chain_format_quantity * chain_format_price) + expected_margin = ((chain_format_margin // first_match_bet_market.min_quantity_tick_size) + * first_match_bet_market.min_quantity_tick_size + * Decimal(f"1e18")) + + assert (order.market_id == first_match_bet_market.id) + assert (order.order_info.subaccount_id == "1") + assert (order.order_info.fee_recipient == fee_recipient) + assert (order.order_info.price == str(int(expected_price))) + assert (order.order_info.quantity == str(int(expected_quantity))) + assert (order.order_type == exchange_pb2.OrderType.BUY) + assert (order.margin == str(int(expected_margin))) + assert (order.trigger_price == "0") From b2192c1714eea8bb9ea893ba29311a45981e96fd Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 26 May 2023 10:12:55 +0200 Subject: [PATCH 16/40] (fix) Remove deprecation warning from Denom class since it is still being used for Binary Options --- examples/chain_client/6_MsgCreateDerivativeLimitOrder.py | 2 +- pyinjective/constant.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py index 5a3c3e36..8753d2d9 100644 --- a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py +++ b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py @@ -23,7 +23,7 @@ async def main() -> None: subaccount_id = address.get_subaccount_id(index=0) # prepare trade info - market_id = "0x90e662193fa29a3a7e6c07be4407c94833e762d9ee82136a2cc712d6b87d7de3" + market_id = "0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74" fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg diff --git a/pyinjective/constant.py b/pyinjective/constant.py index 0774e4b3..35947d89 100644 --- a/pyinjective/constant.py +++ b/pyinjective/constant.py @@ -1,6 +1,5 @@ import os from configparser import ConfigParser -from warnings import warn MAX_CLIENT_ID_LENGTH = 128 MAX_DATA_SIZE = 256 @@ -34,8 +33,6 @@ def __init__( min_price_tick_size: float, min_quantity_tick_size: float ): - """This throws a deprecation warning on initialization.""" - warn(f'{self.__class__.__name__} will be deprecated.', DeprecationWarning, stacklevel=2) self.description = description self.base = base From 8fa18c1e87fe8085561fb39e9cb325b08fd5b00b Mon Sep 17 00:00:00 2001 From: abel Date: Thu, 25 May 2023 18:21:05 +0200 Subject: [PATCH 17/40] (feat) Refactor Composer to use actual markets and tokens to translate human-readable values into chain format --- pyinjective/constant.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyinjective/constant.py b/pyinjective/constant.py index 35947d89..0e074e62 100644 --- a/pyinjective/constant.py +++ b/pyinjective/constant.py @@ -1,5 +1,6 @@ import os from configparser import ConfigParser +from warnings import warn MAX_CLIENT_ID_LENGTH = 128 MAX_DATA_SIZE = 256 From b5ccef23700d55d955dea7af4b77462c3f8b2094 Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Mon, 29 May 2023 18:22:31 +0200 Subject: [PATCH 18/40] (fix) Turned market classes and token class into dataclass with eq and hash support --- pyinjective/core/market.py | 8 ++++---- pyinjective/core/token.py | 28 +++++++++------------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/pyinjective/core/market.py b/pyinjective/core/market.py index d28ba462..9a42b88c 100644 --- a/pyinjective/core/market.py +++ b/pyinjective/core/market.py @@ -2,11 +2,11 @@ from decimal import Decimal from typing import Optional -from constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS, Denom +from pyinjective.constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS, Denom from pyinjective.core.token import Token -@dataclass +@dataclass(eq=True, frozen=True) class SpotMarket: id: str status: str @@ -34,7 +34,7 @@ def price_to_chain_format(self, human_readable_value: Decimal) -> Decimal: return extended_chain_formatted_value -@dataclass +@dataclass(eq=True, frozen=True) class DerivativeMarket: id: str status: str @@ -92,7 +92,7 @@ def calculate_margin_in_chain_format( return extended_chain_formatted_margin -@dataclass +@dataclass(eq=True, frozen=True) class BinaryOptionMarket: id: str status: str diff --git a/pyinjective/core/token.py b/pyinjective/core/token.py index 59bac41e..c6af6c0d 100644 --- a/pyinjective/core/token.py +++ b/pyinjective/core/token.py @@ -1,25 +1,15 @@ +from dataclasses import dataclass from decimal import Decimal - +@dataclass(eq=True, frozen=True) class Token: - - def __init__( - self, - name: str, - symbol: str, - denom: str, - address: str, - decimals: int, - logo: str, - updated: int, - ): - self.name = name - self.symbol = symbol - self.denom = denom - self.address = address - self.decimals = decimals - self.logo = logo - self.updated = updated + name: str + symbol: str + denom: str + address: str + decimals: int + logo: str + updated: int def chain_formatted_value(self, human_readable_value: Decimal) -> Decimal: return human_readable_value * Decimal(f"1e{self.decimals}") From 0c5683e518ec1041389ffc12e11805340a050099 Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Mon, 29 May 2023 19:32:28 +0200 Subject: [PATCH 19/40] (feat) Included logic to validate INI files metadata against indexer info in the `utils` module --- pyinjective/{ => utils}/fetch_metadata.py | 4 +- pyinjective/utils/metadata_validation.py | 105 ++++++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) rename pyinjective/{ => utils}/fetch_metadata.py (97%) create mode 100644 pyinjective/utils/metadata_validation.py diff --git a/pyinjective/fetch_metadata.py b/pyinjective/utils/fetch_metadata.py similarity index 97% rename from pyinjective/fetch_metadata.py rename to pyinjective/utils/fetch_metadata.py index 1abbd815..a1a00c51 100644 --- a/pyinjective/fetch_metadata.py +++ b/pyinjective/utils/fetch_metadata.py @@ -96,12 +96,12 @@ async def fetch_denom(network) -> str: async def main() -> None: testnet = Network.testnet() data = await fetch_denom(testnet) - with open("denoms_testnet.ini", "w") as text_file: + with open("../denoms_testnet.ini", "w") as text_file: text_file.write(data) mainnet = Network.mainnet() data = await fetch_denom(mainnet) - with open("denoms_mainnet.ini", "w") as text_file: + with open("../denoms_mainnet.ini", "w") as text_file: text_file.write(data) if __name__ == '__main__': diff --git a/pyinjective/utils/metadata_validation.py b/pyinjective/utils/metadata_validation.py new file mode 100644 index 00000000..79befd40 --- /dev/null +++ b/pyinjective/utils/metadata_validation.py @@ -0,0 +1,105 @@ +import asyncio +from decimal import Decimal +from typing import Any, List, Tuple + +import pyinjective.constant as constant +from pyinjective.async_client import AsyncClient +from pyinjective.constant import Network +from pyinjective.core.market import SpotMarket, DerivativeMarket, BinaryOptionMarket + + +def find_metadata_inconsistencies(network: Network) -> Tuple[List[Any]]: + client = AsyncClient(network, insecure=False) + + spot_markets = asyncio.get_event_loop().run_until_complete(client.all_spot_markets()) + derivative_markets = asyncio.get_event_loop().run_until_complete(client.all_derivative_markets()) + binary_option_markets = asyncio.get_event_loop().run_until_complete(client.all_binary_option_markets()) + all_tokens = asyncio.get_event_loop().run_until_complete(client.all_tokens()) + + markets_not_found = [] + markets_with_diffs = [] + peggy_denoms_not_found = [] + peggy_denoms_with_diffs = [] + + for config_key in constant.mainnet_config: + if config_key.startswith("0x"): + denom = constant.Denom.load_market(network=network.string(), market_id=config_key) + if config_key in spot_markets: + market: SpotMarket = spot_markets[config_key] + if (market.base_token.decimals != denom.base + or market.quote_token.decimals != denom.quote + or market.min_price_tick_size != Decimal(str(denom.min_price_tick_size)) + or market.min_quantity_tick_size != Decimal(str(denom.min_quantity_tick_size))): + markets_with_diffs.append([ + {"denom-market": config_key, "base_decimals": denom.base, "quote_decimals": denom.quote, + "min_quantity_tick_size": denom.min_quantity_tick_size, + "min_price_tick_size": denom.min_price_tick_size}, + {"newer-market": market.id, "base_decimals": market.base_token.decimals, + "quote_decimals": market.quote_token.decimals, + "min_quantity_tick_size": float(market.min_quantity_tick_size), + "min_price_tick_size": float(market.min_price_tick_size), "ticker": market.ticker}, + ]) + elif config_key in derivative_markets: + market: DerivativeMarket = derivative_markets[config_key] + if (market.quote_token.decimals != denom.quote + or market.min_price_tick_size != Decimal(str(denom.min_price_tick_size)) + or market.min_quantity_tick_size != Decimal(str(denom.min_quantity_tick_size))): + markets_with_diffs.append([ + {"denom-market": config_key, "quote_decimals": denom.quote, + "min_quantity_tick_size": denom.min_quantity_tick_size, + "min_price_tick_size": denom.min_price_tick_size}, + {"newer-market": market.id, "quote_decimals": market.quote_token.decimals, + "min_quantity_tick_size": float(market.min_quantity_tick_size), + "min_price_tick_size": float(market.min_price_tick_size), "ticker": market.ticker}, + ]) + elif config_key in binary_option_markets: + market: BinaryOptionMarket = binary_option_markets[config_key] + if (market.quote_token.decimals != denom.quote + or market.min_price_tick_size != Decimal(str(denom.min_price_tick_size)) + or market.min_quantity_tick_size != Decimal(str(denom.min_quantity_tick_size))): + markets_with_diffs.append([ + {"denom-market": config_key, "quote_decimals": denom.quote, + "min_quantity_tick_size": denom.min_quantity_tick_size, + "min_price_tick_size": denom.min_price_tick_size}, + {"newer-market": market.id, "quote_decimals": market.quote_token.decimals, + "min_quantity_tick_size": float(market.min_quantity_tick_size), + "min_price_tick_size": float(market.min_price_tick_size), "ticker": market.ticker}, + ]) + else: + markets_not_found.append({"denom-market": config_key, "description": denom.description}) + + elif config_key == "DEFAULT": + continue + else: + # the configuration is a token + peggy_denom, decimals = constant.Denom.load_peggy_denom(network=network.string(), symbol=config_key) + if config_key in all_tokens: + token = all_tokens[config_key] + if (token.denom != peggy_denom + or token.decimals != decimals): + peggy_denoms_with_diffs.append([ + {"denom_token": config_key, "peggy_denom": peggy_denom, "decimals": decimals}, + {"newer_token": token.symbol, "peggy_denom": token.denom, "decimals": token.decimals} + ]) + else: + peggy_denoms_not_found.append( + {"denom_token": config_key, "peggy_denom": peggy_denom, "decimals": decimals}) + + return markets_with_diffs, markets_not_found, peggy_denoms_with_diffs, peggy_denoms_not_found + + +def print_metadata_mismatches(network: Network): + markets_with_diffs, markets_not_found, peggy_denoms_with_diffs, peggy_denoms_not_found = find_metadata_inconsistencies( + network=network) + + for diff_pair in markets_with_diffs: + print(f"{diff_pair[0]}\n{diff_pair[1]}") + print(f"\n\n") + for missing_market in markets_not_found: + print(f"{missing_market}") + print(f"\n\n") + for diff_token in peggy_denoms_with_diffs: + print(f"{diff_token[0]}\n{diff_token[1]}") + print(f"\n\n") + for missing_peggy in peggy_denoms_not_found: + print(f"{missing_peggy}") From ce896bef8186d746ef6bcf0956be442b73b076e6 Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Tue, 30 May 2023 01:45:06 +0200 Subject: [PATCH 20/40] (fix) Fixed INI files to synchronize them with the information for the markets in the chain --- pyinjective/denoms_devnet.ini | 2 +- pyinjective/denoms_mainnet.ini | 19 +++++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/pyinjective/denoms_devnet.ini b/pyinjective/denoms_devnet.ini index 7b2df629..4e4f2797 100644 --- a/pyinjective/denoms_devnet.ini +++ b/pyinjective/denoms_devnet.ini @@ -92,7 +92,7 @@ min_display_quantity_tick_size = 0.001 description = 'Devnet Spot GF/USDT' base = 18 quote = 6 -min_price_tick_size = 0.000000000000001 +min_price_tick_size = 0.0000000000000001 min_display_price_tick_size = 0.001 min_quantity_tick_size = 100000 min_display_quantity_tick_size = 1e-13 diff --git a/pyinjective/denoms_mainnet.ini b/pyinjective/denoms_mainnet.ini index 000b5415..9a5fca85 100644 --- a/pyinjective/denoms_mainnet.ini +++ b/pyinjective/denoms_mainnet.ini @@ -200,7 +200,7 @@ min_display_quantity_tick_size = 0.01 description = 'Mainnet Spot GF/USDT' base = 18 quote = 6 -min_price_tick_size = 0.000000000000001 +min_price_tick_size = 0.0000000000000001 min_display_price_tick_size = 0.001 min_quantity_tick_size = 1000000000000000 min_display_quantity_tick_size = 0.001 @@ -317,7 +317,7 @@ min_display_quantity_tick_size = 100.0 description = 'Mainnet Spot STRD/USDT' base = 6 quote = 6 -min_price_tick_size = 0.001 +min_price_tick_size = 0.0001 min_display_price_tick_size = 1e-09 min_quantity_tick_size = 1000 min_display_quantity_tick_size = 1000.0 @@ -328,7 +328,7 @@ base = 6 quote = 6 min_price_tick_size = 0.0001 min_display_price_tick_size = 0.0001 -min_quantity_tick_size = 10000000 +min_quantity_tick_size = 1000000 min_display_quantity_tick_size = 10.0 [0x4fa0bd2c2adbfe077f58395c18a72f5cbf89532743e3bddf43bc7aba706b0b74] @@ -452,7 +452,7 @@ min_display_quantity_tick_size = 0.01 description = 'Mainnet Derivative STX/USDT PERP' base = 0 quote = 6 -min_price_tick_size = 1000 +min_price_tick_size = 100 min_display_price_tick_size = 0.001 min_quantity_tick_size = 0.1 min_display_quantity_tick_size = 0.1 @@ -493,15 +493,6 @@ min_display_price_tick_size = 0.01 min_quantity_tick_size = 0.1 min_display_quantity_tick_size = 0.1 -[0x5e7be7948c78f0c7fb1170655b5faa0a519ee0801250dde0b50308791474e61c] -description = 'Mainnet Derivative ETH/USDT 19SEP22' -base = 0 -quote = 6 -min_price_tick_size = 100000 -min_display_price_tick_size = 0.1 -min_quantity_tick_size = 0.01 -min_display_quantity_tick_size = 0.01 - [0x3b7fb1d9351f7fa2e6e0e5a11b3639ee5e0486c33a6a74f629c3fc3c3043efd5] description = 'Mainnet Derivative BONK/USDT PERP' base = 0 @@ -664,7 +655,7 @@ decimals = 8 peggy_denom = factory/inj14ejqjyq8um4p3xfqj74yld5waqljf88f9eneuk/inj1d5vz0uzwlpfvgwrwulxg6syy82axa58y4fuszd decimals = 8 -[wMATIC] +[WMATIC] peggy_denom = factory/inj14ejqjyq8um4p3xfqj74yld5waqljf88f9eneuk/inj1dxv423h8ygzgxmxnvrf33ws3k94aedfdevxd8h decimals = 8 From 2d162144c6a3a87099f2db814c2a8557e9f410aa Mon Sep 17 00:00:00 2001 From: Abel Armoa Date: Tue, 30 May 2023 13:15:35 +0200 Subject: [PATCH 21/40] (fix) Updated examples and the `run-examples.sh` script to enable the execution off all examples with the new code base --- .../spot_exchange_rpc/14_Orderbooks.py | 2 +- .../spot_exchange_rpc/16_OrderbooksV2.py | 19 ------------------- .../spot_exchange_rpc/4_Orderbook.py | 2 +- pyinjective/async_client.py | 8 -------- pyinjective/composer.py | 11 ++++++++--- pyinjective/denoms_testnet.ini | 2 +- run-examples.sh | 6 ++++-- tests/test_composer.py | 13 +++++++++++++ 8 files changed, 28 insertions(+), 35 deletions(-) delete mode 100644 examples/exchange_client/spot_exchange_rpc/16_OrderbooksV2.py diff --git a/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py b/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py index 0e792d5a..59d23047 100644 --- a/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py +++ b/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py @@ -11,7 +11,7 @@ async def main() -> None: "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0" ] - orderbooks = await client.get_spot_orderbooks(market_ids=market_ids) + orderbooks = await client.get_spot_orderbooksV2(market_ids=market_ids) print(orderbooks) if __name__ == '__main__': diff --git a/examples/exchange_client/spot_exchange_rpc/16_OrderbooksV2.py b/examples/exchange_client/spot_exchange_rpc/16_OrderbooksV2.py deleted file mode 100644 index 6a28009e..00000000 --- a/examples/exchange_client/spot_exchange_rpc/16_OrderbooksV2.py +++ /dev/null @@ -1,19 +0,0 @@ -import asyncio -import logging - -from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network - -async def main() -> None: - # select network: local, testnet, mainnet - network = Network.testnet() - client = AsyncClient(network, insecure=False) - market_ids = [ - "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", - "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0" - ] - orderbooks = await client.get_spot_orderbooksV2(market_ids=market_ids) - print(orderbooks) - -if __name__ == '__main__': - asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py b/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py index 44522fbc..19b58933 100644 --- a/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py +++ b/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py @@ -8,7 +8,7 @@ async def main() -> None: network = Network.testnet() client = AsyncClient(network, insecure=False) market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" - orderbook = await client.get_spot_orderbook(market_id=market_id) + orderbook = await client.get_spot_orderbookV2(market_id=market_id) print(orderbook) if __name__ == '__main__': diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index e29bcbe9..429b73ef 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -675,14 +675,6 @@ async def stream_spot_markets(self, **kwargs): metadata = await self.load_cookie(type="exchange") return self.stubSpotExchange.StreamMarkets.__call__(req, metadata=metadata) - async def get_spot_orderbook(self, market_id: str): - req = spot_exchange_rpc_pb.OrderbookRequest(market_id=market_id) - return await self.stubSpotExchange.Orderbook(req) - - async def get_spot_orderbooks(self, market_ids: List): - req = spot_exchange_rpc_pb.OrderbooksRequest(market_ids=market_ids) - return await self.stubSpotExchange.Orderbooks(req) - async def get_spot_orderbookV2(self, market_id: str): req = spot_exchange_rpc_pb.OrderbookV2Request(market_id=market_id) return await self.stubSpotExchange.OrderbookV2(req) diff --git a/pyinjective/composer.py b/pyinjective/composer.py index bbb9bcbf..73171002 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -69,6 +69,10 @@ def __init__( """ self.network = network + self.spot_markets = dict() + self.derivative_markets = dict() + self.binary_option_markets = dict() + self.tokens = dict() if spot_markets is None or derivative_markets is None or binary_option_markets is None or tokens is None: self._initialize_markets_and_tokens_from_files() else: @@ -1005,7 +1009,7 @@ def _initialize_markets_and_tokens_from_files(self): min_price_tick_size=Decimal(str(configuration_section["min_price_tick_size"])), min_quantity_tick_size=Decimal(str(configuration_section["min_quantity_tick_size"])) ) - spot_markets[description] = market + spot_markets[market.id] = market else: market = DerivativeMarket( id=section_name, @@ -1025,7 +1029,7 @@ def _initialize_markets_and_tokens_from_files(self): min_quantity_tick_size=Decimal(str(configuration_section["min_quantity_tick_size"])), ) - derivative_markets[description] = market + derivative_markets[market.id] = market elif section_name != "DEFAULT": token = Token( @@ -1038,8 +1042,9 @@ def _initialize_markets_and_tokens_from_files(self): updated=-1, ) - tokens[token.symbol] = Token + tokens[token.symbol] = token self.tokens = tokens self.spot_markets = spot_markets self.derivative_markets = derivative_markets + self.binary_option_markets = dict() diff --git a/pyinjective/denoms_testnet.ini b/pyinjective/denoms_testnet.ini index 84edee96..4ad6e0e1 100644 --- a/pyinjective/denoms_testnet.ini +++ b/pyinjective/denoms_testnet.ini @@ -52,7 +52,7 @@ min_display_price_tick_size = 1e-05 min_quantity_tick_size = 100000 min_display_quantity_tick_size = 0.1 -[0xe112199d9ee44ceb2697ea0edd1cd422223c105f3ed2bdf85223d3ca59f5909a] +[0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6] description = 'Testnet Derivative INJ/USDT PERP' base = 0 quote = 6 diff --git a/run-examples.sh b/run-examples.sh index 8196e9d9..4b376ce9 100755 --- a/run-examples.sh +++ b/run-examples.sh @@ -1,5 +1,5 @@ runChainExamples(){ - examples=$(find -s examples/chain_client_examples -type f -mindepth 1 -name '*.py') + examples=$(find -s examples/chain_client -type f -mindepth 1 -name '*.py') echo "Running all chain examples..." for example in $examples do @@ -10,7 +10,7 @@ runChainExamples(){ } runExchangeExamples(){ - dirs=$(find -s examples/exchange_api_examples -type d -mindepth 1) + dirs=$(find -s examples/exchange_client -type d -mindepth 1) for dir in $dirs do examples=$(find -s $dir -type f -name '*.py') @@ -26,6 +26,8 @@ runExchangeExamples(){ done } +export PYTHONPATH=$PYTHONPATH:$(pwd) + TYPE=$1 case $TYPE in "chain") diff --git a/tests/test_composer.py b/tests/test_composer.py index ed936351..9c5426e5 100644 --- a/tests/test_composer.py +++ b/tests/test_composer.py @@ -38,6 +38,19 @@ def basic_composer(self, inj_usdt_spot_market, btc_usdt_perp_market, first_match return composer + def test_composer_initialization_from_ini_files(self): + composer = Composer(network=Network.devnet().string()) + + inj_token = composer.tokens["INJ"] + inj_usdt_spot_market = next((market for market in composer.spot_markets.values() if market.ticker == "'Devnet Spot INJ/USDT'")) + inj_usdt_perp_market = next((market for market in composer.derivative_markets.values() if market.ticker == "'Devnet Derivative INJ/USDT PERP'")) + + assert (18 == inj_token.decimals) + assert (18 == inj_usdt_spot_market.base_token.decimals) + assert (6 == inj_usdt_spot_market.quote_token.decimals) + assert (6 == inj_usdt_perp_market.quote_token.decimals) + + def test_buy_spot_order_creation(self, basic_composer: Composer, inj_usdt_spot_market: SpotMarket): fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" price = 6.869 From 115affdf3f8c2293653ec988142d6e653ba9f9f3 Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 6 Jun 2023 16:33:08 +0200 Subject: [PATCH 22/40] (fix) Regenerated Pipfile.lock after synchronizing the branch with the latest `dev` --- Pipfile.lock | 10 +++++++++- tests/__init__.py | 0 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/__init__.py diff --git a/Pipfile.lock b/Pipfile.lock index ead81018..35037395 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "ddd9c0acafbf86fc3b26c88650bee0a2aa19d05a537541bfcbd8c8c2a1401266" + "sha256": "414c3e95a8abb1f4986d0ae4814e25f8c7eba47e5343b5c67cf0bab32b21eadc" }, "pipfile-spec": 6, "requires": { @@ -1503,6 +1503,14 @@ "index": "pypi", "version": "==0.21.0" }, + "pytest-grpc": { + "hashes": [ + "sha256:0bd2683ffd34199444d707c0ab01970b22e0afbba6cb1ddb6d578c85ebfe09bd", + "sha256:5b062cf498e59995e84b3051da76f7bcff8cfe307927869f7bdc27ab967eee35" + ], + "index": "pypi", + "version": "==0.8.0" + }, "requests": { "hashes": [ "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b From 3951c1a0a5132d530bac43c4aa34c3dcf9567a7a Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 6 Jun 2023 17:25:42 +0200 Subject: [PATCH 23/40] (fix) Included __init__.py in the tests folder to make it a python module --- Makefile | 2 +- tests/__init__.py | 0 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 tests/__init__.py diff --git a/Makefile b/Makefile index 21e230ae..b043c0d7 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,6 @@ copy-proto: done tests: - pytest -v tests/** + pytest -v .PHONY: all gen gen-client copy-proto tests diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b From 6dedca56b802c2192f6f381f0222d058f11607dd Mon Sep 17 00:00:00 2001 From: abel Date: Thu, 15 Jun 2023 14:29:20 -0400 Subject: [PATCH 24/40] (fix) Added extra logic to allow the tokens initialization to accept tokens with repeated symbol but different denom as different tokens --- pyinjective/async_client.py | 80 +++++++++++++----------- pyinjective/denoms_testnet.ini | 22 +------ pyinjective/utils/metadata_validation.py | 3 +- tests/rpc_fixtures/markets_fixtures.py | 29 ++++++--- tests/test_async_client.py | 49 ++++++++------- 5 files changed, 96 insertions(+), 87 deletions(-) diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 429b73ef..253bb4d9 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -1067,32 +1067,22 @@ async def _initialize_tokens_and_markets(self): for market_info in markets_info: base_token_symbol, quote_token_symbol = market_info.ticker.split(constant.TICKER_TOKENS_SEPARATOR) - base_token = tokens.get(base_token_symbol, None) - if base_token is None: - base_token = Token( - name=market_info.base_token_meta.name, - symbol=base_token_symbol, - denom=market_info.base_denom, - address=market_info.base_token_meta.address, - decimals=market_info.base_token_meta.decimals, - logo=market_info.base_token_meta.logo, - updated=market_info.base_token_meta.updated_at, - ) - tokens[base_token_symbol] = base_token + base_token = self._token_representation( + symbol=base_token_symbol, + token_meta=market_info.base_token_meta, + denom=market_info.base_denom, + all_tokens=tokens, + ) + if base_token.denom not in tokens_by_denom: tokens_by_denom[base_token.denom] = base_token - quote_token = tokens.get(quote_token_symbol, None) - if quote_token is None: - quote_token = Token( - name=market_info.quote_token_meta.name, - symbol=quote_token_symbol, - denom=market_info.quote_denom, - address=market_info.quote_token_meta.address, - decimals=market_info.quote_token_meta.decimals, - logo=market_info.quote_token_meta.logo, - updated=market_info.quote_token_meta.updated_at, - ) - tokens[quote_token_symbol] = quote_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, + ) + if quote_token.denom not in tokens_by_denom: tokens_by_denom[quote_token.denom] = quote_token market = SpotMarket( @@ -1114,18 +1104,13 @@ async def _initialize_tokens_and_markets(self): for market_info in markets_info: quote_token_symbol = market_info.quote_token_meta.symbol - quote_token = tokens.get(quote_token_symbol, None) - if quote_token is None: - quote_token = Token( - name=market_info.quote_token_meta.name, - symbol=quote_token_symbol, - denom=market_info.quote_denom, - address=market_info.quote_token_meta.address, - decimals=market_info.quote_token_meta.decimals, - logo=market_info.quote_token_meta.logo, - updated=market_info.quote_token_meta.updated_at, - ) - tokens[quote_token_symbol] = quote_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, + ) + if quote_token.denom not in tokens_by_denom: tokens_by_denom[quote_token.denom] = quote_token market = DerivativeMarket( @@ -1176,3 +1161,26 @@ async def _initialize_tokens_and_markets(self): 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 diff --git a/pyinjective/denoms_testnet.ini b/pyinjective/denoms_testnet.ini index 4ad6e0e1..04fb4bba 100644 --- a/pyinjective/denoms_testnet.ini +++ b/pyinjective/denoms_testnet.ini @@ -36,7 +36,7 @@ min_display_quantity_tick_size = 1e-13 [0x1c315bd2cfcc769a8d8eca49ce7b1bc5fb0353bfcb9fa82895fe0c1c2a62306e] description = 'Testnet Spot WBTC/USDT' -base = 6 +base = 8 quote = 6 min_price_tick_size = 0.00001 min_display_price_tick_size = 0.001 @@ -56,25 +56,7 @@ min_display_quantity_tick_size = 0.1 description = 'Testnet Derivative INJ/USDT PERP' base = 0 quote = 6 -min_price_tick_size = 100000 -min_display_price_tick_size = 0.1 -min_quantity_tick_size = 0.0001 -min_display_quantity_tick_size = 0.0001 - -[0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff] -description = 'Testnet Derivative ETH/USDT PERP' -base = 0 -quote = 6 -min_price_tick_size = 100000 -min_display_price_tick_size = 0.1 -min_quantity_tick_size = 0.0001 -min_display_quantity_tick_size = 0.0001 - -[0x90e662193fa29a3a7e6c07be4407c94833e762d9ee82136a2cc712d6b87d7de3] -description = 'Testnet Derivative BTC/USDT PERP' -base = 0 -quote = 6 -min_price_tick_size = 100000 +min_price_tick_size = 100 min_display_price_tick_size = 0.1 min_quantity_tick_size = 0.0001 min_display_quantity_tick_size = 0.0001 diff --git a/pyinjective/utils/metadata_validation.py b/pyinjective/utils/metadata_validation.py index 79befd40..3ef03209 100644 --- a/pyinjective/utils/metadata_validation.py +++ b/pyinjective/utils/metadata_validation.py @@ -10,6 +10,7 @@ def find_metadata_inconsistencies(network: Network) -> Tuple[List[Any]]: client = AsyncClient(network, insecure=False) + ini_config = constant.CONFIGS[network.string()] spot_markets = asyncio.get_event_loop().run_until_complete(client.all_spot_markets()) derivative_markets = asyncio.get_event_loop().run_until_complete(client.all_derivative_markets()) @@ -21,7 +22,7 @@ def find_metadata_inconsistencies(network: Network) -> Tuple[List[Any]]: peggy_denoms_not_found = [] peggy_denoms_with_diffs = [] - for config_key in constant.mainnet_config: + for config_key in ini_config: if config_key.startswith("0x"): denom = constant.Denom.load_market(network=network.string(), market_id=config_key) if config_key in spot_markets: diff --git a/tests/rpc_fixtures/markets_fixtures.py b/tests/rpc_fixtures/markets_fixtures.py index 2145e7ba..b6a2d3a3 100644 --- a/tests/rpc_fixtures/markets_fixtures.py +++ b/tests/rpc_fixtures/markets_fixtures.py @@ -46,6 +46,21 @@ def usdt_token_meta(): return token +@pytest.fixture +def usdt_token_meta_second_denom(): + from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import TokenMeta + + token = TokenMeta( + name="USDT Second Denom", + address="0x0000000000000000000000000000000000000000", + symbol="USDT", + logo="https://static.alchemyapi.io/images/assets/826.png", + decimals=6, + updated_at=1691739137645 + ) + + return token + @pytest.fixture def usdt_perp_token_meta(): @@ -64,7 +79,7 @@ def usdt_perp_token_meta(): @pytest.fixture -def ape_usdt_spot_market(ape_token_meta, usdt_token_meta): +def ape_usdt_spot_market_meta(ape_token_meta, usdt_token_meta_second_denom): from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo market = SpotMarketInfo( @@ -73,8 +88,8 @@ def ape_usdt_spot_market(ape_token_meta, usdt_token_meta): ticker="APE/USDT", base_denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7", base_token_meta=ape_token_meta, - quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", - quote_token_meta=usdt_token_meta, + quote_denom="factory/peggy0x87aB3B4C8661e07D6372361211B96ed4Dc300000", + quote_token_meta=usdt_token_meta_second_denom, maker_fee_rate="-0.0001", taker_fee_rate="0.001", service_provider_fee="0.4", @@ -85,7 +100,7 @@ def ape_usdt_spot_market(ape_token_meta, usdt_token_meta): return market @pytest.fixture -def inj_usdt_spot_market(inj_token_meta, usdt_token_meta): +def inj_usdt_spot_market_meta(inj_token_meta, usdt_token_meta): from pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 import SpotMarketInfo market = SpotMarketInfo( @@ -106,7 +121,7 @@ def inj_usdt_spot_market(inj_token_meta, usdt_token_meta): return market @pytest.fixture -def btc_usdt_perp_market(usdt_perp_token_meta): +def btc_usdt_perp_market_meta(usdt_perp_token_meta): from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2 import ( DerivativeMarketInfo, PerpetualMarketInfo, @@ -150,7 +165,7 @@ def btc_usdt_perp_market(usdt_perp_token_meta): return market @pytest.fixture -def first_match_bet_market(inj_usdt_spot_market): +def first_match_bet_market_meta(inj_usdt_spot_market_meta): from pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2 import BinaryOptionsMarketInfo market = BinaryOptionsMarketInfo( @@ -163,7 +178,7 @@ def first_match_bet_market(inj_usdt_spot_market): oracle_scale_factor=6, expiration_timestamp=1707800399, settlement_timestamp=1707843599, - quote_denom=inj_usdt_spot_market.quote_denom, + quote_denom=inj_usdt_spot_market_meta.quote_denom, maker_fee_rate="0", taker_fee_rate="0", service_provider_fee="0.4", diff --git a/tests/test_async_client.py b/tests/test_async_client.py index 97532a43..56644e9c 100644 --- a/tests/test_async_client.py +++ b/tests/test_async_client.py @@ -12,11 +12,12 @@ inj_token_meta, ape_token_meta, usdt_token_meta, + usdt_token_meta_second_denom, usdt_perp_token_meta, - inj_usdt_spot_market, - ape_usdt_spot_market, - btc_usdt_perp_market, - first_match_bet_market, + inj_usdt_spot_market_meta, + ape_usdt_spot_market_meta, + btc_usdt_perp_market_meta, + first_match_bet_market_meta, ) from tests.rpc_fixtures.configurable_servicers import ConfigurableInjectiveDerivativeExchangeRPCServicer, \ ConfigurableInjectiveSpotExchangeRPCServicer @@ -114,20 +115,20 @@ async def test_initialize_tokens_and_markets( self, spot_servicer, derivative_servicer, - inj_usdt_spot_market, - ape_usdt_spot_market, - btc_usdt_perp_market, - first_match_bet_market, + inj_usdt_spot_market_meta, + ape_usdt_spot_market_meta, + btc_usdt_perp_market_meta, + first_match_bet_market_meta, ): spot_servicer.markets_queue.append(injective_spot_exchange_rpc_pb2.MarketsResponse( - markets=[inj_usdt_spot_market, ape_usdt_spot_market] + markets=[inj_usdt_spot_market_meta, ape_usdt_spot_market_meta] )) derivative_servicer.markets_queue.append(injective_derivative_exchange_rpc_pb2.MarketsResponse( - markets=[btc_usdt_perp_market] + markets=[btc_usdt_perp_market_meta] )) derivative_servicer.binary_option_markets_queue.append( injective_derivative_exchange_rpc_pb2.BinaryOptionsMarketsResponse( - markets=[first_match_bet_market] + markets=[first_match_bet_market_meta] )) client = AsyncClient( @@ -141,24 +142,26 @@ async def test_initialize_tokens_and_markets( await client._initialize_tokens_and_markets() all_tokens = await client.all_tokens() - assert(4 == len(all_tokens)) - inj_symbol, usdt_symbol = inj_usdt_spot_market.ticker.split("/") - ape_symbol, _ = ape_usdt_spot_market.ticker.split("/") - usdt_perp_symbol = btc_usdt_perp_market.quote_token_meta.symbol - assert(any((inj_symbol == token.symbol for _, token in all_tokens.items()))) - assert (any((usdt_symbol == token.symbol for _, token in all_tokens.items()))) - assert (any((ape_symbol == token.symbol for _, token in all_tokens.items()))) - assert (any((usdt_perp_symbol == token.symbol for _, token in all_tokens.items()))) + assert(5 == len(all_tokens)) + inj_symbol, usdt_symbol = inj_usdt_spot_market_meta.ticker.split("/") + ape_symbol, _ = ape_usdt_spot_market_meta.ticker.split("/") + alternative_usdt_name = ape_usdt_spot_market_meta.quote_token_meta.name + usdt_perp_symbol = btc_usdt_perp_market_meta.quote_token_meta.symbol + assert(inj_symbol in all_tokens) + assert(usdt_symbol in all_tokens) + assert(alternative_usdt_name in all_tokens) + assert(ape_symbol in all_tokens) + assert(usdt_perp_symbol in all_tokens) all_spot_markets = await client.all_spot_markets() assert (2 == len(all_spot_markets)) - assert (any((inj_usdt_spot_market.market_id == market.id for market in all_spot_markets.values()))) - assert (any((ape_usdt_spot_market.market_id == market.id for market in all_spot_markets.values()))) + assert (any((inj_usdt_spot_market_meta.market_id == market.id for market in all_spot_markets.values()))) + assert (any((ape_usdt_spot_market_meta.market_id == market.id for market in all_spot_markets.values()))) all_derivative_markets = await client.all_derivative_markets() assert (1 == len(all_derivative_markets)) - assert (any((btc_usdt_perp_market.market_id == market.id for market in all_derivative_markets.values()))) + assert (any((btc_usdt_perp_market_meta.market_id == market.id for market in all_derivative_markets.values()))) all_binary_option_markets = await client.all_binary_option_markets() assert (1 == len(all_binary_option_markets)) - assert (any((first_match_bet_market.market_id == market.id for market in all_binary_option_markets.values()))) + assert (any((first_match_bet_market_meta.market_id == market.id for market in all_binary_option_markets.values()))) From 8abeb382d8378e54ac6ec4e715702159703911d8 Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 18 Aug 2023 00:55:26 -0300 Subject: [PATCH 25/40] (feat) Added a component to calculate gas limit for the Transaction Broadcaster based on the messages (without running the transaction simulation) --- .../46_MessageBroadcasterWithoutSimulation.py | 64 +++++ ...sterWithGranteeAccountWithoutSimulation.py | 54 ++++ .../explorer_rpc/1_GetTxByHash.py | 4 +- pyinjective/core/broadcaster.py | 155 +++++++++++- ...essage_based_transaction_fee_calculator.py | 231 ++++++++++++++++++ 5 files changed, 503 insertions(+), 5 deletions(-) create mode 100644 examples/chain_client/46_MessageBroadcasterWithoutSimulation.py create mode 100644 examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py create mode 100644 tests/core/test_message_based_transaction_fee_calculator.py diff --git a/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py b/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py new file mode 100644 index 00000000..847c79a9 --- /dev/null +++ b/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py @@ -0,0 +1,64 @@ +import asyncio + +from pyinjective.composer import Composer as ProtoMsgComposer +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.constant import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + composer = ProtoMsgComposer(network=network.string()) + private_key_in_hexa = "f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3" + + message_broadcaster = MsgBroadcasterWithPk.new_without_simulation( + network=network, + private_key=private_key_in_hexa, + use_secure_connection=True + ) + + priv_key = PrivateKey.from_hex(private_key_in_hexa) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + subaccount_id = address.get_subaccount_id(index=0) + + # prepare trade info + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + + spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + + spot_orders_to_create = [ + composer.SpotOrder( + market_id=spot_market_id_create, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=3, + quantity=55, + is_buy=True, + is_po=False + ), + composer.SpotOrder( + market_id=spot_market_id_create, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=300, + quantity=55, + is_buy=False, + is_po=False + ), + ] + + # prepare tx msg + msg = composer.MsgBatchUpdateOrders( + sender=address.to_acc_bech32(), + spot_orders_to_create=spot_orders_to_create, + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([msg]) + print("---Transaction Response---") + print(result) + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py b/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py new file mode 100644 index 00000000..b3311279 --- /dev/null +++ b/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py @@ -0,0 +1,54 @@ +import asyncio + +from pyinjective.composer import Composer as ProtoMsgComposer +from pyinjective.async_client import AsyncClient +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.constant import Network +from pyinjective.wallet import PrivateKey, Address + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + composer = ProtoMsgComposer(network=network.string()) + + # initialize grpc client + client = AsyncClient(network, insecure=False) + await client.sync_timeout_height() + + # load account + private_key_in_hexa = "5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e" + priv_key = PrivateKey.from_hex(private_key_in_hexa) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + + message_broadcaster = MsgBroadcasterWithPk.new_for_grantee_account_without_simulation( + network=network, + grantee_private_key=private_key_in_hexa, + use_secure_connection=True + ) + + # prepare tx msg + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + granter_inj_address = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + granter_address = Address.from_acc_bech32(granter_inj_address) + granter_subaccount_id = granter_address.get_subaccount_id(index=0) + + msg = composer.MsgCreateSpotLimitOrder( + sender=granter_inj_address, + market_id=market_id, + subaccount_id=granter_subaccount_id, + fee_recipient=address.to_acc_bech32(), + price=7.523, + quantity=0.01, + is_buy=True, + is_po=False + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([msg]) + print("---Transaction Response---") + print(result) + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/exchange_client/explorer_rpc/1_GetTxByHash.py b/examples/exchange_client/explorer_rpc/1_GetTxByHash.py index 7362d1e0..fa21e293 100644 --- a/examples/exchange_client/explorer_rpc/1_GetTxByHash.py +++ b/examples/exchange_client/explorer_rpc/1_GetTxByHash.py @@ -7,10 +7,10 @@ async def main() -> None: # select network: local, testnet, mainnet - network = Network.testnet() + network = Network.mainnet() client = AsyncClient(network, insecure=False) composer = Composer(network=network.string()) - tx_hash = "0F3EBEC1882E1EEAC5B7BDD836E976250F1CD072B79485877CEACCB92ACDDF52" + tx_hash = "50DD80270052D85835939A393127B5626917007E71A7ABD5205F1A094B976C1B" transaction_response = await client.get_tx_by_hash(tx_hash=tx_hash) print(transaction_response) diff --git a/pyinjective/core/broadcaster.py b/pyinjective/core/broadcaster.py index d213d8de..fb9f7eed 100644 --- a/pyinjective/core/broadcaster.py +++ b/pyinjective/core/broadcaster.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod from decimal import Decimal -from typing import List, Optional +from typing import Callable, List, Optional, Tuple import math from google.protobuf import any_pb2 @@ -9,6 +9,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.composer import Composer from pyinjective.constant import Network +from pyinjective.proto.cosmos.authz.v1beta1 import tx_pb2 as cosmos_authz_tx_pb class BroadcasterAccountConfig(ABC): @@ -86,6 +87,31 @@ def new_using_simulation( ) return instance + @classmethod + def new_without_simulation( + cls, + network: Network, + private_key: str, + use_secure_connection: bool = True, + client: Optional[AsyncClient] = None, + composer: Optional[Composer] = None, + ): + client = client or AsyncClient(network=network, insecure=not (use_secure_connection)) + composer = composer or Composer(network=client.network.string()) + account_config = StandardAccountBroadcasterConfig(private_key=private_key) + fee_calculator = MessageBasedTransactionFeeCalculator( + client=client, + composer=composer + ) + instance = cls( + network=network, + account_config=account_config, + client=client, + composer=composer, + fee_calculator=fee_calculator, + ) + return instance + @classmethod def new_for_grantee_account_using_simulation( cls, @@ -111,6 +137,31 @@ def new_for_grantee_account_using_simulation( ) return instance + @classmethod + def new_for_grantee_account_without_simulation( + cls, + network: Network, + grantee_private_key: str, + use_secure_connection: bool = True, + client: Optional[AsyncClient] = None, + composer: Optional[Composer] = None, + ): + client = client or AsyncClient(network=network, insecure=not (use_secure_connection)) + composer = composer or Composer(network=client.network.string()) + account_config = GranteeAccountBroadcasterConfig(grantee_private_key=grantee_private_key, composer=composer) + fee_calculator = MessageBasedTransactionFeeCalculator( + client=client, + composer=composer + ) + instance = cls( + network=network, + account_config=account_config, + client=client, + composer=composer, + fee_calculator=fee_calculator, + ) + return instance + async def broadcast(self, messages: List[any_pb2.Any]): await self._client.sync_timeout_height() await self._client.get_account(self._account_config.trading_injective_address) @@ -196,10 +247,16 @@ def messages_prepared_for_transaction(self, messages: List[any_pb2.Any]) -> List class SimulatedTransactionFeeCalculator(TransactionFeeCalculator): - def __init__(self, client: AsyncClient, composer: Composer, gas_price: Optional[int] = None): + def __init__( + self, + client: AsyncClient, + composer: Composer, + gas_price: Optional[int] = None, + gas_limit_adjustment_multiplier: Optional[Decimal] = None): self._client = client self._composer = composer self._gas_price = gas_price or self.DEFAULT_GAS_PRICE + self._gas_limit_adjustment_multiplier = gas_limit_adjustment_multiplier or Decimal("1.3") async def configure_gas_fee_for_transaction( self, @@ -216,7 +273,7 @@ async def configure_gas_fee_for_transaction( if not success: raise RuntimeError(f"Transaction simulation error: {sim_res}") - gas_limit = math.ceil(Decimal(str(sim_res.gas_info.gas_used)) * Decimal("1.1")) + gas_limit = math.ceil(Decimal(str(sim_res.gas_info.gas_used)) * self._gas_limit_adjustment_multiplier) fee = [ self._composer.Coin( @@ -227,3 +284,95 @@ async def configure_gas_fee_for_transaction( transaction.with_gas(gas=gas_limit) transaction.with_fee(fee=fee) + + +class MessageBasedTransactionFeeCalculator(TransactionFeeCalculator): + DEFAULT_GAS_LIMIT = 400_000 + DEFAULT_EXCHANGE_GAS_LIMIT = 200_000 + + def __init__( + self, + client: AsyncClient, + composer: Composer, + gas_price: Optional[int] = None, + base_gas_limit: Optional[int] = None, + base_exchange_gas_limit: Optional[int] = None): + self._client = client + self._composer = composer + self._gas_price = gas_price or self.DEFAULT_GAS_PRICE + self._base_gas_limit = base_gas_limit or self.DEFAULT_GAS_LIMIT + self._base_exchange_gas_limit = base_exchange_gas_limit or self.DEFAULT_EXCHANGE_GAS_LIMIT + + self._gas_limit_per_message_type_rules: List[Tuple[Callable, Decimal]] = [ + ( + lambda message: "MsgPrivilegedExecuteContract" in self._message_type(message=message), + Decimal("6") * self._base_gas_limit + ), + ( + lambda message: "MsgExecuteContract" in self._message_type(message=message), + Decimal("2.5") * self._base_gas_limit + ), + ( + lambda message: "wasm" in self._message_type(message=message), + Decimal("1.5") * self._base_gas_limit + ), + ( + lambda message: "exchange" in self._message_type(message=message), + Decimal("1") * self._base_exchange_gas_limit + ), + ( + lambda message: self._is_governance_message(message=message), + Decimal("15") * self._base_gas_limit + ), + ] + + async def configure_gas_fee_for_transaction( + self, + transaction: Transaction, + private_key: PrivateKey, + public_key: PublicKey, + ): + transaction_gas_limit = math.ceil(self._calculate_gas_limit(messages=transaction.msgs)) + + fee = [ + self._composer.Coin( + amount=math.ceil(self._gas_price * transaction_gas_limit), + denom=self._client.network.fee_denom, + ) + ] + + transaction.with_gas(gas=transaction_gas_limit) + transaction.with_fee(fee=fee) + + def _message_type(self, message: any_pb2.Any) -> str: + if isinstance(message, any_pb2.Any): + message_type = message.type_url + else: + message_type = message.DESCRIPTOR.full_name + return message_type + + def _is_governance_message(self, message: any_pb2.Any) -> bool: + message_type = self._message_type(message=message) + return "gov" in message_type and ("MsgDeposit" in message_type or "MsgSubmitProposal" in message_type) + + def _calculate_gas_limit(self, messages: List[any_pb2.Any]) -> int: + total_gas_limit = Decimal("0") + + for message in messages: + applying_rule = next( + (rule_tuple for rule_tuple in self._gas_limit_per_message_type_rules + if rule_tuple[0](message)), + None + ) + + if applying_rule is None: + total_gas_limit += self._base_gas_limit + else: + total_gas_limit += applying_rule[1] + + if self._message_type(message=message).endswith("MsgExec"): + exec_message = cosmos_authz_tx_pb.MsgExec.FromString(message.value) + sub_messages_limit = self._calculate_gas_limit(messages=exec_message.msgs) + total_gas_limit += sub_messages_limit + + return math.ceil(total_gas_limit) diff --git a/tests/core/test_message_based_transaction_fee_calculator.py b/tests/core/test_message_based_transaction_fee_calculator.py new file mode 100644 index 00000000..14bfea81 --- /dev/null +++ b/tests/core/test_message_based_transaction_fee_calculator.py @@ -0,0 +1,231 @@ +from decimal import Decimal + +import math +import pytest + +from pyinjective import Transaction +from pyinjective.async_client import AsyncClient +from pyinjective.composer import Composer +from pyinjective.constant import Network +from pyinjective.core.broadcaster import MessageBasedTransactionFeeCalculator +from pyinjective.proto.cosmos.gov.v1beta1 import tx_pb2 as gov_tx_pb2 +from pyinjective.proto.cosmwasm.wasm.v1 import tx_pb2 as wasm_tx_pb2 +from pyinjective.proto.injective.exchange.v1beta1 import tx_pb2 + + +class TestMessageBasedTransactionFeeCalculator: + + @pytest.mark.asyncio + async def test_gas_fee_for_privileged_execute_contract_message(self): + network = Network.testnet(node="sentry") + client = AsyncClient(network=network, insecure=False) + composer = Composer(network=network.string()) + calculator = MessageBasedTransactionFeeCalculator( + client=client, + composer=composer, + gas_price=5_000_000, + base_gas_limit=400_000, + base_exchange_gas_limit=150_000, + ) + + message = tx_pb2.MsgPrivilegedExecuteContract() + transaction = Transaction() + transaction.with_messages(message) + + await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) + + expected_gas_limit = math.ceil(Decimal(6) * 400_000) + assert(expected_gas_limit == transaction.fee.gas_limit) + assert(str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) + + @pytest.mark.asyncio + async def test_gas_fee_for_execute_contract_message(self): + network = Network.testnet(node="sentry") + client = AsyncClient(network=network, insecure=False) + composer = Composer(network=network.string()) + calculator = MessageBasedTransactionFeeCalculator( + client=client, + composer=composer, + gas_price=5_000_000, + base_gas_limit=400_000, + base_exchange_gas_limit=150_000, + ) + + message = composer.MsgExecuteContract( + sender="", + contract="", + msg="", + ) + transaction = Transaction() + transaction.with_messages(message) + + await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) + + expected_gas_limit = math.ceil(Decimal(2.5) * 400_000) + assert (expected_gas_limit == transaction.fee.gas_limit) + assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) + + @pytest.mark.asyncio + async def test_gas_fee_for_wasm_message(self): + network = Network.testnet(node="sentry") + client = AsyncClient(network=network, insecure=False) + composer = Composer(network=network.string()) + calculator = MessageBasedTransactionFeeCalculator( + client=client, + composer=composer, + gas_price=5_000_000, + base_gas_limit=400_000, + base_exchange_gas_limit=150_000, + ) + + message = wasm_tx_pb2.MsgInstantiateContract2() + transaction = Transaction() + transaction.with_messages(message) + + await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) + + expected_gas_limit = math.ceil(Decimal(1.5) * 400_000) + assert (expected_gas_limit == transaction.fee.gas_limit) + assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) + + @pytest.mark.asyncio + async def test_gas_fee_for_governance_message(self): + network = Network.testnet(node="sentry") + client = AsyncClient(network=network, insecure=False) + composer = Composer(network=network.string()) + calculator = MessageBasedTransactionFeeCalculator( + client=client, + composer=composer, + gas_price=5_000_000, + base_gas_limit=400_000, + base_exchange_gas_limit=150_000, + ) + + message = gov_tx_pb2.MsgDeposit() + transaction = Transaction() + transaction.with_messages(message) + + await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) + + expected_gas_limit = math.ceil(Decimal(15) * 400_000) + assert (expected_gas_limit == transaction.fee.gas_limit) + assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) + + @pytest.mark.asyncio + async def test_gas_fee_for_exchange_message(self): + network = Network.testnet(node="sentry") + client = AsyncClient(network=network, insecure=False) + composer = Composer(network=network.string()) + calculator = MessageBasedTransactionFeeCalculator( + client=client, + composer=composer, + gas_price=5_000_000, + base_gas_limit=400_000, + base_exchange_gas_limit=150_000, + ) + + message = composer.MsgCreateSpotLimitOrder( + sender="sender", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=7.523, + quantity=0.01, + is_buy=True, + is_po=False + ) + transaction = Transaction() + transaction.with_messages(message) + + await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) + + expected_gas_limit = math.ceil(Decimal(1) * 150_000) + assert (expected_gas_limit == transaction.fee.gas_limit) + assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) + + @pytest.mark.asyncio + async def test_gas_fee_for_msg_exec_message(self): + network = Network.testnet(node="sentry") + client = AsyncClient(network=network, insecure=False) + composer = Composer(network=network.string()) + calculator = MessageBasedTransactionFeeCalculator( + client=client, + composer=composer, + gas_price=5_000_000, + base_gas_limit=400_000, + base_exchange_gas_limit=150_000, + ) + + inner_message = composer.MsgCreateSpotLimitOrder( + sender="sender", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=7.523, + quantity=0.01, + is_buy=True, + is_po=False + ) + message = composer.MsgExec( + grantee="grantee", + msgs=[inner_message] + ) + transaction = Transaction() + transaction.with_messages(message) + + await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) + + expected_inner_message_gas_limit = Decimal(1) * 150_000 + expected_exec_message_gas_limit = 400_000 + expected_gas_limit = math.ceil(expected_exec_message_gas_limit + expected_inner_message_gas_limit) + assert (expected_gas_limit == transaction.fee.gas_limit) + assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) + + @pytest.mark.asyncio + async def test_gas_fee_for_two_messages_in_one_transaction(self): + network = Network.testnet(node="sentry") + client = AsyncClient(network=network, insecure=False) + composer = Composer(network=network.string()) + calculator = MessageBasedTransactionFeeCalculator( + client=client, + composer=composer, + gas_price=5_000_000, + base_gas_limit=400_000, + base_exchange_gas_limit=150_000, + ) + + inner_message = composer.MsgCreateSpotLimitOrder( + sender="sender", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=7.523, + quantity=0.01, + is_buy=True, + is_po=False + ) + message = composer.MsgExec( + grantee="grantee", + msgs=[inner_message] + ) + + send_message = composer.MsgSend( + from_address="address", + to_address='to_address', + amount=1, + denom='INJ' + ) + + transaction = Transaction() + transaction.with_messages(message, send_message) + + await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) + + expected_inner_message_gas_limit = Decimal(1) * 150_000 + expected_exec_message_gas_limit = 400_000 + expected_send_message_gas_limit = 400_000 + expected_gas_limit = math.ceil( + expected_exec_message_gas_limit + expected_inner_message_gas_limit + expected_send_message_gas_limit + ) + assert (expected_gas_limit == transaction.fee.gas_limit) + assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) From 41be5603a2ff281b91030546783151e14f5e50a2 Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 18 Aug 2023 00:58:52 -0300 Subject: [PATCH 26/40] (fix) Change version number and update README file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fdb3ae19..c073f127 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ make tests * Fixed Testnet network URLs **0.7.1** -* Include implementation of the MessageBroadcaster, to simplify the transaction creation and broadcasting process. +* Include implementation of the TransactionBroadcaster, to simplify the transaction creation and broadcasting process. **0.7.0.6** * ADD SEI/USDT in metadata From 34d1d74f6c5ec7b7e6fc8040e0b8120fb44c78ba Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 18 Aug 2023 12:47:44 -0300 Subject: [PATCH 27/40] (fix) Changes to gas limit estimation to reduce a little bit gas consumption --- pyinjective/async_client.py | 44 ++++++++++++++------------------- pyinjective/core/broadcaster.py | 10 ++++---- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 8e442bd5..256fd774 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -343,7 +343,7 @@ async def get_account(self, address: str) -> Optional[account_pb2.EthAccount]: try: metadata = await self.load_cookie(type="chain") account_any = (await self.stubAuth.Account( - auth_query.QueryAccountRequest.__call__(address=address), metadata=metadata + auth_query.QueryAccountRequest(address=address), metadata=metadata )).account account = account_pb2.EthAccount() if account_any.Is(account.DESCRIPTOR): @@ -380,7 +380,7 @@ async def simulate_tx( try: req = tx_service.SimulateRequest(tx_bytes=tx_byte) metadata = await self.load_cookie(type="chain") - return await self.stubTx.Simulate.__call__(req, metadata=metadata), True + return await self.stubTx.Simulate(request=req, metadata=metadata), True except grpc.RpcError as err: return err, False @@ -389,7 +389,7 @@ async def send_tx_sync_mode(self, tx_byte: bytes) -> abci_type.TxResponse: tx_bytes=tx_byte, mode=tx_service.BroadcastMode.BROADCAST_MODE_SYNC ) metadata = await self.load_cookie(type="chain") - result = await self.stubTx.BroadcastTx.__call__(req, metadata=metadata) + result = await self.stubTx.BroadcastTx(request=req, metadata=metadata) return result.tx_response async def send_tx_async_mode(self, tx_byte: bytes) -> abci_type.TxResponse: @@ -397,7 +397,7 @@ async def send_tx_async_mode(self, tx_byte: bytes) -> abci_type.TxResponse: tx_bytes=tx_byte, mode=tx_service.BroadcastMode.BROADCAST_MODE_ASYNC ) metadata = await self.load_cookie(type="chain") - result = await self.stubTx.BroadcastTx.__call__(req, metadata=metadata) + result = await self.stubTx.BroadcastTx(request=req, metadata=metadata) return result.tx_response async def send_tx_block_mode(self, tx_byte: bytes) -> abci_type.TxResponse: @@ -405,7 +405,7 @@ async def send_tx_block_mode(self, tx_byte: bytes) -> abci_type.TxResponse: tx_bytes=tx_byte, mode=tx_service.BroadcastMode.BROADCAST_MODE_BLOCK ) metadata = await self.load_cookie(type="chain") - result = await self.stubTx.BroadcastTx.__call__(req, metadata=metadata) + result = await self.stubTx.BroadcastTx(request=req, metadata=metadata) return result.tx_response async def get_chain_id(self) -> str: @@ -673,7 +673,7 @@ async def stream_spot_markets(self, **kwargs): market_ids=kwargs.get("market_ids") ) metadata = await self.load_cookie(type="exchange") - return self.stubSpotExchange.StreamMarkets.__call__(req, metadata=metadata) + return self.stubSpotExchange.StreamMarkets(request=req, metadata=metadata) async def get_spot_orderbookV2(self, market_id: str): req = spot_exchange_rpc_pb.OrderbookV2Request(market_id=market_id) @@ -730,12 +730,12 @@ async def get_spot_trades(self, **kwargs): async def stream_spot_orderbook_snapshot(self, market_ids: List[str]): req = spot_exchange_rpc_pb.StreamOrderbookV2Request(market_ids=market_ids) metadata = await self.load_cookie(type="exchange") - return self.stubSpotExchange.StreamOrderbookV2.__call__(req, metadata=metadata) + return self.stubSpotExchange.StreamOrderbookV2(request=req, metadata=metadata) async def stream_spot_orderbook_update(self, market_ids: List[str]): req = spot_exchange_rpc_pb.StreamOrderbookUpdateRequest(market_ids=market_ids) metadata = await self.load_cookie(type="exchange") - return self.stubSpotExchange.StreamOrderbookUpdate.__call__(req, metadata=metadata) + return self.stubSpotExchange.StreamOrderbookUpdate(request=req, metadata=metadata) async def stream_spot_orders(self, market_id: str, **kwargs): req = spot_exchange_rpc_pb.StreamOrdersRequest( @@ -744,7 +744,7 @@ async def stream_spot_orders(self, market_id: str, **kwargs): subaccount_id=kwargs.get("subaccount_id"), ) metadata = await self.load_cookie(type="exchange") - return self.stubSpotExchange.StreamOrders.__call__(req, metadata=metadata) + return self.stubSpotExchange.StreamOrders(request=req, metadata=metadata) async def stream_historical_spot_orders(self, market_id: str, **kwargs): req = spot_exchange_rpc_pb.StreamOrdersHistoryRequest( @@ -756,7 +756,7 @@ async def stream_historical_spot_orders(self, market_id: str, **kwargs): execution_types=kwargs.get("execution_types") ) metadata = await self.load_cookie(type="exchange") - return self.stubSpotExchange.StreamOrdersHistory.__call__(req, metadata=metadata) + return self.stubSpotExchange.StreamOrdersHistory(request=req, metadata=metadata) async def stream_historical_derivative_orders(self, market_id: str, **kwargs): req = derivative_exchange_rpc_pb.StreamOrdersHistoryRequest( @@ -768,7 +768,7 @@ async def stream_historical_derivative_orders(self, market_id: str, **kwargs): execution_types=kwargs.get("execution_types") ) metadata = await self.load_cookie(type="exchange") - return self.stubDerivativeExchange.StreamOrdersHistory.__call__(req, metadata=metadata) + return self.stubDerivativeExchange.StreamOrdersHistory(request=req, metadata=metadata) async def stream_spot_trades(self, **kwargs): req = spot_exchange_rpc_pb.StreamTradesRequest( @@ -781,7 +781,7 @@ async def stream_spot_trades(self, **kwargs): execution_types=kwargs.get("execution_types"), ) metadata = await self.load_cookie(type="exchange") - return self.stubSpotExchange.StreamTrades.__call__(req, metadata=metadata) + return self.stubSpotExchange.StreamTrades(request=req, metadata=metadata) async def get_spot_subaccount_orders(self, subaccount_id: str, **kwargs): req = spot_exchange_rpc_pb.SubaccountOrdersListRequest( @@ -821,7 +821,7 @@ async def stream_derivative_markets(self, **kwargs): market_ids=kwargs.get("market_ids") ) metadata = await self.load_cookie(type="exchange") - return self.stubDerivativeExchange.StreamMarket.__call__(req, metadata=metadata) + return self.stubDerivativeExchange.StreamMarket(request=req, metadata=metadata) async def get_derivative_orderbook(self, market_id: str): req = derivative_exchange_rpc_pb.OrderbookV2Request(market_id=market_id) @@ -887,16 +887,12 @@ async def get_derivative_trades(self, **kwargs): async def stream_derivative_orderbook_snapshot(self, market_ids: List[str]): req = derivative_exchange_rpc_pb.StreamOrderbookV2Request(market_ids=market_ids) metadata = await self.load_cookie(type="exchange") - return self.stubDerivativeExchange.StreamOrderbookV2.__call__( - req, metadata=metadata - ) + return self.stubDerivativeExchange.StreamOrderbookV2(request=req, metadata=metadata) async def stream_derivative_orderbook_update(self, market_ids: List[str]): req = derivative_exchange_rpc_pb.StreamOrderbookUpdateRequest(market_ids=market_ids) metadata = await self.load_cookie(type="exchange") - return self.stubDerivativeExchange.StreamOrderbookUpdate.__call__( - req, metadata=metadata - ) + return self.stubDerivativeExchange.StreamOrderbookUpdate(request=req, metadata=metadata) async def stream_derivative_orders(self, market_id: str, **kwargs): req = derivative_exchange_rpc_pb.StreamOrdersRequest( @@ -905,7 +901,7 @@ async def stream_derivative_orders(self, market_id: str, **kwargs): subaccount_id=kwargs.get("subaccount_id"), ) metadata = await self.load_cookie(type="exchange") - return self.stubDerivativeExchange.StreamOrders.__call__(req, metadata=metadata) + return self.stubDerivativeExchange.StreamOrders(request=req, metadata=metadata) async def stream_derivative_trades(self, **kwargs): req = derivative_exchange_rpc_pb.StreamTradesRequest( @@ -920,7 +916,7 @@ async def stream_derivative_trades(self, **kwargs): execution_types=kwargs.get("execution_types"), ) metadata = await self.load_cookie(type="exchange") - return self.stubDerivativeExchange.StreamTrades.__call__(req, metadata=metadata) + return self.stubDerivativeExchange.StreamTrades(request=req, metadata=metadata) async def get_derivative_positions(self, **kwargs): req = derivative_exchange_rpc_pb.PositionsRequest( @@ -942,9 +938,7 @@ async def stream_derivative_positions(self, **kwargs): subaccount_ids=kwargs.get("subaccount_ids"), ) metadata = await self.load_cookie(type="exchange") - return self.stubDerivativeExchange.StreamPositions.__call__( - req, metadata=metadata - ) + return self.stubDerivativeExchange.StreamPositions(request=req, metadata=metadata) async def get_derivative_liquidable_positions(self, **kwargs): req = derivative_exchange_rpc_pb.LiquidablePositionsRequest( @@ -1020,7 +1014,7 @@ async def stream_account_portfolio(self, account_address: str, **kwargs): type=kwargs.get("type") ) metadata = await self.load_cookie(type="exchange") - return self.stubPortfolio.StreamAccountPortfolio.__call__(req, metadata=metadata) + return self.stubPortfolio.StreamAccountPortfolio(request=req, metadata=metadata) async def composer(self): return Composer( diff --git a/pyinjective/core/broadcaster.py b/pyinjective/core/broadcaster.py index fb9f7eed..55606b85 100644 --- a/pyinjective/core/broadcaster.py +++ b/pyinjective/core/broadcaster.py @@ -287,8 +287,8 @@ async def configure_gas_fee_for_transaction( class MessageBasedTransactionFeeCalculator(TransactionFeeCalculator): - DEFAULT_GAS_LIMIT = 400_000 - DEFAULT_EXCHANGE_GAS_LIMIT = 200_000 + DEFAULT_GAS_LIMIT = 150_000 + DEFAULT_EXCHANGE_GAS_LIMIT = 100_000 def __init__( self, @@ -313,11 +313,11 @@ def __init__( Decimal("2.5") * self._base_gas_limit ), ( - lambda message: "wasm" in self._message_type(message=message), + lambda message: "wasm." in self._message_type(message=message), Decimal("1.5") * self._base_gas_limit ), ( - lambda message: "exchange" in self._message_type(message=message), + lambda message: "exchange." in self._message_type(message=message), Decimal("1") * self._base_exchange_gas_limit ), ( @@ -353,7 +353,7 @@ def _message_type(self, message: any_pb2.Any) -> str: def _is_governance_message(self, message: any_pb2.Any) -> bool: message_type = self._message_type(message=message) - return "gov" in message_type and ("MsgDeposit" in message_type or "MsgSubmitProposal" in message_type) + return "gov." in message_type and ("MsgDeposit" in message_type or "MsgSubmitProposal" in message_type) def _calculate_gas_limit(self, messages: List[any_pb2.Any]) -> int: total_gas_limit = Decimal("0") From 222b7216c1cc951e08e1913c566968d17469bf86 Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 18 Aug 2023 13:09:47 -0300 Subject: [PATCH 28/40] (fix) Undo change in the example to get a transaction by hash --- examples/exchange_client/explorer_rpc/1_GetTxByHash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/exchange_client/explorer_rpc/1_GetTxByHash.py b/examples/exchange_client/explorer_rpc/1_GetTxByHash.py index fa21e293..7362d1e0 100644 --- a/examples/exchange_client/explorer_rpc/1_GetTxByHash.py +++ b/examples/exchange_client/explorer_rpc/1_GetTxByHash.py @@ -7,10 +7,10 @@ async def main() -> None: # select network: local, testnet, mainnet - network = Network.mainnet() + network = Network.testnet() client = AsyncClient(network, insecure=False) composer = Composer(network=network.string()) - tx_hash = "50DD80270052D85835939A393127B5626917007E71A7ABD5205F1A094B976C1B" + tx_hash = "0F3EBEC1882E1EEAC5B7BDD836E976250F1CD072B79485877CEACCB92ACDDF52" transaction_response = await client.get_tx_by_hash(tx_hash=tx_hash) print(transaction_response) From d53eca672fd72067e6080936b7eb1b82e5375fae Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 22 Aug 2023 10:20:04 -0300 Subject: [PATCH 29/40] (feat) Improved the logic in the gas limit estimator component to consider the cost of each included element for batch messages --- pyinjective/core/broadcaster.py | 60 +- pyinjective/core/gas_limit_estimator.py | 307 ++++++++++ tests/core/test_gas_limit_estimator.py | 527 ++++++++++++++++++ ...essage_based_transaction_fee_calculator.py | 50 +- 4 files changed, 866 insertions(+), 78 deletions(-) create mode 100644 pyinjective/core/gas_limit_estimator.py create mode 100644 tests/core/test_gas_limit_estimator.py diff --git a/pyinjective/core/broadcaster.py b/pyinjective/core/broadcaster.py index 55606b85..cc9dc2bb 100644 --- a/pyinjective/core/broadcaster.py +++ b/pyinjective/core/broadcaster.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod from decimal import Decimal -from typing import Callable, List, Optional, Tuple +from typing import List, Optional import math from google.protobuf import any_pb2 @@ -9,7 +9,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.composer import Composer from pyinjective.constant import Network -from pyinjective.proto.cosmos.authz.v1beta1 import tx_pb2 as cosmos_authz_tx_pb +from pyinjective.core.gas_limit_estimator import GasLimitEstimator class BroadcasterAccountConfig(ABC): @@ -287,44 +287,16 @@ async def configure_gas_fee_for_transaction( class MessageBasedTransactionFeeCalculator(TransactionFeeCalculator): - DEFAULT_GAS_LIMIT = 150_000 - DEFAULT_EXCHANGE_GAS_LIMIT = 100_000 + TRANSACTION_GAS_LIMIT = 60_000 def __init__( self, client: AsyncClient, composer: Composer, - gas_price: Optional[int] = None, - base_gas_limit: Optional[int] = None, - base_exchange_gas_limit: Optional[int] = None): + gas_price: Optional[int] = None): self._client = client self._composer = composer self._gas_price = gas_price or self.DEFAULT_GAS_PRICE - self._base_gas_limit = base_gas_limit or self.DEFAULT_GAS_LIMIT - self._base_exchange_gas_limit = base_exchange_gas_limit or self.DEFAULT_EXCHANGE_GAS_LIMIT - - self._gas_limit_per_message_type_rules: List[Tuple[Callable, Decimal]] = [ - ( - lambda message: "MsgPrivilegedExecuteContract" in self._message_type(message=message), - Decimal("6") * self._base_gas_limit - ), - ( - lambda message: "MsgExecuteContract" in self._message_type(message=message), - Decimal("2.5") * self._base_gas_limit - ), - ( - lambda message: "wasm." in self._message_type(message=message), - Decimal("1.5") * self._base_gas_limit - ), - ( - lambda message: "exchange." in self._message_type(message=message), - Decimal("1") * self._base_exchange_gas_limit - ), - ( - lambda message: self._is_governance_message(message=message), - Decimal("15") * self._base_gas_limit - ), - ] async def configure_gas_fee_for_transaction( self, @@ -332,7 +304,8 @@ async def configure_gas_fee_for_transaction( private_key: PrivateKey, public_key: PublicKey, ): - transaction_gas_limit = math.ceil(self._calculate_gas_limit(messages=transaction.msgs)) + messages_gas_limit = math.ceil(self._calculate_gas_limit(messages=transaction.msgs)) + transaction_gas_limit = messages_gas_limit + self.TRANSACTION_GAS_LIMIT fee = [ self._composer.Coin( @@ -351,28 +324,11 @@ def _message_type(self, message: any_pb2.Any) -> str: message_type = message.DESCRIPTOR.full_name return message_type - def _is_governance_message(self, message: any_pb2.Any) -> bool: - message_type = self._message_type(message=message) - return "gov." in message_type and ("MsgDeposit" in message_type or "MsgSubmitProposal" in message_type) - def _calculate_gas_limit(self, messages: List[any_pb2.Any]) -> int: total_gas_limit = Decimal("0") for message in messages: - applying_rule = next( - (rule_tuple for rule_tuple in self._gas_limit_per_message_type_rules - if rule_tuple[0](message)), - None - ) - - if applying_rule is None: - total_gas_limit += self._base_gas_limit - else: - total_gas_limit += applying_rule[1] - - if self._message_type(message=message).endswith("MsgExec"): - exec_message = cosmos_authz_tx_pb.MsgExec.FromString(message.value) - sub_messages_limit = self._calculate_gas_limit(messages=exec_message.msgs) - total_gas_limit += sub_messages_limit + estimator = GasLimitEstimator.for_message(message=message) + total_gas_limit += estimator.gas_limit() return math.ceil(total_gas_limit) diff --git a/pyinjective/core/gas_limit_estimator.py b/pyinjective/core/gas_limit_estimator.py new file mode 100644 index 00000000..d21c385b --- /dev/null +++ b/pyinjective/core/gas_limit_estimator.py @@ -0,0 +1,307 @@ +from abc import ABC, abstractmethod + +from google.protobuf import any_pb2 + +from pyinjective.proto.cosmos.authz.v1beta1 import tx_pb2 as cosmos_authz_tx_pb +from pyinjective.proto.cosmos.gov.v1beta1 import tx_pb2 as gov_tx_pb +from pyinjective.proto.cosmwasm.wasm.v1 import tx_pb2 as wasm_tx_pb +from pyinjective.proto.injective.exchange.v1beta1 import tx_pb2 as injective_exchange_tx_pb + + +class GasLimitEstimator(ABC): + GENERAL_MESSAGE_GAS_LIMIT = 5_000 + BASIC_REFERENCE_GAS_LIMIT = 150_000 + + @classmethod + @abstractmethod + def applies_to(cls, message: any_pb2.Any) -> bool: + ... + + @classmethod + def for_message(cls, message: any_pb2.Any): + estimator_class = next((estimator_subclass for estimator_subclass in cls.__subclasses__() + if estimator_subclass.applies_to(message=message)), + None) + if estimator_class is None: + estimator = DefaultGasLimitEstimator() + else: + estimator = estimator_class(message=message) + + return estimator + + @abstractmethod + def gas_limit(self) -> int: + ... + + @staticmethod + def message_type(message: any_pb2.Any) -> str: + if isinstance(message, any_pb2.Any): + message_type = message.type_url + else: + message_type = message.DESCRIPTOR.full_name + return message_type + + @abstractmethod + def _message_class(self, message: any_pb2.Any): + ... + + def _parsed_message(self, message: any_pb2.Any) -> any_pb2.Any: + if isinstance(message, any_pb2.Any): + parsed_message = self._message_class(message=message).FromString(message.value) + else: + parsed_message = message + return parsed_message + + +class DefaultGasLimitEstimator(GasLimitEstimator): + DEFAULT_GAS_LIMIT = 150_000 + + @classmethod + def applies_to(cls, message: any_pb2.Any) -> bool: + return False + + def gas_limit(self) -> int: + return self.DEFAULT_GAS_LIMIT + + def _message_class(self, message: any_pb2.Any): + # This class should not try to convert messages + raise NotImplementedError + + +class BatchCreateSpotLimitOrdersGasLimitEstimator(GasLimitEstimator): + ORDER_GAS_LIMIT = 45_000 + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any): + return cls.message_type(message=message).endswith("MsgBatchCreateSpotLimitOrders") + + def gas_limit(self) -> int: + total = 0 + total += self.GENERAL_MESSAGE_GAS_LIMIT + total += len(self._message.orders) * self.ORDER_GAS_LIMIT + + return total + + def _message_class(self, message: any_pb2.Any): + return injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders + + +class BatchCancelSpotOrdersGasLimitEstimator(GasLimitEstimator): + ORDER_GAS_LIMIT = 45_000 + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any): + return cls.message_type(message=message).endswith("MsgBatchCancelSpotOrders") + + def gas_limit(self) -> int: + total = 0 + total += self.GENERAL_MESSAGE_GAS_LIMIT + total += len(self._message.data) * self.ORDER_GAS_LIMIT + + return total + + def _message_class(self, message: any_pb2.Any): + return injective_exchange_tx_pb.MsgBatchCancelSpotOrders + + +class BatchCreateDerivativeLimitOrdersGasLimitEstimator(GasLimitEstimator): + ORDER_GAS_LIMIT = 60_000 + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any): + return cls.message_type(message=message).endswith("MsgBatchCreateDerivativeLimitOrders") + + def gas_limit(self) -> int: + total = 0 + total += self.GENERAL_MESSAGE_GAS_LIMIT + total += len(self._message.orders) * self.ORDER_GAS_LIMIT + + return total + + def _message_class(self, message: any_pb2.Any): + return injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders + + +class BatchCancelDerivativeOrdersGasLimitEstimator(GasLimitEstimator): + ORDER_GAS_LIMIT = 55_000 + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any): + return cls.message_type(message=message).endswith("MsgBatchCancelDerivativeOrders") + + def gas_limit(self) -> int: + total = 0 + total += self.GENERAL_MESSAGE_GAS_LIMIT + total += len(self._message.data) * self.ORDER_GAS_LIMIT + + return total + + def _message_class(self, message: any_pb2.Any): + return injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders + + +class BatchUpdateOrdersGasLimitEstimator(GasLimitEstimator): + SPOT_ORDER_CREATION_GAS_LIMIT = 40_000 + DERIVATIVE_ORDER_CREATION_GAS_LIMIT = 60_000 + SPOT_ORDER_CANCELATION_GAS_LIMIT = 45_000 + DERIVATIVE_ORDER_CANCELATION_GAS_LIMIT = 55_000 + CANCEL_ALL_SPOT_MARKET_GAS_LIMIT = 35_000 + CANCEL_ALL_DERIVATIVE_MARKET_GAS_LIMIT = 45_000 + MESSAGE_GAS_LIMIT = 10_000 + + AVERAGE_CANCEL_ALL_AFFECTED_ORDERS = 20 + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any): + return cls.message_type(message=message).endswith("MsgBatchUpdateOrders") + + def gas_limit(self) -> int: + total = 0 + total += self.MESSAGE_GAS_LIMIT + total += len(self._message.spot_orders_to_create) * self.SPOT_ORDER_CREATION_GAS_LIMIT + total += len(self._message.derivative_orders_to_create) * self.DERIVATIVE_ORDER_CREATION_GAS_LIMIT + total += len(self._message.binary_options_orders_to_create) * self.DERIVATIVE_ORDER_CREATION_GAS_LIMIT + total += len(self._message.spot_orders_to_cancel) * self.SPOT_ORDER_CANCELATION_GAS_LIMIT + total += len(self._message.derivative_orders_to_cancel) * self.DERIVATIVE_ORDER_CANCELATION_GAS_LIMIT + total += len(self._message.binary_options_orders_to_cancel) * self.DERIVATIVE_ORDER_CANCELATION_GAS_LIMIT + + total += (len(self._message.spot_market_ids_to_cancel_all) + * self.CANCEL_ALL_SPOT_MARKET_GAS_LIMIT + * self.AVERAGE_CANCEL_ALL_AFFECTED_ORDERS) + total += (len(self._message.derivative_market_ids_to_cancel_all) + * self.CANCEL_ALL_DERIVATIVE_MARKET_GAS_LIMIT + * self.AVERAGE_CANCEL_ALL_AFFECTED_ORDERS) + total += (len(self._message.binary_options_market_ids_to_cancel_all) + * self.CANCEL_ALL_DERIVATIVE_MARKET_GAS_LIMIT + * self.AVERAGE_CANCEL_ALL_AFFECTED_ORDERS) + + return total + + def _message_class(self, message: any_pb2.Any): + return injective_exchange_tx_pb.MsgBatchUpdateOrders + + +class ExecGasLimitEstimator(GasLimitEstimator): + DEFAULT_GAS_LIMIT = 5_000 + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any) -> bool: + return cls.message_type(message=message).endswith("MsgExec") + + def gas_limit(self) -> int: + total = sum([GasLimitEstimator.for_message(message=inner_message).gas_limit() + for inner_message in self._message.msgs]) + total += self.DEFAULT_GAS_LIMIT + + return total + + def _message_class(self, message: any_pb2.Any): + return cosmos_authz_tx_pb.MsgExec + + +class PrivilegedExecuteContractGasLimitEstimator(GasLimitEstimator): + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any) -> bool: + return cls.message_type(message=message).endswith("MsgPrivilegedExecuteContract") + + def gas_limit(self) -> int: + return self.BASIC_REFERENCE_GAS_LIMIT * 6 + + def _message_class(self, message: any_pb2.Any): + return injective_exchange_tx_pb.MsgPrivilegedExecuteContract + + +class ExecuteContractGasLimitEstimator(GasLimitEstimator): + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any) -> bool: + return cls.message_type(message=message).endswith("MsgExecuteContract") + + def gas_limit(self) -> int: + return int(self.BASIC_REFERENCE_GAS_LIMIT * 2.5) + + def _message_class(self, message: any_pb2.Any): + return wasm_tx_pb.MsgExecuteContract + + +class GeneralWasmGasLimitEstimator(GasLimitEstimator): + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any) -> bool: + return "wasm." in cls.message_type(message=message) + + def gas_limit(self) -> int: + return int(self.BASIC_REFERENCE_GAS_LIMIT * 1.5) + + def _message_class(self, message: any_pb2.Any): + return wasm_tx_pb.MsgInstantiateContract2 + + +class GovernanceGasLimitEstimator(GasLimitEstimator): + + def __init__(self, message: any_pb2.Any): + self._message = self._parsed_message(message=message) + + @classmethod + def applies_to(cls, message: any_pb2.Any) -> bool: + message_type = cls.message_type(message=message) + return "gov." in message_type and ( + message_type.endswith("MsgDeposit") or message_type.endswith("MsgSubmitProposal") + ) + + def gas_limit(self) -> int: + return int(self.BASIC_REFERENCE_GAS_LIMIT * 15) + + def _message_class(self, message: any_pb2.Any): + if "MsgDeposit" in self.message_type(message=message): + message_class = gov_tx_pb.MsgDeposit + else: + message_class = gov_tx_pb.MsgSubmitProposal + return message_class + + +class GenericExchangeGasLimitEstimator(GasLimitEstimator): + BASIC_REFERENCE_GAS_LIMIT = 100_000 + + def __init__(self, message: any_pb2.Any): + self._message = message + + @classmethod + def applies_to(cls, message: any_pb2.Any) -> bool: + message_type = cls.message_type(message=message) + return "exchange." in message_type + + def gas_limit(self) -> int: + return self.BASIC_REFERENCE_GAS_LIMIT + + def _message_class(self, message: any_pb2.Any): + # This class applies to many different messages, but we don't need to transform from Any format + raise NotImplementedError diff --git a/tests/core/test_gas_limit_estimator.py b/tests/core/test_gas_limit_estimator.py new file mode 100644 index 00000000..070ebb26 --- /dev/null +++ b/tests/core/test_gas_limit_estimator.py @@ -0,0 +1,527 @@ +from pyinjective.composer import Composer +from pyinjective.core.gas_limit_estimator import GasLimitEstimator +from pyinjective.proto.cosmos.gov.v1beta1 import tx_pb2 as gov_tx_pb +from pyinjective.proto.cosmwasm.wasm.v1 import tx_pb2 as wasm_tx_pb +from pyinjective.proto.injective.exchange.v1beta1 import tx_pb2 as injective_exchange_tx_pb + + +class TestGasLimitEstimator: + + def test_estimation_for_message_without_applying_rule(self): + composer = Composer(network="testnet") + message = composer.MsgSend( + from_address="from_address", + to_address="to_address", + amount=1, + denom='INJ' + ) + + estimator = GasLimitEstimator.for_message(message=message) + + expected_message_gas_limit = 150_000 + + assert(expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_create_spot_limit_orders(self): + spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + composer = Composer(network="testnet") + orders = [ + composer.SpotOrder( + market_id=spot_market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=5, + quantity=1, + is_buy=True, + is_po=False + ), + composer.SpotOrder( + market_id=spot_market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=4, + quantity=1, + is_buy=True, + is_po=False + ), + ] + message = composer.MsgBatchCreateSpotLimitOrders( + sender="sender", + orders=orders + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 45000 + expected_message_gas_limit = 5000 + + assert((expected_order_gas_limit * 2) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_cancel_spot_orders(self): + spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + composer = Composer(network="testnet") + orders = [ + composer.OrderData( + market_id=spot_market_id, + subaccount_id="subaccount_id", + order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d" + ), + composer.OrderData( + market_id=spot_market_id, + subaccount_id="subaccount_id", + order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2" + ), + composer.OrderData( + market_id=spot_market_id, + subaccount_id="subaccount_id", + order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5" + ) + ] + message = composer.MsgBatchCancelSpotOrders( + sender="sender", + data=orders + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 45000 + expected_message_gas_limit = 5000 + + assert((expected_order_gas_limit * 3) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_create_derivative_limit_orders(self): + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + composer = Composer(network="testnet") + orders = [ + composer.DerivativeOrder( + market_id=market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=3, + quantity=1, + leverage=1, + is_buy=True, + is_po=False + ), + composer.DerivativeOrder( + market_id=market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=20, + quantity=1, + leverage=1, + is_buy=False, + is_reduce_only=False + ), + ] + message = composer.MsgBatchCreateDerivativeLimitOrders( + sender="sender", + orders=orders + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 60_000 + expected_message_gas_limit = 5000 + + assert((expected_order_gas_limit * 2) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_cancel_derivative_orders(self): + spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + composer = Composer(network="testnet") + orders = [ + composer.OrderData( + market_id=spot_market_id, + subaccount_id="subaccount_id", + order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d" + ), + composer.OrderData( + market_id=spot_market_id, + subaccount_id="subaccount_id", + order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2" + ), + composer.OrderData( + market_id=spot_market_id, + subaccount_id="subaccount_id", + order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5" + ) + ] + message = composer.MsgBatchCancelDerivativeOrders( + sender="sender", + data=orders + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 55_000 + expected_message_gas_limit = 5000 + + assert((expected_order_gas_limit * 3) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_update_orders_to_create_spot_orders(self): + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + composer = Composer(network="testnet") + orders = [ + composer.SpotOrder( + market_id=market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=5, + quantity=1, + is_buy=True, + is_po=False + ), + composer.SpotOrder( + market_id=market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=4, + quantity=1, + is_buy=True, + is_po=False + ), + ] + message = composer.MsgBatchUpdateOrders( + sender="senders", + derivative_orders_to_create=[], + spot_orders_to_create=orders, + derivative_orders_to_cancel=[], + spot_orders_to_cancel=[] + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 40_000 + expected_message_gas_limit = 10_000 + + assert((expected_order_gas_limit * 2) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_update_orders_to_create_derivative_orders(self): + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + composer = Composer(network="testnet") + orders = [ + composer.DerivativeOrder( + market_id=market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=3, + quantity=1, + leverage=1, + is_buy=True, + is_po=False + ), + composer.DerivativeOrder( + market_id=market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=20, + quantity=1, + leverage=1, + is_buy=False, + is_reduce_only=False + ), + ] + message = composer.MsgBatchUpdateOrders( + sender="senders", + derivative_orders_to_create=orders, + spot_orders_to_create=[], + derivative_orders_to_cancel=[], + spot_orders_to_cancel=[] + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 60_000 + expected_message_gas_limit = 10_000 + + assert((expected_order_gas_limit * 2) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_update_orders_to_create_binary_orders(self): + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + composer = Composer(network="testnet") + orders = [ + composer.BinaryOptionsOrder( + market_id=market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=3, + quantity=1, + leverage=1, + is_buy=True, + is_po=False + ), + composer.BinaryOptionsOrder( + market_id=market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=20, + quantity=1, + leverage=1, + is_buy=False, + is_reduce_only=False + ), + ] + message = composer.MsgBatchUpdateOrders( + sender="senders", + derivative_orders_to_create=[], + spot_orders_to_create=[], + binary_options_orders_to_create=orders, + derivative_orders_to_cancel=[], + spot_orders_to_cancel=[] + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 60_000 + expected_message_gas_limit = 10_000 + + assert((expected_order_gas_limit * 2) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_update_orders_to_cancel_spot_orders(self): + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + composer = Composer(network="testnet") + orders = [ + composer.OrderData( + market_id=market_id, + subaccount_id="subaccount_id", + order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d" + ), + composer.OrderData( + market_id=market_id, + subaccount_id="subaccount_id", + order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2" + ), + composer.OrderData( + market_id=market_id, + subaccount_id="subaccount_id", + order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5" + ) + ] + message = composer.MsgBatchUpdateOrders( + sender="senders", + derivative_orders_to_create=[], + spot_orders_to_create=[], + derivative_orders_to_cancel=[], + spot_orders_to_cancel=orders + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 45_000 + expected_message_gas_limit = 10_000 + + assert((expected_order_gas_limit * 3) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_update_orders_to_cancel_derivative_orders(self): + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + composer = Composer(network="testnet") + orders = [ + composer.OrderData( + market_id=market_id, + subaccount_id="subaccount_id", + order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d" + ), + composer.OrderData( + market_id=market_id, + subaccount_id="subaccount_id", + order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2" + ), + composer.OrderData( + market_id=market_id, + subaccount_id="subaccount_id", + order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5" + ) + ] + message = composer.MsgBatchUpdateOrders( + sender="senders", + derivative_orders_to_create=[], + spot_orders_to_create=[], + derivative_orders_to_cancel=orders, + spot_orders_to_cancel=[] + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 55_000 + expected_message_gas_limit = 10_000 + + assert((expected_order_gas_limit * 3) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_update_orders_to_cancel_binary_orders(self): + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + composer = Composer(network="testnet") + orders = [ + composer.OrderData( + market_id=market_id, + subaccount_id="subaccount_id", + order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d" + ), + composer.OrderData( + market_id=market_id, + subaccount_id="subaccount_id", + order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2" + ), + composer.OrderData( + market_id=market_id, + subaccount_id="subaccount_id", + order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5" + ) + ] + message = composer.MsgBatchUpdateOrders( + sender="senders", + derivative_orders_to_create=[], + spot_orders_to_create=[], + derivative_orders_to_cancel=[], + spot_orders_to_cancel=[], + binary_options_orders_to_cancel=orders, + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 55_000 + expected_message_gas_limit = 10_000 + + assert((expected_order_gas_limit * 3) + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_update_orders_to_cancel_all_for_spot_market(self): + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + composer = Composer(network="testnet") + + message = composer.MsgBatchUpdateOrders( + sender="senders", + subaccount_id="subaccount_id", + spot_market_ids_to_cancel_all=[market_id], + derivative_orders_to_create=[], + spot_orders_to_create=[], + derivative_orders_to_cancel=[], + spot_orders_to_cancel=[] + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_gas_limit = 35_000 * 20 + expected_message_gas_limit = 10_000 + + assert(expected_gas_limit + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_update_orders_to_cancel_all_for_derivative_market(self): + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + composer = Composer(network="testnet") + + message = composer.MsgBatchUpdateOrders( + sender="senders", + subaccount_id="subaccount_id", + derivative_market_ids_to_cancel_all=[market_id], + derivative_orders_to_create=[], + spot_orders_to_create=[], + derivative_orders_to_cancel=[], + spot_orders_to_cancel=[] + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_gas_limit = 45_000 * 20 + expected_message_gas_limit = 10_000 + + assert(expected_gas_limit + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_batch_update_orders_to_cancel_all_for_binary_options_market(self): + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + composer = Composer(network="testnet") + + message = composer.MsgBatchUpdateOrders( + sender="senders", + subaccount_id="subaccount_id", + binary_options_market_ids_to_cancel_all=[market_id], + derivative_orders_to_create=[], + spot_orders_to_create=[], + derivative_orders_to_cancel=[], + spot_orders_to_cancel=[] + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_gas_limit = 45_000 * 20 + expected_message_gas_limit = 10_000 + + assert(expected_gas_limit + expected_message_gas_limit == estimator.gas_limit()) + + def test_estimation_for_exec_message(self): + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + composer = Composer(network="testnet") + orders = [ + composer.SpotOrder( + market_id=market_id, + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=5, + quantity=1, + is_buy=True, + is_po=False + ), + ] + inner_message = composer.MsgBatchUpdateOrders( + sender="senders", + derivative_orders_to_create=[], + spot_orders_to_create=orders, + derivative_orders_to_cancel=[], + spot_orders_to_cancel=[] + ) + message = composer.MsgExec( + grantee="grantee", + msgs=[inner_message] + ) + + estimator = GasLimitEstimator.for_message(message=message) + + expected_order_gas_limit = 40_000 + expected_inner_message_gas_limit = 10_000 + expected_exec_message_gas_limit = 5_000 + + assert(expected_order_gas_limit + + expected_inner_message_gas_limit + + expected_exec_message_gas_limit + == estimator.gas_limit()) + + def test_estimation_for_privileged_execute_contract_message(self): + message = injective_exchange_tx_pb.MsgPrivilegedExecuteContract() + estimator = GasLimitEstimator.for_message(message=message) + + expected_gas_limit = 900_000 + + assert(expected_gas_limit == estimator.gas_limit()) + + + def test_estimation_for_execute_contract_message(self): + composer = Composer(network="testnet") + message = composer.MsgExecuteContract( + sender="", + contract="", + msg="", + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_gas_limit = 375_000 + + assert(expected_gas_limit == estimator.gas_limit()) + + def test_estimation_for_wasm_message(self): + message = wasm_tx_pb.MsgInstantiateContract2() + estimator = GasLimitEstimator.for_message(message=message) + + expected_gas_limit = 225_000 + + assert(expected_gas_limit == estimator.gas_limit()) + + def test_estimation_for_governance_message(self): + message = gov_tx_pb.MsgDeposit() + estimator = GasLimitEstimator.for_message(message=message) + + expected_gas_limit = 2_250_000 + + assert(expected_gas_limit == estimator.gas_limit()) + + def test_estimation_for_generic_exchange_message(self): + composer = Composer(network="testnet") + message = composer.MsgCreateSpotLimitOrder( + sender="sender", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="subaccount_id", + fee_recipient="fee_recipient", + price=7.523, + quantity=0.01, + is_buy=True, + is_po=False + ) + estimator = GasLimitEstimator.for_message(message=message) + + expected_gas_limit = 100_000 + + assert(expected_gas_limit == estimator.gas_limit()) diff --git a/tests/core/test_message_based_transaction_fee_calculator.py b/tests/core/test_message_based_transaction_fee_calculator.py index 14bfea81..602b71af 100644 --- a/tests/core/test_message_based_transaction_fee_calculator.py +++ b/tests/core/test_message_based_transaction_fee_calculator.py @@ -24,8 +24,6 @@ async def test_gas_fee_for_privileged_execute_contract_message(self): client=client, composer=composer, gas_price=5_000_000, - base_gas_limit=400_000, - base_exchange_gas_limit=150_000, ) message = tx_pb2.MsgPrivilegedExecuteContract() @@ -34,7 +32,8 @@ async def test_gas_fee_for_privileged_execute_contract_message(self): await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) - expected_gas_limit = math.ceil(Decimal(6) * 400_000) + expected_transaction_gas_limit = 60_000 + expected_gas_limit = math.ceil(Decimal(6) * 150_000 + expected_transaction_gas_limit) assert(expected_gas_limit == transaction.fee.gas_limit) assert(str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) @@ -47,8 +46,6 @@ async def test_gas_fee_for_execute_contract_message(self): client=client, composer=composer, gas_price=5_000_000, - base_gas_limit=400_000, - base_exchange_gas_limit=150_000, ) message = composer.MsgExecuteContract( @@ -61,7 +58,8 @@ async def test_gas_fee_for_execute_contract_message(self): await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) - expected_gas_limit = math.ceil(Decimal(2.5) * 400_000) + expected_transaction_gas_limit = 60_000 + expected_gas_limit = math.ceil(Decimal(2.5) * 150_000 + expected_transaction_gas_limit) assert (expected_gas_limit == transaction.fee.gas_limit) assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) @@ -74,8 +72,6 @@ async def test_gas_fee_for_wasm_message(self): client=client, composer=composer, gas_price=5_000_000, - base_gas_limit=400_000, - base_exchange_gas_limit=150_000, ) message = wasm_tx_pb2.MsgInstantiateContract2() @@ -84,7 +80,8 @@ async def test_gas_fee_for_wasm_message(self): await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) - expected_gas_limit = math.ceil(Decimal(1.5) * 400_000) + expected_transaction_gas_limit = 60_000 + expected_gas_limit = math.ceil(Decimal(1.5) * 150_000 + expected_transaction_gas_limit) assert (expected_gas_limit == transaction.fee.gas_limit) assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) @@ -97,8 +94,6 @@ async def test_gas_fee_for_governance_message(self): client=client, composer=composer, gas_price=5_000_000, - base_gas_limit=400_000, - base_exchange_gas_limit=150_000, ) message = gov_tx_pb2.MsgDeposit() @@ -107,7 +102,8 @@ async def test_gas_fee_for_governance_message(self): await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) - expected_gas_limit = math.ceil(Decimal(15) * 400_000) + expected_transaction_gas_limit = 60_000 + expected_gas_limit = math.ceil(Decimal(15) * 150_000 + expected_transaction_gas_limit) assert (expected_gas_limit == transaction.fee.gas_limit) assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) @@ -120,8 +116,6 @@ async def test_gas_fee_for_exchange_message(self): client=client, composer=composer, gas_price=5_000_000, - base_gas_limit=400_000, - base_exchange_gas_limit=150_000, ) message = composer.MsgCreateSpotLimitOrder( @@ -139,7 +133,8 @@ async def test_gas_fee_for_exchange_message(self): await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) - expected_gas_limit = math.ceil(Decimal(1) * 150_000) + expected_transaction_gas_limit = 60_000 + expected_gas_limit = math.ceil(Decimal(1) * 100_000 + expected_transaction_gas_limit) assert (expected_gas_limit == transaction.fee.gas_limit) assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) @@ -152,8 +147,6 @@ async def test_gas_fee_for_msg_exec_message(self): client=client, composer=composer, gas_price=5_000_000, - base_gas_limit=400_000, - base_exchange_gas_limit=150_000, ) inner_message = composer.MsgCreateSpotLimitOrder( @@ -175,9 +168,12 @@ async def test_gas_fee_for_msg_exec_message(self): await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) - expected_inner_message_gas_limit = Decimal(1) * 150_000 - expected_exec_message_gas_limit = 400_000 - expected_gas_limit = math.ceil(expected_exec_message_gas_limit + expected_inner_message_gas_limit) + expected_transaction_gas_limit = 60_000 + expected_inner_message_gas_limit = Decimal(1) * 100_000 + expected_exec_message_gas_limit = 5_000 + expected_gas_limit = math.ceil( + expected_exec_message_gas_limit + expected_inner_message_gas_limit + expected_transaction_gas_limit + ) assert (expected_gas_limit == transaction.fee.gas_limit) assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) @@ -190,8 +186,6 @@ async def test_gas_fee_for_two_messages_in_one_transaction(self): client=client, composer=composer, gas_price=5_000_000, - base_gas_limit=400_000, - base_exchange_gas_limit=150_000, ) inner_message = composer.MsgCreateSpotLimitOrder( @@ -221,11 +215,15 @@ async def test_gas_fee_for_two_messages_in_one_transaction(self): await calculator.configure_gas_fee_for_transaction(transaction=transaction, private_key=None, public_key=None) - expected_inner_message_gas_limit = Decimal(1) * 150_000 - expected_exec_message_gas_limit = 400_000 - expected_send_message_gas_limit = 400_000 + expected_transaction_gas_limit = 60_000 + expected_inner_message_gas_limit = Decimal(1) * 100_000 + expected_exec_message_gas_limit = 5_000 + expected_send_message_gas_limit = 150_000 expected_gas_limit = math.ceil( - expected_exec_message_gas_limit + expected_inner_message_gas_limit + expected_send_message_gas_limit + expected_exec_message_gas_limit + + expected_inner_message_gas_limit + + expected_send_message_gas_limit + + expected_transaction_gas_limit ) assert (expected_gas_limit == transaction.fee.gas_limit) assert (str(expected_gas_limit * 5_000_000) == transaction.fee.amount[0].amount) From 3ecfb4d3ef5ae28ef3bb6029edc8ca9cd1adfe95 Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 22 Aug 2023 16:15:45 -0300 Subject: [PATCH 30/40] (fix) Updated library version number and README file --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c073f127..fa59c16e 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,9 @@ make tests **0.7.1.1** * Fixed Testnet network URLs +**0.7.1.1** +* Fixed Testnet network URLs + **0.7.1** * Include implementation of the TransactionBroadcaster, to simplify the transaction creation and broadcasting process. From f8710906256dd67d0bdc6722c90bb6d29e991da9 Mon Sep 17 00:00:00 2001 From: abel Date: Wed, 23 Aug 2023 10:14:16 -0300 Subject: [PATCH 31/40] (feat) Created the cookies admin for load balanced mainnet and testnet nodes. --- examples/SendToInjective.py | 2 +- examples/chain_client/0_LocalOrderHash.py | 2 +- .../13_MsgIncreasePositionMargin.py | 2 +- examples/chain_client/15_MsgWithdraw.py | 2 +- .../chain_client/16_MsgSubaccountTransfer.py | 2 +- .../chain_client/17_MsgBatchUpdateOrders.py | 2 +- examples/chain_client/18_MsgBid.py | 2 +- examples/chain_client/19_MsgGrant.py | 2 +- examples/chain_client/1_MsgSend.py | 2 +- examples/chain_client/20_MsgExec.py | 2 +- examples/chain_client/21_MsgRevoke.py | 2 +- examples/chain_client/22_MsgSendToEth.py | 2 +- .../chain_client/23_MsgRelayPriceFeedPrice.py | 2 +- examples/chain_client/24_MsgRewardsOptOut.py | 2 +- examples/chain_client/25_MsgDelegate.py | 2 +- .../26_MsgWithdrawDelegatorReward.py | 2 +- examples/chain_client/27_Grants.py | 3 +- examples/chain_client/28_BankBalances.py | 3 +- examples/chain_client/29_BankBalance.py | 3 +- examples/chain_client/2_MsgDeposit.py | 2 +- examples/chain_client/30_ExternalTransfer.py | 2 +- .../31_MsgCreateBinaryOptionsLimitOrder.py | 3 +- .../32_MsgCreateBinaryOptionsMarketOrder.py | 2 +- .../33_MsgCancelBinaryOptionsOrder.py | 2 +- .../34_MsgAdminUpdateBinaryOptionsMarket.py | 2 +- .../35_MsgInstantBinaryOptionsMarketLaunch.py | 2 +- .../chain_client/36_MsgRelayProviderPrices.py | 2 +- examples/chain_client/37_GetTx.py | 3 +- .../chain_client/38_StreamEventOrderFail.py | 3 +- examples/chain_client/39_Account.py | 3 +- .../chain_client/3_MsgCreateSpotLimitOrder.py | 2 +- .../chain_client/40_MsgExecuteContract.py | 2 +- .../chain_client/41_MsgCreateInsuranceFund.py | 2 +- examples/chain_client/42_MsgUnderwrite.py | 2 +- .../chain_client/43_MsgRequestRedemption.py | 2 +- .../chain_client/44_MessageBroadcaster.py | 2 +- ...45_MessageBroadcasterWithGranteeAccount.py | 2 +- .../46_MessageBroadcasterWithoutSimulation.py | 2 +- ...sterWithGranteeAccountWithoutSimulation.py | 2 +- .../4_MsgCreateSpotMarketOrder.py | 2 +- examples/chain_client/5_MsgCancelSpotOrder.py | 2 +- .../6_MsgCreateDerivativeLimitOrder.py | 2 +- .../7_MsgCreateDerivativeMarketOrder.py | 2 +- .../8_MsgCancelDerivativeOrder.py | 2 +- .../accounts_rpc/1_StreamSubaccountBalance.py | 3 +- .../accounts_rpc/2_SubaccountBalance.py | 3 +- .../accounts_rpc/3_SubaccountsList.py | 3 +- .../accounts_rpc/4_SubaccountBalancesList.py | 3 +- .../accounts_rpc/5_SubaccountHistory.py | 3 +- .../accounts_rpc/6_SubaccountOrderSummary.py | 3 +- .../accounts_rpc/7_OrderStates.py | 3 +- .../accounts_rpc/8_Portfolio.py | 3 +- .../exchange_client/accounts_rpc/9_Rewards.py | 3 +- .../exchange_client/auctions_rpc/1_Auction.py | 3 +- .../auctions_rpc/2_Auctions.py | 3 +- .../auctions_rpc/3_StreamBids.py | 3 +- .../10_StreamHistoricalOrders.py | 3 +- .../derivative_exchange_rpc/11_Trades.py | 3 +- .../12_StreamTrades.py | 3 +- .../13_SubaccountOrdersList.py | 3 +- .../14_SubaccountTradesList.py | 3 +- .../15_FundingPayments.py | 3 +- .../17_FundingRates.py | 3 +- .../derivative_exchange_rpc/18_Orderbooks.py | 2 +- .../19_Binary_Options_Markets.py | 3 +- .../derivative_exchange_rpc/1_Market.py | 3 +- .../20_Binary_Options_Market.py | 3 +- .../21_Historical_Orders.py | 3 +- .../22_OrderbooksV2.py | 3 +- .../derivative_exchange_rpc/2_Markets.py | 3 +- .../derivative_exchange_rpc/3_StreamMarket.py | 3 +- .../derivative_exchange_rpc/4_Orderbook.py | 3 +- .../5_StreamOrderbooks.py | 2 +- .../6_StreamOrderbookUpdate.py | 2 +- .../derivative_exchange_rpc/7_Positions.py | 3 +- .../9_StreamPositions.py | 3 +- .../explorer_rpc/10_GetIBCTransfers.py | 3 +- .../explorer_rpc/1_GetTxByHash.py | 3 +- .../explorer_rpc/2_AccountTxs.py | 3 +- .../exchange_client/explorer_rpc/3_Blocks.py | 3 +- .../exchange_client/explorer_rpc/4_Block.py | 3 +- .../explorer_rpc/5_TxsRequest.py | 3 +- .../explorer_rpc/6_StreamTxs.py | 3 +- .../explorer_rpc/7_StreamBlocks.py | 3 +- .../explorer_rpc/8_GetPeggyDeposits.py | 3 +- .../explorer_rpc/9_GetPeggyWithdrawals.py | 3 +- .../insurance_rpc/1_InsuranceFunds.py | 3 +- .../insurance_rpc/2_Redemptions.py | 3 +- examples/exchange_client/meta_rpc/1_Ping.py | 3 +- .../exchange_client/meta_rpc/2_Version.py | 3 +- examples/exchange_client/meta_rpc/3_Info.py | 3 +- .../meta_rpc/4_StreamKeepAlive.py | 3 +- .../oracle_rpc/1_StreamPrices.py | 3 +- .../exchange_client/oracle_rpc/2_Price.py | 3 +- .../oracle_rpc/3_OracleList.py | 3 +- .../portfolio_rpc/1_AccountPortfolio.py | 3 +- .../portfolio_rpc/2_StreamAccountPortfolio.py | 2 +- .../spot_exchange_rpc/10_StreamTrades.py | 3 +- .../11_SubaccountOrdersList.py | 3 +- .../12_SubaccountTradesList.py | 3 +- .../spot_exchange_rpc/13_StreamOrderbooks.py | 3 +- .../spot_exchange_rpc/14_Orderbooks.py | 3 +- .../spot_exchange_rpc/15_HistoricalOrders.py | 3 +- .../spot_exchange_rpc/1_Market.py | 3 +- .../spot_exchange_rpc/2_Markets.py | 3 +- .../spot_exchange_rpc/3_StreamMarkets.py | 3 +- .../spot_exchange_rpc/4_Orderbook.py | 3 +- .../spot_exchange_rpc/6_Trades.py | 3 +- .../7_StreamOrderbookSnapshot.py | 2 +- .../8_StreamOrderbookUpdate.py | 2 +- .../9_StreamHistoricalOrders.py | 3 +- pyinjective/async_client.py | 2 +- pyinjective/client.py | 2 +- pyinjective/constant.py | 132 ------- pyinjective/core/broadcaster.py | 2 +- pyinjective/core/network.py | 354 ++++++++++++++++++ pyinjective/utils/fetch_metadata.py | 10 +- ...essage_based_transaction_fee_calculator.py | 2 +- tests/test_orderhash.py | 2 +- 119 files changed, 539 insertions(+), 257 deletions(-) create mode 100644 pyinjective/core/network.py diff --git a/examples/SendToInjective.py b/examples/SendToInjective.py index 7a27841b..5d0d1072 100644 --- a/examples/SendToInjective.py +++ b/examples/SendToInjective.py @@ -4,7 +4,7 @@ import asyncio import logging -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.sendtocosmos import Peggo import importlib.resources as pkg_resources diff --git a/examples/chain_client/0_LocalOrderHash.py b/examples/chain_client/0_LocalOrderHash.py index 6c037209..7ce7de68 100644 --- a/examples/chain_client/0_LocalOrderHash.py +++ b/examples/chain_client/0_LocalOrderHash.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey from pyinjective.orderhash import OrderHashManager diff --git a/examples/chain_client/13_MsgIncreasePositionMargin.py b/examples/chain_client/13_MsgIncreasePositionMargin.py index 46630a99..2aa66a13 100644 --- a/examples/chain_client/13_MsgIncreasePositionMargin.py +++ b/examples/chain_client/13_MsgIncreasePositionMargin.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/15_MsgWithdraw.py b/examples/chain_client/15_MsgWithdraw.py index 5694ae46..51baf733 100644 --- a/examples/chain_client/15_MsgWithdraw.py +++ b/examples/chain_client/15_MsgWithdraw.py @@ -16,7 +16,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/16_MsgSubaccountTransfer.py b/examples/chain_client/16_MsgSubaccountTransfer.py index 3af6e7a7..80cb0ee5 100644 --- a/examples/chain_client/16_MsgSubaccountTransfer.py +++ b/examples/chain_client/16_MsgSubaccountTransfer.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/17_MsgBatchUpdateOrders.py b/examples/chain_client/17_MsgBatchUpdateOrders.py index bcfff042..4ce2cc56 100644 --- a/examples/chain_client/17_MsgBatchUpdateOrders.py +++ b/examples/chain_client/17_MsgBatchUpdateOrders.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/18_MsgBid.py b/examples/chain_client/18_MsgBid.py index e48ef1fa..eba03940 100644 --- a/examples/chain_client/18_MsgBid.py +++ b/examples/chain_client/18_MsgBid.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey async def main() -> None: diff --git a/examples/chain_client/19_MsgGrant.py b/examples/chain_client/19_MsgGrant.py index 2b0bbb7b..1d58a24b 100644 --- a/examples/chain_client/19_MsgGrant.py +++ b/examples/chain_client/19_MsgGrant.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/1_MsgSend.py b/examples/chain_client/1_MsgSend.py index 0a37afc1..72556625 100644 --- a/examples/chain_client/1_MsgSend.py +++ b/examples/chain_client/1_MsgSend.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/20_MsgExec.py b/examples/chain_client/20_MsgExec.py index 231a939f..12f4526c 100644 --- a/examples/chain_client/20_MsgExec.py +++ b/examples/chain_client/20_MsgExec.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey, Address diff --git a/examples/chain_client/21_MsgRevoke.py b/examples/chain_client/21_MsgRevoke.py index e6d35bd2..db39f714 100644 --- a/examples/chain_client/21_MsgRevoke.py +++ b/examples/chain_client/21_MsgRevoke.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/22_MsgSendToEth.py b/examples/chain_client/22_MsgSendToEth.py index 3b9abfc8..afaf3030 100644 --- a/examples/chain_client/22_MsgSendToEth.py +++ b/examples/chain_client/22_MsgSendToEth.py @@ -3,7 +3,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey async def main() -> None: diff --git a/examples/chain_client/23_MsgRelayPriceFeedPrice.py b/examples/chain_client/23_MsgRelayPriceFeedPrice.py index 1f9bfc53..e17f05a2 100644 --- a/examples/chain_client/23_MsgRelayPriceFeedPrice.py +++ b/examples/chain_client/23_MsgRelayPriceFeedPrice.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/24_MsgRewardsOptOut.py b/examples/chain_client/24_MsgRewardsOptOut.py index 34c48bc7..da4fc0fc 100644 --- a/examples/chain_client/24_MsgRewardsOptOut.py +++ b/examples/chain_client/24_MsgRewardsOptOut.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/25_MsgDelegate.py b/examples/chain_client/25_MsgDelegate.py index d040dfd2..f2f25db6 100644 --- a/examples/chain_client/25_MsgDelegate.py +++ b/examples/chain_client/25_MsgDelegate.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/26_MsgWithdrawDelegatorReward.py b/examples/chain_client/26_MsgWithdrawDelegatorReward.py index c133f0ec..99d87b62 100644 --- a/examples/chain_client/26_MsgWithdrawDelegatorReward.py +++ b/examples/chain_client/26_MsgWithdrawDelegatorReward.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/27_Grants.py b/examples/chain_client/27_Grants.py index 7f16ecac..2ff81236 100644 --- a/examples/chain_client/27_Grants.py +++ b/examples/chain_client/27_Grants.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/chain_client/28_BankBalances.py b/examples/chain_client/28_BankBalances.py index 6a185ccc..84424426 100644 --- a/examples/chain_client/28_BankBalances.py +++ b/examples/chain_client/28_BankBalances.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/chain_client/29_BankBalance.py b/examples/chain_client/29_BankBalance.py index aab01086..1f38a02d 100644 --- a/examples/chain_client/29_BankBalance.py +++ b/examples/chain_client/29_BankBalance.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/chain_client/2_MsgDeposit.py b/examples/chain_client/2_MsgDeposit.py index a1684ddc..709c0bf2 100644 --- a/examples/chain_client/2_MsgDeposit.py +++ b/examples/chain_client/2_MsgDeposit.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/30_ExternalTransfer.py b/examples/chain_client/30_ExternalTransfer.py index 1fcef982..ab2b9034 100644 --- a/examples/chain_client/30_ExternalTransfer.py +++ b/examples/chain_client/30_ExternalTransfer.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py index 0d33b93d..dfa03aa3 100644 --- a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py +++ b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py @@ -2,7 +2,8 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network, Denom +from pyinjective.constant import Denom +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey async def main() -> None: diff --git a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py index 12b808c4..62030441 100644 --- a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py +++ b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py index 7a4d1197..557f1dd9 100644 --- a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py +++ b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py index 5037c899..78e7e88e 100644 --- a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py +++ b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py index e20e54b9..99510b6b 100644 --- a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py +++ b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/36_MsgRelayProviderPrices.py b/examples/chain_client/36_MsgRelayProviderPrices.py index bd88d650..41cabe90 100644 --- a/examples/chain_client/36_MsgRelayProviderPrices.py +++ b/examples/chain_client/36_MsgRelayProviderPrices.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/37_GetTx.py b/examples/chain_client/37_GetTx.py index 2e2487bc..d2eb72fa 100644 --- a/examples/chain_client/37_GetTx.py +++ b/examples/chain_client/37_GetTx.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/chain_client/38_StreamEventOrderFail.py b/examples/chain_client/38_StreamEventOrderFail.py index 1b3f760f..e453fd12 100644 --- a/examples/chain_client/38_StreamEventOrderFail.py +++ b/examples/chain_client/38_StreamEventOrderFail.py @@ -4,7 +4,8 @@ import websockets import base64 -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.mainnet() diff --git a/examples/chain_client/39_Account.py b/examples/chain_client/39_Account.py index 50d30c76..b30232ec 100644 --- a/examples/chain_client/39_Account.py +++ b/examples/chain_client/39_Account.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/chain_client/3_MsgCreateSpotLimitOrder.py b/examples/chain_client/3_MsgCreateSpotLimitOrder.py index 5501b01b..daba1a39 100644 --- a/examples/chain_client/3_MsgCreateSpotLimitOrder.py +++ b/examples/chain_client/3_MsgCreateSpotLimitOrder.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/40_MsgExecuteContract.py b/examples/chain_client/40_MsgExecuteContract.py index d3ab1dda..949caa1d 100644 --- a/examples/chain_client/40_MsgExecuteContract.py +++ b/examples/chain_client/40_MsgExecuteContract.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/41_MsgCreateInsuranceFund.py b/examples/chain_client/41_MsgCreateInsuranceFund.py index 1a511f05..3fb0c5cc 100644 --- a/examples/chain_client/41_MsgCreateInsuranceFund.py +++ b/examples/chain_client/41_MsgCreateInsuranceFund.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey async def main() -> None: diff --git a/examples/chain_client/42_MsgUnderwrite.py b/examples/chain_client/42_MsgUnderwrite.py index d7d04fb3..79cfe5d7 100644 --- a/examples/chain_client/42_MsgUnderwrite.py +++ b/examples/chain_client/42_MsgUnderwrite.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey async def main() -> None: diff --git a/examples/chain_client/43_MsgRequestRedemption.py b/examples/chain_client/43_MsgRequestRedemption.py index 640a42d2..8d434368 100644 --- a/examples/chain_client/43_MsgRequestRedemption.py +++ b/examples/chain_client/43_MsgRequestRedemption.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey async def main() -> None: diff --git a/examples/chain_client/44_MessageBroadcaster.py b/examples/chain_client/44_MessageBroadcaster.py index b144c0cc..10d157fc 100644 --- a/examples/chain_client/44_MessageBroadcaster.py +++ b/examples/chain_client/44_MessageBroadcaster.py @@ -2,7 +2,7 @@ from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.core.broadcaster import MsgBroadcasterWithPk -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py b/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py index f0b4c7e8..81417a1e 100644 --- a/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py +++ b/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py @@ -3,7 +3,7 @@ from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.core.broadcaster import MsgBroadcasterWithPk -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey, Address diff --git a/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py b/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py index 847c79a9..4e062d63 100644 --- a/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py +++ b/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py @@ -2,7 +2,7 @@ from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.core.broadcaster import MsgBroadcasterWithPk -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py b/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py index b3311279..371f852d 100644 --- a/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py +++ b/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py @@ -3,7 +3,7 @@ from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.async_client import AsyncClient from pyinjective.core.broadcaster import MsgBroadcasterWithPk -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey, Address diff --git a/examples/chain_client/4_MsgCreateSpotMarketOrder.py b/examples/chain_client/4_MsgCreateSpotMarketOrder.py index 0f234d0b..827e653d 100644 --- a/examples/chain_client/4_MsgCreateSpotMarketOrder.py +++ b/examples/chain_client/4_MsgCreateSpotMarketOrder.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/5_MsgCancelSpotOrder.py b/examples/chain_client/5_MsgCancelSpotOrder.py index ced2467f..602beb7a 100644 --- a/examples/chain_client/5_MsgCancelSpotOrder.py +++ b/examples/chain_client/5_MsgCancelSpotOrder.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py index b507ac71..dc175e20 100644 --- a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py +++ b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py index d7b0b574..88a18eb8 100644 --- a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py +++ b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/chain_client/8_MsgCancelDerivativeOrder.py b/examples/chain_client/8_MsgCancelDerivativeOrder.py index 2f668e5c..3784bdc6 100644 --- a/examples/chain_client/8_MsgCancelDerivativeOrder.py +++ b/examples/chain_client/8_MsgCancelDerivativeOrder.py @@ -2,7 +2,7 @@ from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey diff --git a/examples/exchange_client/accounts_rpc/1_StreamSubaccountBalance.py b/examples/exchange_client/accounts_rpc/1_StreamSubaccountBalance.py index 53d85f90..bc0017ba 100644 --- a/examples/exchange_client/accounts_rpc/1_StreamSubaccountBalance.py +++ b/examples/exchange_client/accounts_rpc/1_StreamSubaccountBalance.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/accounts_rpc/2_SubaccountBalance.py b/examples/exchange_client/accounts_rpc/2_SubaccountBalance.py index 61ef0396..eeabafd1 100644 --- a/examples/exchange_client/accounts_rpc/2_SubaccountBalance.py +++ b/examples/exchange_client/accounts_rpc/2_SubaccountBalance.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/accounts_rpc/3_SubaccountsList.py b/examples/exchange_client/accounts_rpc/3_SubaccountsList.py index d037106c..54abf051 100644 --- a/examples/exchange_client/accounts_rpc/3_SubaccountsList.py +++ b/examples/exchange_client/accounts_rpc/3_SubaccountsList.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/accounts_rpc/4_SubaccountBalancesList.py b/examples/exchange_client/accounts_rpc/4_SubaccountBalancesList.py index c5c8b9de..49320cfa 100644 --- a/examples/exchange_client/accounts_rpc/4_SubaccountBalancesList.py +++ b/examples/exchange_client/accounts_rpc/4_SubaccountBalancesList.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/accounts_rpc/5_SubaccountHistory.py b/examples/exchange_client/accounts_rpc/5_SubaccountHistory.py index 66d9875b..93e75d89 100644 --- a/examples/exchange_client/accounts_rpc/5_SubaccountHistory.py +++ b/examples/exchange_client/accounts_rpc/5_SubaccountHistory.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/accounts_rpc/6_SubaccountOrderSummary.py b/examples/exchange_client/accounts_rpc/6_SubaccountOrderSummary.py index f0bf85fd..eb49ee05 100644 --- a/examples/exchange_client/accounts_rpc/6_SubaccountOrderSummary.py +++ b/examples/exchange_client/accounts_rpc/6_SubaccountOrderSummary.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/accounts_rpc/7_OrderStates.py b/examples/exchange_client/accounts_rpc/7_OrderStates.py index c0851ed6..75747360 100644 --- a/examples/exchange_client/accounts_rpc/7_OrderStates.py +++ b/examples/exchange_client/accounts_rpc/7_OrderStates.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/accounts_rpc/8_Portfolio.py b/examples/exchange_client/accounts_rpc/8_Portfolio.py index 9fea55a5..3f6fdd48 100644 --- a/examples/exchange_client/accounts_rpc/8_Portfolio.py +++ b/examples/exchange_client/accounts_rpc/8_Portfolio.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/accounts_rpc/9_Rewards.py b/examples/exchange_client/accounts_rpc/9_Rewards.py index f99d804f..a3139ab2 100644 --- a/examples/exchange_client/accounts_rpc/9_Rewards.py +++ b/examples/exchange_client/accounts_rpc/9_Rewards.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/auctions_rpc/1_Auction.py b/examples/exchange_client/auctions_rpc/1_Auction.py index 79fd2dc8..ec6a80ad 100644 --- a/examples/exchange_client/auctions_rpc/1_Auction.py +++ b/examples/exchange_client/auctions_rpc/1_Auction.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/auctions_rpc/2_Auctions.py b/examples/exchange_client/auctions_rpc/2_Auctions.py index fca61338..0fa3b5b4 100644 --- a/examples/exchange_client/auctions_rpc/2_Auctions.py +++ b/examples/exchange_client/auctions_rpc/2_Auctions.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/auctions_rpc/3_StreamBids.py b/examples/exchange_client/auctions_rpc/3_StreamBids.py index 60b6927f..5078f981 100644 --- a/examples/exchange_client/auctions_rpc/3_StreamBids.py +++ b/examples/exchange_client/auctions_rpc/3_StreamBids.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/10_StreamHistoricalOrders.py b/examples/exchange_client/derivative_exchange_rpc/10_StreamHistoricalOrders.py index 33ef76e4..22081c71 100644 --- a/examples/exchange_client/derivative_exchange_rpc/10_StreamHistoricalOrders.py +++ b/examples/exchange_client/derivative_exchange_rpc/10_StreamHistoricalOrders.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/11_Trades.py b/examples/exchange_client/derivative_exchange_rpc/11_Trades.py index 056d2155..665e4651 100644 --- a/examples/exchange_client/derivative_exchange_rpc/11_Trades.py +++ b/examples/exchange_client/derivative_exchange_rpc/11_Trades.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/12_StreamTrades.py b/examples/exchange_client/derivative_exchange_rpc/12_StreamTrades.py index 31dabd25..c6b6c48d 100644 --- a/examples/exchange_client/derivative_exchange_rpc/12_StreamTrades.py +++ b/examples/exchange_client/derivative_exchange_rpc/12_StreamTrades.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/13_SubaccountOrdersList.py b/examples/exchange_client/derivative_exchange_rpc/13_SubaccountOrdersList.py index 587e3b0e..d899ba2f 100644 --- a/examples/exchange_client/derivative_exchange_rpc/13_SubaccountOrdersList.py +++ b/examples/exchange_client/derivative_exchange_rpc/13_SubaccountOrdersList.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/14_SubaccountTradesList.py b/examples/exchange_client/derivative_exchange_rpc/14_SubaccountTradesList.py index 0d835437..adf2cee5 100644 --- a/examples/exchange_client/derivative_exchange_rpc/14_SubaccountTradesList.py +++ b/examples/exchange_client/derivative_exchange_rpc/14_SubaccountTradesList.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/15_FundingPayments.py b/examples/exchange_client/derivative_exchange_rpc/15_FundingPayments.py index ebde0a71..0f15c537 100644 --- a/examples/exchange_client/derivative_exchange_rpc/15_FundingPayments.py +++ b/examples/exchange_client/derivative_exchange_rpc/15_FundingPayments.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/17_FundingRates.py b/examples/exchange_client/derivative_exchange_rpc/17_FundingRates.py index 089b89b6..04122a7c 100644 --- a/examples/exchange_client/derivative_exchange_rpc/17_FundingRates.py +++ b/examples/exchange_client/derivative_exchange_rpc/17_FundingRates.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/18_Orderbooks.py b/examples/exchange_client/derivative_exchange_rpc/18_Orderbooks.py index 3996c9f2..cc1c8aca 100644 --- a/examples/exchange_client/derivative_exchange_rpc/18_Orderbooks.py +++ b/examples/exchange_client/derivative_exchange_rpc/18_Orderbooks.py @@ -2,7 +2,7 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network async def main() -> None: diff --git a/examples/exchange_client/derivative_exchange_rpc/19_Binary_Options_Markets.py b/examples/exchange_client/derivative_exchange_rpc/19_Binary_Options_Markets.py index f7e9b111..1fef009f 100644 --- a/examples/exchange_client/derivative_exchange_rpc/19_Binary_Options_Markets.py +++ b/examples/exchange_client/derivative_exchange_rpc/19_Binary_Options_Markets.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/derivative_exchange_rpc/1_Market.py b/examples/exchange_client/derivative_exchange_rpc/1_Market.py index 7666efe3..d2c6e80b 100644 --- a/examples/exchange_client/derivative_exchange_rpc/1_Market.py +++ b/examples/exchange_client/derivative_exchange_rpc/1_Market.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/20_Binary_Options_Market.py b/examples/exchange_client/derivative_exchange_rpc/20_Binary_Options_Market.py index 59949fee..0d1b9150 100644 --- a/examples/exchange_client/derivative_exchange_rpc/20_Binary_Options_Market.py +++ b/examples/exchange_client/derivative_exchange_rpc/20_Binary_Options_Market.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/derivative_exchange_rpc/21_Historical_Orders.py b/examples/exchange_client/derivative_exchange_rpc/21_Historical_Orders.py index 367ee214..eed98d99 100644 --- a/examples/exchange_client/derivative_exchange_rpc/21_Historical_Orders.py +++ b/examples/exchange_client/derivative_exchange_rpc/21_Historical_Orders.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/22_OrderbooksV2.py b/examples/exchange_client/derivative_exchange_rpc/22_OrderbooksV2.py index 35fe128f..8205a694 100644 --- a/examples/exchange_client/derivative_exchange_rpc/22_OrderbooksV2.py +++ b/examples/exchange_client/derivative_exchange_rpc/22_OrderbooksV2.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/2_Markets.py b/examples/exchange_client/derivative_exchange_rpc/2_Markets.py index 89242d02..9b7ec94f 100644 --- a/examples/exchange_client/derivative_exchange_rpc/2_Markets.py +++ b/examples/exchange_client/derivative_exchange_rpc/2_Markets.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/3_StreamMarket.py b/examples/exchange_client/derivative_exchange_rpc/3_StreamMarket.py index f4f09d9a..b44fa804 100644 --- a/examples/exchange_client/derivative_exchange_rpc/3_StreamMarket.py +++ b/examples/exchange_client/derivative_exchange_rpc/3_StreamMarket.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/4_Orderbook.py b/examples/exchange_client/derivative_exchange_rpc/4_Orderbook.py index 61575bc8..8d891a6c 100644 --- a/examples/exchange_client/derivative_exchange_rpc/4_Orderbook.py +++ b/examples/exchange_client/derivative_exchange_rpc/4_Orderbook.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/5_StreamOrderbooks.py b/examples/exchange_client/derivative_exchange_rpc/5_StreamOrderbooks.py index b50535ee..64304ec4 100644 --- a/examples/exchange_client/derivative_exchange_rpc/5_StreamOrderbooks.py +++ b/examples/exchange_client/derivative_exchange_rpc/5_StreamOrderbooks.py @@ -2,7 +2,7 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network async def main() -> None: diff --git a/examples/exchange_client/derivative_exchange_rpc/6_StreamOrderbookUpdate.py b/examples/exchange_client/derivative_exchange_rpc/6_StreamOrderbookUpdate.py index b1ac8804..b5f48c5a 100644 --- a/examples/exchange_client/derivative_exchange_rpc/6_StreamOrderbookUpdate.py +++ b/examples/exchange_client/derivative_exchange_rpc/6_StreamOrderbookUpdate.py @@ -3,7 +3,7 @@ from decimal import * from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network class PriceLevel: diff --git a/examples/exchange_client/derivative_exchange_rpc/7_Positions.py b/examples/exchange_client/derivative_exchange_rpc/7_Positions.py index f91ec4e8..36e871cb 100644 --- a/examples/exchange_client/derivative_exchange_rpc/7_Positions.py +++ b/examples/exchange_client/derivative_exchange_rpc/7_Positions.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/derivative_exchange_rpc/9_StreamPositions.py b/examples/exchange_client/derivative_exchange_rpc/9_StreamPositions.py index c1bad053..32586681 100644 --- a/examples/exchange_client/derivative_exchange_rpc/9_StreamPositions.py +++ b/examples/exchange_client/derivative_exchange_rpc/9_StreamPositions.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/10_GetIBCTransfers.py b/examples/exchange_client/explorer_rpc/10_GetIBCTransfers.py index 38602907..945d5313 100644 --- a/examples/exchange_client/explorer_rpc/10_GetIBCTransfers.py +++ b/examples/exchange_client/explorer_rpc/10_GetIBCTransfers.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/1_GetTxByHash.py b/examples/exchange_client/explorer_rpc/1_GetTxByHash.py index 7362d1e0..ad1be37f 100644 --- a/examples/exchange_client/explorer_rpc/1_GetTxByHash.py +++ b/examples/exchange_client/explorer_rpc/1_GetTxByHash.py @@ -3,7 +3,8 @@ from pyinjective.async_client import AsyncClient from pyinjective.composer import Composer -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/2_AccountTxs.py b/examples/exchange_client/explorer_rpc/2_AccountTxs.py index 7e5c7a3f..f0f7cca0 100644 --- a/examples/exchange_client/explorer_rpc/2_AccountTxs.py +++ b/examples/exchange_client/explorer_rpc/2_AccountTxs.py @@ -3,7 +3,8 @@ from pyinjective.async_client import AsyncClient from pyinjective.composer import Composer -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/3_Blocks.py b/examples/exchange_client/explorer_rpc/3_Blocks.py index 0b636ffd..0035c51d 100644 --- a/examples/exchange_client/explorer_rpc/3_Blocks.py +++ b/examples/exchange_client/explorer_rpc/3_Blocks.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/4_Block.py b/examples/exchange_client/explorer_rpc/4_Block.py index 91aac693..6ac9982f 100644 --- a/examples/exchange_client/explorer_rpc/4_Block.py +++ b/examples/exchange_client/explorer_rpc/4_Block.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/5_TxsRequest.py b/examples/exchange_client/explorer_rpc/5_TxsRequest.py index d8c53771..e01a7066 100644 --- a/examples/exchange_client/explorer_rpc/5_TxsRequest.py +++ b/examples/exchange_client/explorer_rpc/5_TxsRequest.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/6_StreamTxs.py b/examples/exchange_client/explorer_rpc/6_StreamTxs.py index d146ea81..52cde6d3 100644 --- a/examples/exchange_client/explorer_rpc/6_StreamTxs.py +++ b/examples/exchange_client/explorer_rpc/6_StreamTxs.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/7_StreamBlocks.py b/examples/exchange_client/explorer_rpc/7_StreamBlocks.py index da755cdb..a460ee14 100644 --- a/examples/exchange_client/explorer_rpc/7_StreamBlocks.py +++ b/examples/exchange_client/explorer_rpc/7_StreamBlocks.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/8_GetPeggyDeposits.py b/examples/exchange_client/explorer_rpc/8_GetPeggyDeposits.py index b2ecb90a..32a8f01a 100644 --- a/examples/exchange_client/explorer_rpc/8_GetPeggyDeposits.py +++ b/examples/exchange_client/explorer_rpc/8_GetPeggyDeposits.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/explorer_rpc/9_GetPeggyWithdrawals.py b/examples/exchange_client/explorer_rpc/9_GetPeggyWithdrawals.py index fc12d7a6..889b46df 100644 --- a/examples/exchange_client/explorer_rpc/9_GetPeggyWithdrawals.py +++ b/examples/exchange_client/explorer_rpc/9_GetPeggyWithdrawals.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/insurance_rpc/1_InsuranceFunds.py b/examples/exchange_client/insurance_rpc/1_InsuranceFunds.py index 7dd3a207..6e0885d1 100644 --- a/examples/exchange_client/insurance_rpc/1_InsuranceFunds.py +++ b/examples/exchange_client/insurance_rpc/1_InsuranceFunds.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/insurance_rpc/2_Redemptions.py b/examples/exchange_client/insurance_rpc/2_Redemptions.py index de0582e7..66e94ad9 100644 --- a/examples/exchange_client/insurance_rpc/2_Redemptions.py +++ b/examples/exchange_client/insurance_rpc/2_Redemptions.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/meta_rpc/1_Ping.py b/examples/exchange_client/meta_rpc/1_Ping.py index 0745dcbc..ce7bd3e3 100644 --- a/examples/exchange_client/meta_rpc/1_Ping.py +++ b/examples/exchange_client/meta_rpc/1_Ping.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/meta_rpc/2_Version.py b/examples/exchange_client/meta_rpc/2_Version.py index 3ed2581d..1cd63d81 100644 --- a/examples/exchange_client/meta_rpc/2_Version.py +++ b/examples/exchange_client/meta_rpc/2_Version.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/meta_rpc/3_Info.py b/examples/exchange_client/meta_rpc/3_Info.py index c6b5ba32..bd925f20 100644 --- a/examples/exchange_client/meta_rpc/3_Info.py +++ b/examples/exchange_client/meta_rpc/3_Info.py @@ -3,7 +3,8 @@ import time from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/meta_rpc/4_StreamKeepAlive.py b/examples/exchange_client/meta_rpc/4_StreamKeepAlive.py index e73ef56b..53092a05 100644 --- a/examples/exchange_client/meta_rpc/4_StreamKeepAlive.py +++ b/examples/exchange_client/meta_rpc/4_StreamKeepAlive.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/oracle_rpc/1_StreamPrices.py b/examples/exchange_client/oracle_rpc/1_StreamPrices.py index c4233229..3707aa72 100644 --- a/examples/exchange_client/oracle_rpc/1_StreamPrices.py +++ b/examples/exchange_client/oracle_rpc/1_StreamPrices.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/oracle_rpc/2_Price.py b/examples/exchange_client/oracle_rpc/2_Price.py index eb3abdd2..cf92aa1e 100644 --- a/examples/exchange_client/oracle_rpc/2_Price.py +++ b/examples/exchange_client/oracle_rpc/2_Price.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/oracle_rpc/3_OracleList.py b/examples/exchange_client/oracle_rpc/3_OracleList.py index 0eb58036..2ff2152c 100644 --- a/examples/exchange_client/oracle_rpc/3_OracleList.py +++ b/examples/exchange_client/oracle_rpc/3_OracleList.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/portfolio_rpc/1_AccountPortfolio.py b/examples/exchange_client/portfolio_rpc/1_AccountPortfolio.py index 4ab4def8..83b46d57 100644 --- a/examples/exchange_client/portfolio_rpc/1_AccountPortfolio.py +++ b/examples/exchange_client/portfolio_rpc/1_AccountPortfolio.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/portfolio_rpc/2_StreamAccountPortfolio.py b/examples/exchange_client/portfolio_rpc/2_StreamAccountPortfolio.py index 9c37cb42..bc587bb9 100644 --- a/examples/exchange_client/portfolio_rpc/2_StreamAccountPortfolio.py +++ b/examples/exchange_client/portfolio_rpc/2_StreamAccountPortfolio.py @@ -2,7 +2,7 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network async def main() -> None: diff --git a/examples/exchange_client/spot_exchange_rpc/10_StreamTrades.py b/examples/exchange_client/spot_exchange_rpc/10_StreamTrades.py index 392be977..d906378c 100644 --- a/examples/exchange_client/spot_exchange_rpc/10_StreamTrades.py +++ b/examples/exchange_client/spot_exchange_rpc/10_StreamTrades.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/spot_exchange_rpc/11_SubaccountOrdersList.py b/examples/exchange_client/spot_exchange_rpc/11_SubaccountOrdersList.py index 178934c5..a7ab90ef 100644 --- a/examples/exchange_client/spot_exchange_rpc/11_SubaccountOrdersList.py +++ b/examples/exchange_client/spot_exchange_rpc/11_SubaccountOrdersList.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/spot_exchange_rpc/12_SubaccountTradesList.py b/examples/exchange_client/spot_exchange_rpc/12_SubaccountTradesList.py index f67816d8..090b1fc3 100644 --- a/examples/exchange_client/spot_exchange_rpc/12_SubaccountTradesList.py +++ b/examples/exchange_client/spot_exchange_rpc/12_SubaccountTradesList.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/spot_exchange_rpc/13_StreamOrderbooks.py b/examples/exchange_client/spot_exchange_rpc/13_StreamOrderbooks.py index 5638b0d3..7171595b 100644 --- a/examples/exchange_client/spot_exchange_rpc/13_StreamOrderbooks.py +++ b/examples/exchange_client/spot_exchange_rpc/13_StreamOrderbooks.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py b/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py index 59d23047..b8b0840f 100644 --- a/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py +++ b/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/spot_exchange_rpc/15_HistoricalOrders.py b/examples/exchange_client/spot_exchange_rpc/15_HistoricalOrders.py index 1e3266c9..d116a8a7 100644 --- a/examples/exchange_client/spot_exchange_rpc/15_HistoricalOrders.py +++ b/examples/exchange_client/spot_exchange_rpc/15_HistoricalOrders.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/spot_exchange_rpc/1_Market.py b/examples/exchange_client/spot_exchange_rpc/1_Market.py index abc3b47a..e1c99b6e 100644 --- a/examples/exchange_client/spot_exchange_rpc/1_Market.py +++ b/examples/exchange_client/spot_exchange_rpc/1_Market.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/spot_exchange_rpc/2_Markets.py b/examples/exchange_client/spot_exchange_rpc/2_Markets.py index 59f0590b..ff7e3211 100644 --- a/examples/exchange_client/spot_exchange_rpc/2_Markets.py +++ b/examples/exchange_client/spot_exchange_rpc/2_Markets.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/spot_exchange_rpc/3_StreamMarkets.py b/examples/exchange_client/spot_exchange_rpc/3_StreamMarkets.py index 90b4a1a2..d697eeea 100644 --- a/examples/exchange_client/spot_exchange_rpc/3_StreamMarkets.py +++ b/examples/exchange_client/spot_exchange_rpc/3_StreamMarkets.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: # select network: local, testnet, mainnet diff --git a/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py b/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py index 19b58933..b1a107e2 100644 --- a/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py +++ b/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/spot_exchange_rpc/6_Trades.py b/examples/exchange_client/spot_exchange_rpc/6_Trades.py index 46cf0ee8..aab46ba2 100644 --- a/examples/exchange_client/spot_exchange_rpc/6_Trades.py +++ b/examples/exchange_client/spot_exchange_rpc/6_Trades.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/examples/exchange_client/spot_exchange_rpc/7_StreamOrderbookSnapshot.py b/examples/exchange_client/spot_exchange_rpc/7_StreamOrderbookSnapshot.py index 5514502e..9094d4ba 100644 --- a/examples/exchange_client/spot_exchange_rpc/7_StreamOrderbookSnapshot.py +++ b/examples/exchange_client/spot_exchange_rpc/7_StreamOrderbookSnapshot.py @@ -2,7 +2,7 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network async def main() -> None: diff --git a/examples/exchange_client/spot_exchange_rpc/8_StreamOrderbookUpdate.py b/examples/exchange_client/spot_exchange_rpc/8_StreamOrderbookUpdate.py index b39bf981..ea0a0a95 100644 --- a/examples/exchange_client/spot_exchange_rpc/8_StreamOrderbookUpdate.py +++ b/examples/exchange_client/spot_exchange_rpc/8_StreamOrderbookUpdate.py @@ -3,7 +3,7 @@ from decimal import * from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network class PriceLevel: diff --git a/examples/exchange_client/spot_exchange_rpc/9_StreamHistoricalOrders.py b/examples/exchange_client/spot_exchange_rpc/9_StreamHistoricalOrders.py index 6a10b2f4..48453eed 100644 --- a/examples/exchange_client/spot_exchange_rpc/9_StreamHistoricalOrders.py +++ b/examples/exchange_client/spot_exchange_rpc/9_StreamHistoricalOrders.py @@ -2,7 +2,8 @@ import logging from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network + async def main() -> None: network = Network.testnet() diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 256fd774..1eb0e0c4 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -71,7 +71,7 @@ account_pb2 ) -from .constant import Network +from .core.network import Network from .utils.logger import LoggerProvider DEFAULT_TIMEOUTHEIGHT_SYNC_INTERVAL = 20 # seconds diff --git a/pyinjective/client.py b/pyinjective/client.py index 10b82329..bb9baf7d 100644 --- a/pyinjective/client.py +++ b/pyinjective/client.py @@ -47,7 +47,7 @@ injective_auction_rpc_pb2_grpc as auction_rpc_grpc, ) -from .constant import Network +from .core.network import Network DEFAULT_TIMEOUTHEIGHT_SYNC_INTERVAL = 10 # seconds DEFAULT_TIMEOUTHEIGHT = 20 # blocks diff --git a/pyinjective/constant.py b/pyinjective/constant.py index 51320c93..49aaef3d 100644 --- a/pyinjective/constant.py +++ b/pyinjective/constant.py @@ -69,135 +69,3 @@ def load_peggy_denom(cls, network, symbol): else: config = mainnet_config return config[symbol]["peggy_denom"], int(config[symbol]["decimals"]) - - -class Network: - def __init__( - self, - lcd_endpoint: str , - tm_websocket_endpoint: str, - grpc_endpoint: str , - grpc_exchange_endpoint: str , - grpc_explorer_endpoint: str , - chain_id: str , - fee_denom: str , - env: str - ): - self.lcd_endpoint = lcd_endpoint - self.tm_websocket_endpoint = tm_websocket_endpoint - self.grpc_endpoint = grpc_endpoint - self.grpc_exchange_endpoint = grpc_exchange_endpoint - self.grpc_explorer_endpoint = grpc_explorer_endpoint - self.chain_id = chain_id - self.fee_denom = fee_denom - self.env = env - - @classmethod - def devnet(cls): - return cls( - lcd_endpoint="https://devnet.lcd.injective.dev", - tm_websocket_endpoint="wss://devnet.tm.injective.dev/websocket", - grpc_endpoint="devnet.injective.dev:9900", - grpc_exchange_endpoint="devnet.injective.dev:9910", - grpc_explorer_endpoint="devnet.injective.dev:9911", - chain_id="injective-777", - fee_denom="inj", - env="devnet" - ) - - @classmethod - def testnet(cls, node="lb"): - nodes = [ - "lb", - "sentry", - ] - if node not in nodes: - raise ValueError("Must be one of {}".format(nodes)) - - if node == "lb": - lcd_endpoint = "https://k8s.testnet.lcd.injective.network" - tm_websocket_endpoint = "wss://k8s.testnet.tm.injective.network/websocket" - grpc_endpoint = "k8s.testnet.chain.grpc.injective.network:443" - grpc_exchange_endpoint = "k8s.testnet.exchange.grpc.injective.network:443" - grpc_explorer_endpoint = "k8s.testnet.explorer.grpc.injective.network:443" - else: - lcd_endpoint = "https://testnet.lcd.injective.network" - tm_websocket_endpoint = "wss://testnet.tm.injective.network/websocket" - grpc_endpoint = "testnet.chain.grpc.injective.network" - grpc_exchange_endpoint = "testnet.exchange.grpc.injective.network" - grpc_explorer_endpoint = "testnet.explorer.grpc.injective.network" - - return cls( - lcd_endpoint=lcd_endpoint, - tm_websocket_endpoint=tm_websocket_endpoint, - grpc_endpoint=grpc_endpoint, - grpc_exchange_endpoint=grpc_exchange_endpoint, - grpc_explorer_endpoint=grpc_explorer_endpoint, - chain_id="injective-888", - fee_denom="inj", - env="testnet" - ) - - @classmethod - def mainnet(cls, node="lb"): - nodes = [ - "lb", # us, asia, prod - "sentry0", # ca, prod - "sentry1", # ca, prod - "sentry3", # us, prod - ] - if node not in nodes: - raise ValueError("Must be one of {}".format(nodes)) - - if node == "lb": - lcd_endpoint = "https://k8s.global.mainnet.lcd.injective.network:443" - tm_websocket_endpoint = "wss://k8s.global.mainnet.tm.injective.network:443/websocket" - grpc_endpoint = "k8s.global.mainnet.chain.grpc.injective.network:443" - grpc_exchange_endpoint = "k8s.global.mainnet.exchange.grpc.injective.network:443" - grpc_explorer_endpoint = "k8s.global.mainnet.explorer.grpc.injective.network:443" - else: - lcd_endpoint = f"http://{node}.injective.network:10337" - tm_websocket_endpoint = f"ws://{node}.injective.network:26657/websocket" - grpc_endpoint = f"{node}.injective.network:9900" - grpc_exchange_endpoint = f"{node}.injective.network:9910" - grpc_explorer_endpoint = f"{node}.injective.network:9911" - - return cls( - lcd_endpoint=lcd_endpoint, - tm_websocket_endpoint=tm_websocket_endpoint, - grpc_endpoint=grpc_endpoint, - grpc_exchange_endpoint=grpc_exchange_endpoint, - grpc_explorer_endpoint=grpc_explorer_endpoint, - chain_id="injective-1", - fee_denom="inj", - env="mainnet" - ) - - @classmethod - def local(cls): - return cls( - lcd_endpoint="http://localhost:10337", - tm_websocket_endpoint="ws://localhost:26657/websocket", - grpc_endpoint="localhost:9900", - grpc_exchange_endpoint="localhost:9910", - grpc_explorer_endpoint="localhost:9911", - chain_id="injective-1", - fee_denom="inj", - env="local" - ) - - @classmethod - def custom(cls, lcd_endpoint, tm_websocket_endpoint, grpc_endpoint, grpc_exchange_endpoint, grpc_explorer_endpoint, chain_id, env): - return cls( - lcd_endpoint=lcd_endpoint, - tm_websocket_endpoint=tm_websocket_endpoint, - grpc_endpoint=grpc_endpoint, - grpc_exchange_endpoint=grpc_exchange_endpoint, - grpc_explorer_endpoint=grpc_explorer_endpoint, - chain_id=chain_id, - fee_denom="inj", - env=env - ) - - def string(self): - return self.env diff --git a/pyinjective/core/broadcaster.py b/pyinjective/core/broadcaster.py index cc9dc2bb..68a5baf1 100644 --- a/pyinjective/core/broadcaster.py +++ b/pyinjective/core/broadcaster.py @@ -8,7 +8,7 @@ from pyinjective import PrivateKey, Transaction, PublicKey from pyinjective.async_client import AsyncClient from pyinjective.composer import Composer -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.core.gas_limit_estimator import GasLimitEstimator diff --git a/pyinjective/core/network.py b/pyinjective/core/network.py new file mode 100644 index 00000000..ac731e36 --- /dev/null +++ b/pyinjective/core/network.py @@ -0,0 +1,354 @@ +import asyncio +import datetime +import time +from abc import ABC, abstractmethod +from http.cookies import SimpleCookie +from typing import Tuple, Optional, Coroutine + + +class Network: + def __init__( + self, + lcd_endpoint: str , + tm_websocket_endpoint: str, + grpc_endpoint: str , + grpc_exchange_endpoint: str , + grpc_explorer_endpoint: str , + chain_id: str , + fee_denom: str , + env: str + ): + self.lcd_endpoint = lcd_endpoint + self.tm_websocket_endpoint = tm_websocket_endpoint + self.grpc_endpoint = grpc_endpoint + self.grpc_exchange_endpoint = grpc_exchange_endpoint + self.grpc_explorer_endpoint = grpc_explorer_endpoint + self.chain_id = chain_id + self.fee_denom = fee_denom + self.env = env + + @classmethod + def devnet(cls): + return cls( + lcd_endpoint="https://devnet.lcd.injective.dev", + tm_websocket_endpoint="wss://devnet.tm.injective.dev/websocket", + grpc_endpoint="devnet.injective.dev:9900", + grpc_exchange_endpoint="devnet.injective.dev:9910", + grpc_explorer_endpoint="devnet.injective.dev:9911", + chain_id="injective-777", + fee_denom="inj", + env="devnet" + ) + + @classmethod + def testnet(cls, node="lb"): + nodes = [ + "lb", + "sentry", + ] + if node not in nodes: + raise ValueError("Must be one of {}".format(nodes)) + + if node == "lb": + lcd_endpoint = "https://k8s.testnet.lcd.injective.network" + tm_websocket_endpoint = "wss://k8s.testnet.tm.injective.network/websocket" + grpc_endpoint = "k8s.testnet.chain.grpc.injective.network:443" + grpc_exchange_endpoint = "k8s.testnet.exchange.grpc.injective.network:443" + grpc_explorer_endpoint = "k8s.testnet.explorer.grpc.injective.network:443" + else: + lcd_endpoint = "https://testnet.lcd.injective.network" + tm_websocket_endpoint = "wss://testnet.tm.injective.network/websocket" + grpc_endpoint = "testnet.chain.grpc.injective.network" + grpc_exchange_endpoint = "testnet.exchange.grpc.injective.network" + grpc_explorer_endpoint = "testnet.explorer.grpc.injective.network" + + return cls( + lcd_endpoint=lcd_endpoint, + tm_websocket_endpoint=tm_websocket_endpoint, + grpc_endpoint=grpc_endpoint, + grpc_exchange_endpoint=grpc_exchange_endpoint, + grpc_explorer_endpoint=grpc_explorer_endpoint, + chain_id="injective-888", + fee_denom="inj", + env="testnet" + ) + + @classmethod + def mainnet(cls, node="lb"): + nodes = [ + "lb", # us, asia, prod + "lb_bare_metal", + "sentry0", # ca, prod + "sentry1", # ca, prod + "sentry3", # us, prod + ] + if node not in nodes: + raise ValueError("Must be one of {}".format(nodes)) + + if node == "lb": + lcd_endpoint = "https://k8s.global.mainnet.lcd.injective.network:443" + tm_websocket_endpoint = "wss://k8s.global.mainnet.tm.injective.network:443/websocket" + grpc_endpoint = "k8s.global.mainnet.chain.grpc.injective.network:443" + grpc_exchange_endpoint = "k8s.global.mainnet.exchange.grpc.injective.network:443" + grpc_explorer_endpoint = "k8s.global.mainnet.explorer.grpc.injective.network:443" + elif node == "lb_bare_metal": + lcd_endpoint = "https://sentry.lcd.injective.network:443" + tm_websocket_endpoint = "wss://sentry.tm.injective.network:443/websocket" + grpc_endpoint = "sentry.chain.grpc.injective.network:443" + grpc_exchange_endpoint = "sentry.exchange.grpc.injective.network:443" + grpc_explorer_endpoint = "sentry.explorer.grpc.injective.network:443" + else: + lcd_endpoint = f"http://{node}.injective.network:10337" + tm_websocket_endpoint = f"ws://{node}.injective.network:26657/websocket" + grpc_endpoint = f"{node}.injective.network:9900" + grpc_exchange_endpoint = f"{node}.injective.network:9910" + grpc_explorer_endpoint = f"{node}.injective.network:9911" + + return cls( + lcd_endpoint=lcd_endpoint, + tm_websocket_endpoint=tm_websocket_endpoint, + grpc_endpoint=grpc_endpoint, + grpc_exchange_endpoint=grpc_exchange_endpoint, + grpc_explorer_endpoint=grpc_explorer_endpoint, + chain_id="injective-1", + fee_denom="inj", + env="mainnet" + ) + + @classmethod + def local(cls): + return cls( + lcd_endpoint="http://localhost:10337", + tm_websocket_endpoint="ws://localhost:26657/websocket", + grpc_endpoint="localhost:9900", + grpc_exchange_endpoint="localhost:9910", + grpc_explorer_endpoint="localhost:9911", + chain_id="injective-1", + fee_denom="inj", + env="local" + ) + + @classmethod + def custom(cls, lcd_endpoint, tm_websocket_endpoint, grpc_endpoint, grpc_exchange_endpoint, grpc_explorer_endpoint, chain_id, env): + return cls( + lcd_endpoint=lcd_endpoint, + tm_websocket_endpoint=tm_websocket_endpoint, + grpc_endpoint=grpc_endpoint, + grpc_exchange_endpoint=grpc_exchange_endpoint, + grpc_explorer_endpoint=grpc_explorer_endpoint, + chain_id=chain_id, + fee_denom="inj", + env=env + ) + + def string(self): + return self.env + + +class CookieAssistant(ABC): + SESSION_RENEWAL_OFFSET = 120 + + @abstractmethod + async def chain_cookie(self, metadata_query: Coroutine) -> str: + ... + + @abstractmethod + async def exchange_cookie(self, metadata_query: Coroutine) -> str: + ... + + async def chain_metadata(self, metadata_query: Coroutine) -> Tuple[Tuple[str, str]]: + cookie = await self.chain_cookie(metadata_query=metadata_query) + return (("cookie", cookie),) + + async def exchange_metadata(self, metadata_query: Coroutine) -> Tuple[Tuple[str, str]]: + cookie = await self.exchange_cookie(metadata_query=metadata_query) + return (("cookie", cookie),) + + +class MainnetKubernetesCookieAssistant(CookieAssistant): + + def __init__(self): + self._chain_cookie: Optional[str] = None + self._exchange_cookie: Optional[str] = None + self._chain_cookie_initialization_lock = asyncio.Lock() + self._exchange_cookie_initialization_lock = asyncio.Lock() + + async def chain_cookie(self, metadata_query: Coroutine) -> str: + if self._chain_cookie == None: + async with self._chain_cookie_initialization_lock: + if self._chain_cookie == None: + await self._fetch_chain_cookie(metadata_query=metadata_query) + cookie = self._chain_cookie + self._check_chain_cookie_expiration() + + return cookie + + async def exchange_cookie(self, metadata_query: Coroutine) -> str: + if self._exchange_cookie == None: + async with self._exchange_cookie_initialization_lock: + if self._exchange_cookie == None: + await self._fetch_exchange_cookie(metadata_query=metadata_query) + cookie = self._exchange_cookie + self._check_exchange_cookie_expiration() + + return cookie + + async def _fetch_chain_cookie(self, metadata_query: Coroutine): + metadata = await metadata_query + cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) + + if cookie_info is None: + raise RuntimeError(f"Error fetching chain cookie ({metadata})") + + self._chain_cookie = cookie_info + + async def _fetch_exchange_cookie(self, metadata_query: Coroutine): + metadata = await metadata_query + cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) + + if cookie_info is None: + raise RuntimeError(f"Error fetching exchange cookie ({metadata})") + + self._exchange_cookie = cookie_info + + def _check_chain_cookie_expiration(self): + if self._is_cookie_expired(cookie_data=self._chain_cookie): + self._chain_cookie = None + + def _check_exchange_cookie_expiration(self): + if self._is_cookie_expired(cookie_data=self._exchange_cookie): + self._exchange_cookie = None + + def _is_cookie_expired(self, cookie_data: str) -> bool: + cookie = SimpleCookie() + cookie.load(cookie_data) + + expiration_time = datetime.datetime.strptime(cookie["GCLB"]["expires"], + "%a, %d-%b-%Y %H:%M:%S %Z").timestamp() + + timestamp_diff = expiration_time - time.time() + return timestamp_diff < self.SESSION_RENEWAL_OFFSET + + +class MainnetBareMetalCookieAssistant(CookieAssistant): + + def __init__(self): + self._chain_cookie: Optional[str] = None + self._exchange_cookie: Optional[str] = None + self._chain_cookie_initialization_lock = asyncio.Lock() + self._exchange_cookie_initialization_lock = asyncio.Lock() + + async def chain_cookie(self, metadata_query: Coroutine) -> str: + if self._chain_cookie == None: + async with self._chain_cookie_initialization_lock: + if self._chain_cookie == None: + await self._fetch_chain_cookie(metadata_query=metadata_query) + cookie = self._chain_cookie + self._check_chain_cookie_expiration() + + return cookie + + async def exchange_cookie(self, metadata_query: Coroutine) -> str: + if self._exchange_cookie == None: + async with self._exchange_cookie_initialization_lock: + if self._exchange_cookie == None: + await self._fetch_exchange_cookie(metadata_query=metadata_query) + cookie = self._exchange_cookie + self._check_exchange_cookie_expiration() + + return cookie + + async def _fetch_chain_cookie(self, metadata_query: Coroutine): + metadata = await metadata_query + cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) + + if cookie_info is None: + raise RuntimeError(f"Error fetching chain cookie ({metadata})") + + self._chain_cookie = cookie_info + + async def _fetch_exchange_cookie(self, metadata_query: Coroutine): + metadata = await metadata_query + cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) + + if cookie_info is None: + raise RuntimeError(f"Error fetching exchange cookie ({metadata})") + + self._exchange_cookie = cookie_info + + def _check_chain_cookie_expiration(self): + if self._is_cookie_expired(cookie_data=self._chain_cookie): + self._chain_cookie = None + + def _check_exchange_cookie_expiration(self): + if self._is_cookie_expired(cookie_data=self._exchange_cookie): + self._exchange_cookie = None + + def _is_cookie_expired(self, cookie_data: str) -> bool: + # The cookies for these nodes do not expire + return False + + +class TestnetCookieAssistant(CookieAssistant): + + def __init__(self): + self._chain_cookie: Optional[str] = None + self._exchange_cookie: Optional[str] = None + self._chain_cookie_initialization_lock = asyncio.Lock() + self._exchange_cookie_initialization_lock = asyncio.Lock() + + async def chain_cookie(self, metadata_query: Coroutine) -> str: + if self._chain_cookie == None: + async with self._chain_cookie_initialization_lock: + if self._chain_cookie == None: + await self._fetch_chain_cookie(metadata_query=metadata_query) + cookie = self._chain_cookie + self._check_chain_cookie_expiration() + + return cookie + + async def exchange_cookie(self, metadata_query: Coroutine) -> str: + if self._exchange_cookie == None: + async with self._exchange_cookie_initialization_lock: + if self._exchange_cookie == None: + await self._fetch_exchange_cookie(metadata_query=metadata_query) + cookie = self._exchange_cookie + self._check_exchange_cookie_expiration() + + return cookie + + async def _fetch_chain_cookie(self, metadata_query: Coroutine): + metadata = await metadata_query + cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) + + if cookie_info is None: + raise RuntimeError(f"Error fetching chain cookie ({metadata})") + + self._chain_cookie = cookie_info + + async def _fetch_exchange_cookie(self, metadata_query: Coroutine): + metadata = await metadata_query + cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) + + if cookie_info is None: + raise RuntimeError(f"Error fetching exchange cookie ({metadata})") + + self._exchange_cookie = cookie_info + + def _check_chain_cookie_expiration(self): + if self._is_cookie_expired(cookie_data=self._chain_cookie): + self._chain_cookie = None + + def _check_exchange_cookie_expiration(self): + if self._is_cookie_expired(cookie_data=self._exchange_cookie): + self._exchange_cookie = None + + def _is_cookie_expired(self, cookie_data: str) -> bool: + cookie = SimpleCookie() + cookie.load(cookie_data) + + expiration_time = datetime.datetime.strptime(cookie["grpc-cookie"]["expires"], + "%a, %d-%b-%y %H:%M:%S %Z").timestamp() + + timestamp_diff = expiration_time - time.time() + return timestamp_diff < self.SESSION_RENEWAL_OFFSET diff --git a/pyinjective/utils/fetch_metadata.py b/pyinjective/utils/fetch_metadata.py index a1a00c51..ef81cef0 100644 --- a/pyinjective/utils/fetch_metadata.py +++ b/pyinjective/utils/fetch_metadata.py @@ -1,15 +1,7 @@ import asyncio -import logging -import grpc -import pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2 as spot_exchange_rpc_pb -import pyinjective.proto.exchange.injective_spot_exchange_rpc_pb2_grpc as spot_exchange_rpc_grpc -import pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2 as derivative_exchange_rpc_pb -import pyinjective.proto.exchange.injective_derivative_exchange_rpc_pb2_grpc as derivative_exchange_rpc_grpc - -from decimal import * from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network metadata_template = """[{}] description = '{} {} {}' diff --git a/tests/core/test_message_based_transaction_fee_calculator.py b/tests/core/test_message_based_transaction_fee_calculator.py index 602b71af..7525fe00 100644 --- a/tests/core/test_message_based_transaction_fee_calculator.py +++ b/tests/core/test_message_based_transaction_fee_calculator.py @@ -6,7 +6,7 @@ from pyinjective import Transaction from pyinjective.async_client import AsyncClient from pyinjective.composer import Composer -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.core.broadcaster import MessageBasedTransactionFeeCalculator from pyinjective.proto.cosmos.gov.v1beta1 import tx_pb2 as gov_tx_pb2 from pyinjective.proto.cosmwasm.wasm.v1 import tx_pb2 as wasm_tx_pb2 diff --git a/tests/test_orderhash.py b/tests/test_orderhash.py index 2aff84a0..c5331e26 100644 --- a/tests/test_orderhash.py +++ b/tests/test_orderhash.py @@ -1,6 +1,6 @@ from pyinjective import PrivateKey from pyinjective.composer import Composer -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.orderhash import OrderHashManager From e3b4dffac22f59bb752ab069435ce029f080b679 Mon Sep 17 00:00:00 2001 From: abel Date: Wed, 23 Aug 2023 17:49:35 -0300 Subject: [PATCH 32/40] (feat) Applied the new cookies assistant in the AsyncClient --- examples/chain_client/1_MsgSend.py | 3 +- pyinjective/async_client.py | 197 ++++--------- pyinjective/core/network.py | 380 ++++++++++++++----------- tests/core/test_gas_limit_estimator.py | 30 +- tests/test_async_client.py | 39 +-- tests/test_composer.py | 4 +- 6 files changed, 298 insertions(+), 355 deletions(-) diff --git a/examples/chain_client/1_MsgSend.py b/examples/chain_client/1_MsgSend.py index 72556625..ad24b941 100644 --- a/examples/chain_client/1_MsgSend.py +++ b/examples/chain_client/1_MsgSend.py @@ -11,8 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - # set custom cookie location (optional) - defaults to current dir - client = AsyncClient(network, insecure=False, chain_cookie_location="/tmp/.chain_cookie") + client = AsyncClient(network, insecure=False) composer = await client.composer() await client.sync_timeout_height() diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 1eb0e0c4..5f31e2e0 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -4,10 +4,8 @@ import grpc import aiocron -import datetime from decimal import Decimal -from http.cookies import SimpleCookie -from typing import Dict, List, Optional, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union, Coroutine from pyinjective.composer import Composer @@ -26,17 +24,10 @@ from .proto.cosmos.auth.v1beta1 import ( query_pb2_grpc as auth_query_grpc, query_pb2 as auth_query, - auth_pb2 as auth_type, ) from .proto.cosmos.authz.v1beta1 import ( query_pb2_grpc as authz_query_grpc, query_pb2 as authz_query, - authz_pb2 as authz_type, -) -from .proto.cosmos.authz.v1beta1 import ( - query_pb2_grpc as authz_query_grpc, - query_pb2 as authz_query, - authz_pb2 as authz_type, ) from .proto.cosmos.bank.v1beta1 import ( query_pb2_grpc as bank_query_grpc, @@ -85,31 +76,14 @@ def __init__( self, network: Network, insecure: bool = False, - load_balancer: bool = True, credentials=grpc.ssl_channel_credentials(), - chain_cookie_location=".chain_cookie", ): - # use append mode to create file if not exist - self.chain_cookie_location = chain_cookie_location - cookie_file = open(chain_cookie_location, "a+") - cookie_file.close() - self.addr = "" self.number = 0 self.sequence = 0 - self.cookie_type = None - self.expiration_format = None - self.load_balancer = load_balancer self.network = network - self.cookie_type = "GCLB" - self.expiration_format = "{}" - - if self.network.string() == "testnet": - self.load_balancer = False - self.cookie_type = "grpc-cookie" - self.expiration_format = "20{}" # chain stubs self.chain_channel = ( @@ -126,14 +100,6 @@ def __init__( self.stubBank = bank_query_grpc.QueryStub(self.chain_channel) self.stubTx = tx_service_grpc.ServiceStub(self.chain_channel) - # attempt to load from disk - cookie_file = open(chain_cookie_location, "r+") - self.chain_cookie = cookie_file.read() - cookie_file.close() - LoggerProvider().logger_for_class(logging_class=self.__class__).info( - f"chain session cookie loaded from disk: {self.chain_cookie}" - ) - self.exchange_cookie = "" self.timeout_height = 1 @@ -249,91 +215,6 @@ async def sync_timeout_height(self): ) self.timeout_height = 0 - # cookie helper methods - async def fetch_cookie(self, type): - metadata = None - if type == "chain": - req = tendermint_query.GetLatestBlockRequest() - metadata = await self.stubCosmosTendermint.GetLatestBlock( - req - ).initial_metadata() - time.sleep(DEFAULT_BLOCK_TIME) - if type == "exchange": - req = exchange_meta_rpc_pb.VersionRequest() - metadata = await self.stubMeta.Version(req).initial_metadata() - return metadata - - async def renew_cookie(self, existing_cookie, type): - metadata = None - # format cookie date into RFC1123 standard - cookie = SimpleCookie() - cookie.load(existing_cookie) - - expires_at = cookie.get(f"{self.cookie_type}").get("expires") - expires_at = expires_at.replace("-", " ") - yyyy = f"{self.expiration_format}".format(expires_at[12:14]) - expires_at = expires_at[:12] + yyyy + expires_at[14:] - - # parse expire field to unix timestamp - expire_timestamp = datetime.datetime.strptime( - expires_at, "%a, %d %b %Y %H:%M:%S GMT" - ).timestamp() - - # renew session if timestamp diff < offset - timestamp_diff = expire_timestamp - int(time.time()) - if timestamp_diff < DEFAULT_SESSION_RENEWAL_OFFSET: - metadata = await self.fetch_cookie(type) - else: - metadata = (("cookie", existing_cookie),) - return metadata - - async def load_cookie(self, type): - metadata = None - if self.insecure: - return metadata - - if type == "chain": - if self.chain_cookie != "": - metadata = await self.renew_cookie(self.chain_cookie, type) - self.set_cookie(metadata, type) - else: - metadata = await self.fetch_cookie(type) - self.set_cookie(metadata, type) - - if type == "exchange": - if self.exchange_cookie != "": - metadata = await self.renew_cookie(self.exchange_cookie, type) - self.set_cookie(metadata, type) - else: - metadata = await self.fetch_cookie(type) - self.set_cookie(metadata, type) - - return metadata - - def set_cookie(self, metadata, type): - new_cookie = None - if self.insecure: - return new_cookie - - for k, v in metadata: - if k == "set-cookie": - new_cookie = v - - if new_cookie == None: - return - - if type == "chain": - # write to client instance - self.chain_cookie = new_cookie - # write to disk - cookie_file = open(self.chain_cookie_location, "w") - cookie_file.write(new_cookie) - cookie_file.close() - LoggerProvider().logger_for_class(logging_class=self.__class__).info("chain session cookie saved to disk") - - if type == "exchange": - self.exchange_cookie = new_cookie - # default client methods async def get_latest_block(self) -> tendermint_query.GetLatestBlockResponse: req = tendermint_query.GetLatestBlockRequest() @@ -341,7 +222,8 @@ async def get_latest_block(self) -> tendermint_query.GetLatestBlockResponse: async def get_account(self, address: str) -> Optional[account_pb2.EthAccount]: try: - metadata = await self.load_cookie(type="chain") + metadata = await self.network.chain_metadata( + metadata_query_provider=self._chain_cookie_metadata_requestor) account_any = (await self.stubAuth.Account( auth_query.QueryAccountRequest(address=address), metadata=metadata )).account @@ -379,7 +261,8 @@ async def simulate_tx( ) -> Tuple[Union[abci_type.SimulationResponse, grpc.RpcError], bool]: try: req = tx_service.SimulateRequest(tx_bytes=tx_byte) - metadata = await self.load_cookie(type="chain") + metadata = await self.network.chain_metadata( + metadata_query_provider=self._chain_cookie_metadata_requestor) return await self.stubTx.Simulate(request=req, metadata=metadata), True except grpc.RpcError as err: return err, False @@ -388,7 +271,7 @@ async def send_tx_sync_mode(self, tx_byte: bytes) -> abci_type.TxResponse: req = tx_service.BroadcastTxRequest( tx_bytes=tx_byte, mode=tx_service.BroadcastMode.BROADCAST_MODE_SYNC ) - metadata = await self.load_cookie(type="chain") + metadata = await self.network.chain_metadata(metadata_query_provider=self._chain_cookie_metadata_requestor) result = await self.stubTx.BroadcastTx(request=req, metadata=metadata) return result.tx_response @@ -396,7 +279,7 @@ async def send_tx_async_mode(self, tx_byte: bytes) -> abci_type.TxResponse: req = tx_service.BroadcastTxRequest( tx_bytes=tx_byte, mode=tx_service.BroadcastMode.BROADCAST_MODE_ASYNC ) - metadata = await self.load_cookie(type="chain") + metadata = await self.network.chain_metadata(metadata_query_provider=self._chain_cookie_metadata_requestor) result = await self.stubTx.BroadcastTx(request=req, metadata=metadata) return result.tx_response @@ -404,7 +287,7 @@ async def send_tx_block_mode(self, tx_byte: bytes) -> abci_type.TxResponse: req = tx_service.BroadcastTxRequest( tx_bytes=tx_byte, mode=tx_service.BroadcastMode.BROADCAST_MODE_BLOCK ) - metadata = await self.load_cookie(type="chain") + metadata = await self.network.chain_metadata(metadata_query_provider=self._chain_cookie_metadata_requestor) result = await self.stubTx.BroadcastTx(request=req, metadata=metadata) return result.tx_response @@ -672,7 +555,9 @@ async def stream_spot_markets(self, **kwargs): req = spot_exchange_rpc_pb.StreamMarketsRequest( market_ids=kwargs.get("market_ids") ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubSpotExchange.StreamMarkets(request=req, metadata=metadata) async def get_spot_orderbookV2(self, market_id: str): @@ -729,12 +614,16 @@ async def get_spot_trades(self, **kwargs): async def stream_spot_orderbook_snapshot(self, market_ids: List[str]): req = spot_exchange_rpc_pb.StreamOrderbookV2Request(market_ids=market_ids) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubSpotExchange.StreamOrderbookV2(request=req, metadata=metadata) async def stream_spot_orderbook_update(self, market_ids: List[str]): req = spot_exchange_rpc_pb.StreamOrderbookUpdateRequest(market_ids=market_ids) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubSpotExchange.StreamOrderbookUpdate(request=req, metadata=metadata) async def stream_spot_orders(self, market_id: str, **kwargs): @@ -743,7 +632,9 @@ async def stream_spot_orders(self, market_id: str, **kwargs): order_side=kwargs.get("order_side"), subaccount_id=kwargs.get("subaccount_id"), ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubSpotExchange.StreamOrders(request=req, metadata=metadata) async def stream_historical_spot_orders(self, market_id: str, **kwargs): @@ -755,7 +646,9 @@ async def stream_historical_spot_orders(self, market_id: str, **kwargs): state=kwargs.get("state"), execution_types=kwargs.get("execution_types") ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubSpotExchange.StreamOrdersHistory(request=req, metadata=metadata) async def stream_historical_derivative_orders(self, market_id: str, **kwargs): @@ -767,7 +660,9 @@ async def stream_historical_derivative_orders(self, market_id: str, **kwargs): state=kwargs.get("state"), execution_types=kwargs.get("execution_types") ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubDerivativeExchange.StreamOrdersHistory(request=req, metadata=metadata) async def stream_spot_trades(self, **kwargs): @@ -780,7 +675,9 @@ async def stream_spot_trades(self, **kwargs): subaccount_ids=kwargs.get("subaccount_ids"), execution_types=kwargs.get("execution_types"), ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubSpotExchange.StreamTrades(request=req, metadata=metadata) async def get_spot_subaccount_orders(self, subaccount_id: str, **kwargs): @@ -820,7 +717,9 @@ async def stream_derivative_markets(self, **kwargs): req = derivative_exchange_rpc_pb.StreamMarketRequest( market_ids=kwargs.get("market_ids") ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubDerivativeExchange.StreamMarket(request=req, metadata=metadata) async def get_derivative_orderbook(self, market_id: str): @@ -886,12 +785,16 @@ async def get_derivative_trades(self, **kwargs): async def stream_derivative_orderbook_snapshot(self, market_ids: List[str]): req = derivative_exchange_rpc_pb.StreamOrderbookV2Request(market_ids=market_ids) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubDerivativeExchange.StreamOrderbookV2(request=req, metadata=metadata) async def stream_derivative_orderbook_update(self, market_ids: List[str]): req = derivative_exchange_rpc_pb.StreamOrderbookUpdateRequest(market_ids=market_ids) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubDerivativeExchange.StreamOrderbookUpdate(request=req, metadata=metadata) async def stream_derivative_orders(self, market_id: str, **kwargs): @@ -900,7 +803,9 @@ async def stream_derivative_orders(self, market_id: str, **kwargs): order_side=kwargs.get("order_side"), subaccount_id=kwargs.get("subaccount_id"), ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubDerivativeExchange.StreamOrders(request=req, metadata=metadata) async def stream_derivative_trades(self, **kwargs): @@ -915,7 +820,9 @@ async def stream_derivative_trades(self, **kwargs): limit=kwargs.get("limit"), execution_types=kwargs.get("execution_types"), ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubDerivativeExchange.StreamTrades(request=req, metadata=metadata) async def get_derivative_positions(self, **kwargs): @@ -937,7 +844,9 @@ async def stream_derivative_positions(self, **kwargs): subaccount_id=kwargs.get("subaccount_id"), subaccount_ids=kwargs.get("subaccount_ids"), ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubDerivativeExchange.StreamPositions(request=req, metadata=metadata) async def get_derivative_liquidable_positions(self, **kwargs): @@ -1013,7 +922,9 @@ async def stream_account_portfolio(self, account_address: str, **kwargs): subaccount_id=kwargs.get("subaccount_id"), type=kwargs.get("type") ) - metadata = await self.load_cookie(type="exchange") + metadata = await self.network.exchange_metadata( + metadata_query_provider=self._exchange_cookie_metadata_requestor + ) return self.stubPortfolio.StreamAccountPortfolio(request=req, metadata=metadata) async def composer(self): @@ -1152,3 +1063,11 @@ def _token_representation(self, symbol: str, token_meta, denom: str, all_tokens: existing_token = token return existing_token + + def _chain_cookie_metadata_requestor(self) -> Coroutine: + request = tendermint_query.GetLatestBlockRequest() + return self.stubCosmosTendermint.GetLatestBlock(request).initial_metadata() + + def _exchange_cookie_metadata_requestor(self) -> Coroutine: + request = exchange_meta_rpc_pb.VersionRequest() + return self.stubMeta.Version(request).initial_metadata() diff --git a/pyinjective/core/network.py b/pyinjective/core/network.py index ac731e36..50db599f 100644 --- a/pyinjective/core/network.py +++ b/pyinjective/core/network.py @@ -3,165 +3,26 @@ import time from abc import ABC, abstractmethod from http.cookies import SimpleCookie -from typing import Tuple, Optional, Coroutine - - -class Network: - def __init__( - self, - lcd_endpoint: str , - tm_websocket_endpoint: str, - grpc_endpoint: str , - grpc_exchange_endpoint: str , - grpc_explorer_endpoint: str , - chain_id: str , - fee_denom: str , - env: str - ): - self.lcd_endpoint = lcd_endpoint - self.tm_websocket_endpoint = tm_websocket_endpoint - self.grpc_endpoint = grpc_endpoint - self.grpc_exchange_endpoint = grpc_exchange_endpoint - self.grpc_explorer_endpoint = grpc_explorer_endpoint - self.chain_id = chain_id - self.fee_denom = fee_denom - self.env = env - - @classmethod - def devnet(cls): - return cls( - lcd_endpoint="https://devnet.lcd.injective.dev", - tm_websocket_endpoint="wss://devnet.tm.injective.dev/websocket", - grpc_endpoint="devnet.injective.dev:9900", - grpc_exchange_endpoint="devnet.injective.dev:9910", - grpc_explorer_endpoint="devnet.injective.dev:9911", - chain_id="injective-777", - fee_denom="inj", - env="devnet" - ) - - @classmethod - def testnet(cls, node="lb"): - nodes = [ - "lb", - "sentry", - ] - if node not in nodes: - raise ValueError("Must be one of {}".format(nodes)) - - if node == "lb": - lcd_endpoint = "https://k8s.testnet.lcd.injective.network" - tm_websocket_endpoint = "wss://k8s.testnet.tm.injective.network/websocket" - grpc_endpoint = "k8s.testnet.chain.grpc.injective.network:443" - grpc_exchange_endpoint = "k8s.testnet.exchange.grpc.injective.network:443" - grpc_explorer_endpoint = "k8s.testnet.explorer.grpc.injective.network:443" - else: - lcd_endpoint = "https://testnet.lcd.injective.network" - tm_websocket_endpoint = "wss://testnet.tm.injective.network/websocket" - grpc_endpoint = "testnet.chain.grpc.injective.network" - grpc_exchange_endpoint = "testnet.exchange.grpc.injective.network" - grpc_explorer_endpoint = "testnet.explorer.grpc.injective.network" - - return cls( - lcd_endpoint=lcd_endpoint, - tm_websocket_endpoint=tm_websocket_endpoint, - grpc_endpoint=grpc_endpoint, - grpc_exchange_endpoint=grpc_exchange_endpoint, - grpc_explorer_endpoint=grpc_explorer_endpoint, - chain_id="injective-888", - fee_denom="inj", - env="testnet" - ) - - @classmethod - def mainnet(cls, node="lb"): - nodes = [ - "lb", # us, asia, prod - "lb_bare_metal", - "sentry0", # ca, prod - "sentry1", # ca, prod - "sentry3", # us, prod - ] - if node not in nodes: - raise ValueError("Must be one of {}".format(nodes)) - - if node == "lb": - lcd_endpoint = "https://k8s.global.mainnet.lcd.injective.network:443" - tm_websocket_endpoint = "wss://k8s.global.mainnet.tm.injective.network:443/websocket" - grpc_endpoint = "k8s.global.mainnet.chain.grpc.injective.network:443" - grpc_exchange_endpoint = "k8s.global.mainnet.exchange.grpc.injective.network:443" - grpc_explorer_endpoint = "k8s.global.mainnet.explorer.grpc.injective.network:443" - elif node == "lb_bare_metal": - lcd_endpoint = "https://sentry.lcd.injective.network:443" - tm_websocket_endpoint = "wss://sentry.tm.injective.network:443/websocket" - grpc_endpoint = "sentry.chain.grpc.injective.network:443" - grpc_exchange_endpoint = "sentry.exchange.grpc.injective.network:443" - grpc_explorer_endpoint = "sentry.explorer.grpc.injective.network:443" - else: - lcd_endpoint = f"http://{node}.injective.network:10337" - tm_websocket_endpoint = f"ws://{node}.injective.network:26657/websocket" - grpc_endpoint = f"{node}.injective.network:9900" - grpc_exchange_endpoint = f"{node}.injective.network:9910" - grpc_explorer_endpoint = f"{node}.injective.network:9911" - - return cls( - lcd_endpoint=lcd_endpoint, - tm_websocket_endpoint=tm_websocket_endpoint, - grpc_endpoint=grpc_endpoint, - grpc_exchange_endpoint=grpc_exchange_endpoint, - grpc_explorer_endpoint=grpc_explorer_endpoint, - chain_id="injective-1", - fee_denom="inj", - env="mainnet" - ) - - @classmethod - def local(cls): - return cls( - lcd_endpoint="http://localhost:10337", - tm_websocket_endpoint="ws://localhost:26657/websocket", - grpc_endpoint="localhost:9900", - grpc_exchange_endpoint="localhost:9910", - grpc_explorer_endpoint="localhost:9911", - chain_id="injective-1", - fee_denom="inj", - env="local" - ) - - @classmethod - def custom(cls, lcd_endpoint, tm_websocket_endpoint, grpc_endpoint, grpc_exchange_endpoint, grpc_explorer_endpoint, chain_id, env): - return cls( - lcd_endpoint=lcd_endpoint, - tm_websocket_endpoint=tm_websocket_endpoint, - grpc_endpoint=grpc_endpoint, - grpc_exchange_endpoint=grpc_exchange_endpoint, - grpc_explorer_endpoint=grpc_explorer_endpoint, - chain_id=chain_id, - fee_denom="inj", - env=env - ) - - def string(self): - return self.env +from typing import Callable, Optional, Tuple class CookieAssistant(ABC): SESSION_RENEWAL_OFFSET = 120 @abstractmethod - async def chain_cookie(self, metadata_query: Coroutine) -> str: + async def chain_cookie(self, metadata_query_provider: Callable) -> str: ... @abstractmethod - async def exchange_cookie(self, metadata_query: Coroutine) -> str: + async def exchange_cookie(self, metadata_query_provider: Callable) -> str: ... - async def chain_metadata(self, metadata_query: Coroutine) -> Tuple[Tuple[str, str]]: - cookie = await self.chain_cookie(metadata_query=metadata_query) + async def chain_metadata(self, metadata_query_provider: Callable) -> Tuple[Tuple[str, str]]: + cookie = await self.chain_cookie(metadata_query_provider=metadata_query_provider) return (("cookie", cookie),) - async def exchange_metadata(self, metadata_query: Coroutine) -> Tuple[Tuple[str, str]]: - cookie = await self.exchange_cookie(metadata_query=metadata_query) + async def exchange_metadata(self, metadata_query_provider: Callable) -> Tuple[Tuple[str, str]]: + cookie = await self.exchange_cookie(metadata_query_provider=metadata_query_provider) return (("cookie", cookie),) @@ -173,28 +34,28 @@ def __init__(self): self._chain_cookie_initialization_lock = asyncio.Lock() self._exchange_cookie_initialization_lock = asyncio.Lock() - async def chain_cookie(self, metadata_query: Coroutine) -> str: + async def chain_cookie(self, metadata_query_provider: Callable) -> str: if self._chain_cookie == None: async with self._chain_cookie_initialization_lock: if self._chain_cookie == None: - await self._fetch_chain_cookie(metadata_query=metadata_query) + await self._fetch_chain_cookie(metadata_query_provider=metadata_query_provider) cookie = self._chain_cookie self._check_chain_cookie_expiration() return cookie - async def exchange_cookie(self, metadata_query: Coroutine) -> str: + async def exchange_cookie(self, metadata_query_provider: Callable) -> str: if self._exchange_cookie == None: async with self._exchange_cookie_initialization_lock: if self._exchange_cookie == None: - await self._fetch_exchange_cookie(metadata_query=metadata_query) + await self._fetch_exchange_cookie(metadata_query_provider=metadata_query_provider) cookie = self._exchange_cookie self._check_exchange_cookie_expiration() return cookie - async def _fetch_chain_cookie(self, metadata_query: Coroutine): - metadata = await metadata_query + async def _fetch_chain_cookie(self, metadata_query_provider: Callable): + metadata = await metadata_query_provider() cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) if cookie_info is None: @@ -202,8 +63,8 @@ async def _fetch_chain_cookie(self, metadata_query: Coroutine): self._chain_cookie = cookie_info - async def _fetch_exchange_cookie(self, metadata_query: Coroutine): - metadata = await metadata_query + async def _fetch_exchange_cookie(self, metadata_query_provider: Callable): + metadata = await metadata_query_provider() cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) if cookie_info is None: @@ -238,28 +99,28 @@ def __init__(self): self._chain_cookie_initialization_lock = asyncio.Lock() self._exchange_cookie_initialization_lock = asyncio.Lock() - async def chain_cookie(self, metadata_query: Coroutine) -> str: + async def chain_cookie(self, metadata_query_provider: Callable) -> str: if self._chain_cookie == None: async with self._chain_cookie_initialization_lock: if self._chain_cookie == None: - await self._fetch_chain_cookie(metadata_query=metadata_query) + await self._fetch_chain_cookie(metadata_query_provider=metadata_query_provider) cookie = self._chain_cookie self._check_chain_cookie_expiration() return cookie - async def exchange_cookie(self, metadata_query: Coroutine) -> str: + async def exchange_cookie(self, metadata_query_provider: Callable) -> str: if self._exchange_cookie == None: async with self._exchange_cookie_initialization_lock: if self._exchange_cookie == None: - await self._fetch_exchange_cookie(metadata_query=metadata_query) + await self._fetch_exchange_cookie(metadata_query_provider=metadata_query_provider) cookie = self._exchange_cookie self._check_exchange_cookie_expiration() return cookie - async def _fetch_chain_cookie(self, metadata_query: Coroutine): - metadata = await metadata_query + async def _fetch_chain_cookie(self, metadata_query_provider: Callable): + metadata = await metadata_query_provider() cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) if cookie_info is None: @@ -267,8 +128,8 @@ async def _fetch_chain_cookie(self, metadata_query: Coroutine): self._chain_cookie = cookie_info - async def _fetch_exchange_cookie(self, metadata_query: Coroutine): - metadata = await metadata_query + async def _fetch_exchange_cookie(self, metadata_query_provider: Callable): + metadata = await metadata_query_provider() cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) if cookie_info is None: @@ -297,28 +158,28 @@ def __init__(self): self._chain_cookie_initialization_lock = asyncio.Lock() self._exchange_cookie_initialization_lock = asyncio.Lock() - async def chain_cookie(self, metadata_query: Coroutine) -> str: + async def chain_cookie(self, metadata_query_provider: Callable) -> str: if self._chain_cookie == None: async with self._chain_cookie_initialization_lock: if self._chain_cookie == None: - await self._fetch_chain_cookie(metadata_query=metadata_query) + await self._fetch_chain_cookie(metadata_query_provider=metadata_query_provider) cookie = self._chain_cookie self._check_chain_cookie_expiration() return cookie - async def exchange_cookie(self, metadata_query: Coroutine) -> str: + async def exchange_cookie(self, metadata_query_provider: Callable) -> str: if self._exchange_cookie == None: async with self._exchange_cookie_initialization_lock: if self._exchange_cookie == None: - await self._fetch_exchange_cookie(metadata_query=metadata_query) + await self._fetch_exchange_cookie(metadata_query_provider=metadata_query_provider) cookie = self._exchange_cookie self._check_exchange_cookie_expiration() return cookie - async def _fetch_chain_cookie(self, metadata_query: Coroutine): - metadata = await metadata_query + async def _fetch_chain_cookie(self, metadata_query_provider: Callable): + metadata = await metadata_query_provider() cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) if cookie_info is None: @@ -326,8 +187,8 @@ async def _fetch_chain_cookie(self, metadata_query: Coroutine): self._chain_cookie = cookie_info - async def _fetch_exchange_cookie(self, metadata_query: Coroutine): - metadata = await metadata_query + async def _fetch_exchange_cookie(self, metadata_query_provider: Callable): + metadata = await metadata_query_provider() cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) if cookie_info is None: @@ -352,3 +213,182 @@ def _is_cookie_expired(self, cookie_data: str) -> bool: timestamp_diff = expiration_time - time.time() return timestamp_diff < self.SESSION_RENEWAL_OFFSET + + +class DisabledCookieAssistant(CookieAssistant): + async def chain_cookie(self, metadata_query_provider: Callable) -> str: + pass + + async def exchange_cookie(self, metadata_query_provider: Callable) -> str: + pass + + async def chain_metadata(self, metadata_query_provider: Callable) -> Tuple[Tuple[str, str]]: + return None + + async def exchange_metadata(self, metadata_query_provider: Callable) -> Tuple[Tuple[str, str]]: + return None + + +class Network: + def __init__( + self, + lcd_endpoint: str, + tm_websocket_endpoint: str, + grpc_endpoint: str, + grpc_exchange_endpoint: str, + grpc_explorer_endpoint: str, + chain_id: str, + fee_denom: str, + env: str, + cookie_assistant: CookieAssistant, + ): + self.lcd_endpoint = lcd_endpoint + self.tm_websocket_endpoint = tm_websocket_endpoint + self.grpc_endpoint = grpc_endpoint + self.grpc_exchange_endpoint = grpc_exchange_endpoint + self.grpc_explorer_endpoint = grpc_explorer_endpoint + self.chain_id = chain_id + self.fee_denom = fee_denom + self.env = env + self.cookie_assistant = cookie_assistant + + @classmethod + def devnet(cls): + return cls( + lcd_endpoint="https://devnet.lcd.injective.dev", + tm_websocket_endpoint="wss://devnet.tm.injective.dev/websocket", + grpc_endpoint="devnet.injective.dev:9900", + grpc_exchange_endpoint="devnet.injective.dev:9910", + grpc_explorer_endpoint="devnet.injective.dev:9911", + chain_id="injective-777", + fee_denom="inj", + env="devnet", + cookie_assistant=DisabledCookieAssistant(), + ) + + @classmethod + def testnet(cls, node="lb"): + nodes = [ + "lb", + "sentry", + ] + if node not in nodes: + raise ValueError("Must be one of {}".format(nodes)) + + if node == "lb": + lcd_endpoint = "https://k8s.testnet.lcd.injective.network" + tm_websocket_endpoint = "wss://k8s.testnet.tm.injective.network/websocket" + grpc_endpoint = "k8s.testnet.chain.grpc.injective.network:443" + grpc_exchange_endpoint = "k8s.testnet.exchange.grpc.injective.network:443" + grpc_explorer_endpoint = "k8s.testnet.explorer.grpc.injective.network:443" + else: + lcd_endpoint = "https://testnet.lcd.injective.network" + tm_websocket_endpoint = "wss://testnet.tm.injective.network/websocket" + grpc_endpoint = "testnet.chain.grpc.injective.network" + grpc_exchange_endpoint = "testnet.exchange.grpc.injective.network" + grpc_explorer_endpoint = "testnet.explorer.grpc.injective.network" + + return cls( + lcd_endpoint=lcd_endpoint, + tm_websocket_endpoint=tm_websocket_endpoint, + grpc_endpoint=grpc_endpoint, + grpc_exchange_endpoint=grpc_exchange_endpoint, + grpc_explorer_endpoint=grpc_explorer_endpoint, + chain_id="injective-888", + fee_denom="inj", + env="testnet", + cookie_assistant=TestnetCookieAssistant() + ) + + @classmethod + def mainnet(cls, node="lb"): + nodes = [ + "lb", # us, asia, prod + "lb_bare_metal", + "sentry0", # ca, prod + "sentry1", # ca, prod + "sentry3", # us, prod + ] + if node not in nodes: + raise ValueError("Must be one of {}".format(nodes)) + + if node == "lb": + lcd_endpoint = "https://k8s.global.mainnet.lcd.injective.network:443" + tm_websocket_endpoint = "wss://k8s.global.mainnet.tm.injective.network:443/websocket" + grpc_endpoint = "k8s.global.mainnet.chain.grpc.injective.network:443" + grpc_exchange_endpoint = "k8s.global.mainnet.exchange.grpc.injective.network:443" + grpc_explorer_endpoint = "k8s.global.mainnet.explorer.grpc.injective.network:443" + cookie_assistant = MainnetKubernetesCookieAssistant() + elif node == "lb_bare_metal": + lcd_endpoint = "https://sentry.lcd.injective.network:443" + tm_websocket_endpoint = "wss://sentry.tm.injective.network:443/websocket" + grpc_endpoint = "sentry.chain.grpc.injective.network:443" + grpc_exchange_endpoint = "sentry.exchange.grpc.injective.network:443" + grpc_explorer_endpoint = "sentry.explorer.grpc.injective.network:443" + cookie_assistant = MainnetBareMetalCookieAssistant() + else: + lcd_endpoint = f"http://{node}.injective.network:10337" + tm_websocket_endpoint = f"ws://{node}.injective.network:26657/websocket" + grpc_endpoint = f"{node}.injective.network:9900" + grpc_exchange_endpoint = f"{node}.injective.network:9910" + grpc_explorer_endpoint = f"{node}.injective.network:9911" + cookie_assistant = DisabledCookieAssistant() + + return cls( + lcd_endpoint=lcd_endpoint, + tm_websocket_endpoint=tm_websocket_endpoint, + grpc_endpoint=grpc_endpoint, + grpc_exchange_endpoint=grpc_exchange_endpoint, + grpc_explorer_endpoint=grpc_explorer_endpoint, + chain_id="injective-1", + fee_denom="inj", + env="mainnet", + cookie_assistant=cookie_assistant, + ) + + @classmethod + def local(cls): + return cls( + lcd_endpoint="http://localhost:10337", + tm_websocket_endpoint="ws://localhost:26657/websocket", + grpc_endpoint="localhost:9900", + grpc_exchange_endpoint="localhost:9910", + grpc_explorer_endpoint="localhost:9911", + chain_id="injective-1", + fee_denom="inj", + env="local", + cookie_assistant=DisabledCookieAssistant(), + ) + + @classmethod + def custom( + cls, + lcd_endpoint, + tm_websocket_endpoint, + grpc_endpoint, + grpc_exchange_endpoint, + grpc_explorer_endpoint, + chain_id, + env, + cookie_assistant: CookieAssistant, + ): + return cls( + lcd_endpoint=lcd_endpoint, + tm_websocket_endpoint=tm_websocket_endpoint, + grpc_endpoint=grpc_endpoint, + grpc_exchange_endpoint=grpc_exchange_endpoint, + grpc_explorer_endpoint=grpc_explorer_endpoint, + chain_id=chain_id, + fee_denom="inj", + env=env, + cookie_assistant=cookie_assistant + ) + + def string(self): + return self.env + + async def chain_metadata(self, metadata_query_provider: Callable) -> Tuple[Tuple[str, str]]: + return await self.cookie_assistant.chain_metadata(metadata_query_provider=metadata_query_provider) + + async def exchange_metadata(self, metadata_query_provider: Callable) -> Tuple[Tuple[str, str]]: + return await self.cookie_assistant.exchange_metadata(metadata_query_provider=metadata_query_provider) diff --git a/tests/core/test_gas_limit_estimator.py b/tests/core/test_gas_limit_estimator.py index 070ebb26..9ccbc98b 100644 --- a/tests/core/test_gas_limit_estimator.py +++ b/tests/core/test_gas_limit_estimator.py @@ -1,9 +1,13 @@ +from decimal import Decimal + from pyinjective.composer import Composer from pyinjective.core.gas_limit_estimator import GasLimitEstimator +from pyinjective.core.market import BinaryOptionMarket from pyinjective.proto.cosmos.gov.v1beta1 import tx_pb2 as gov_tx_pb from pyinjective.proto.cosmwasm.wasm.v1 import tx_pb2 as wasm_tx_pb from pyinjective.proto.injective.exchange.v1beta1 import tx_pb2 as injective_exchange_tx_pb +from tests.model_fixtures.markets_fixtures import usdt_token class TestGasLimitEstimator: @@ -155,7 +159,7 @@ def test_estimation_for_batch_cancel_derivative_orders(self): assert((expected_order_gas_limit * 3) + expected_message_gas_limit == estimator.gas_limit()) def test_estimation_for_batch_update_orders_to_create_spot_orders(self): - market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ composer.SpotOrder( @@ -230,9 +234,27 @@ def test_estimation_for_batch_update_orders_to_create_derivative_orders(self): assert((expected_order_gas_limit * 2) + expected_message_gas_limit == estimator.gas_limit()) - def test_estimation_for_batch_update_orders_to_create_binary_orders(self): - market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + def test_estimation_for_batch_update_orders_to_create_binary_orders(self, usdt_token): + market_id = "0x230dcce315364ff6360097838701b14713e2f4007d704df20ed3d81d09eec957" composer = Composer(network="testnet") + market = BinaryOptionMarket( + id=market_id, + status="active", + ticker="5fdbe0b1-1707800399-WAS", + oracle_symbol="Frontrunner", + oracle_provider="Frontrunner", + oracle_type="provider", + oracle_scale_factor=6, + expiration_timestamp=1707800399, + settlement_timestamp=1707843599, + quote_token=usdt_token, + maker_fee_rate=Decimal("0"), + taker_fee_rate=Decimal("0"), + service_provider_fee=Decimal("0.4"), + min_price_tick_size=Decimal("10000"), + min_quantity_tick_size=Decimal("1"), + ) + composer.binary_option_markets[market.id] = market orders = [ composer.BinaryOptionsOrder( market_id=market_id, @@ -434,7 +456,7 @@ def test_estimation_for_batch_update_orders_to_cancel_all_for_binary_options_mar assert(expected_gas_limit + expected_message_gas_limit == estimator.gas_limit()) def test_estimation_for_exec_message(self): - market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ composer.SpotOrder( diff --git a/tests/test_async_client.py b/tests/test_async_client.py index 56644e9c..8cbab554 100644 --- a/tests/test_async_client.py +++ b/tests/test_async_client.py @@ -1,7 +1,7 @@ import logging import pytest -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.async_client import AsyncClient from pyinjective.proto.exchange import ( @@ -35,24 +35,6 @@ def derivative_servicer(): class TestAsyncClient: - def test_instance_creation_logs_session_cookie_load_info(self, caplog): - caplog.set_level(logging.INFO) - - AsyncClient( - network=Network.local(), - insecure=False, - ) - - expected_log_message_prefix = "chain session cookie loaded from disk: " - found_log = next( - (record for record in caplog.record_tuples if record[2].startswith(expected_log_message_prefix)), - None, - ) - assert(found_log is not None) - assert(found_log[0] == "pyinjective.async_client.AsyncClient") - assert(found_log[1] == logging.INFO) - - @pytest.mark.asyncio async def test_sync_timeout_height_logs_exception(self, caplog): client = AsyncClient( @@ -72,25 +54,6 @@ async def test_sync_timeout_height_logs_exception(self, caplog): assert (found_log[0] == "pyinjective.async_client.AsyncClient") assert (found_log[1] == logging.DEBUG) - def test_set_cookie_logs_chain_session_cookie_saved(self, caplog): - caplog.set_level(logging.INFO) - - client = AsyncClient( - network=Network.local(), - insecure=False, - ) - - client.set_cookie(metadata=[("set-cookie", "test-value")], type="chain") - - expected_log_message_prefix = "chain session cookie saved to disk" - found_log = next( - (record for record in caplog.record_tuples if record[2].startswith(expected_log_message_prefix)), - None, - ) - assert (found_log is not None) - assert (found_log[0] == "pyinjective.async_client.AsyncClient") - assert (found_log[1] == logging.INFO) - @pytest.mark.asyncio async def test_get_account_logs_exception(self, caplog): client = AsyncClient( diff --git a/tests/test_composer.py b/tests/test_composer.py index 9c5426e5..449854ad 100644 --- a/tests/test_composer.py +++ b/tests/test_composer.py @@ -1,9 +1,9 @@ -import logging import pytest from decimal import Decimal from pyinjective.composer import Composer -from pyinjective.constant import Denom, Network +from pyinjective.core.network import Network +from pyinjective.constant import Denom from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket from pyinjective.proto.injective.exchange.v1beta1 import exchange_pb2 from tests.model_fixtures.markets_fixtures import ( From b983b000f5ecea618d670db4811f1333d527ea60 Mon Sep 17 00:00:00 2001 From: Jackson-DKMG <65887967+Jackson-DKMG@users.noreply.github.com> Date: Tue, 29 Aug 2023 18:03:55 +0200 Subject: [PATCH 33/40] add WithdrawValidatorCommission to composer.py --- pyinjective/composer.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pyinjective/composer.py b/pyinjective/composer.py index eeb10521..f613e0c8 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -881,6 +881,14 @@ def MsgWithdrawDelegatorReward( delegator_address=delegator_address, validator_address=validator_address ) + def MsgWithdrawValidatorCommission( + self, validator_address: str + ): + + return cosmos_distribution_tx_pb.MsgWithdrawValidatorCommission( + validator_address=validator_address + ) + def MsgVote( self, proposal_id: str, From e6461c6f101e930a21ba2c49a8c136f563d38bbb Mon Sep 17 00:00:00 2001 From: Jackson-DKMG <65887967+Jackson-DKMG@users.noreply.github.com> Date: Tue, 29 Aug 2023 18:04:50 +0200 Subject: [PATCH 34/40] Create 48_WithdrawValidatorCommission_Rewards --- .../48_WithdrawValidatorCommission_Rewards | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 examples/chain_client/48_WithdrawValidatorCommission_Rewards diff --git a/examples/chain_client/48_WithdrawValidatorCommission_Rewards b/examples/chain_client/48_WithdrawValidatorCommission_Rewards new file mode 100644 index 00000000..7d360790 --- /dev/null +++ b/examples/chain_client/48_WithdrawValidatorCommission_Rewards @@ -0,0 +1,79 @@ + +import asyncio +import logging + +from pyinjective.composer import Composer as ProtoMsgComposer +from pyinjective.async_client import AsyncClient +from pyinjective.transaction import Transaction +from pyinjective.constant import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + """For a validator to withdraw his rewards & commissions simultaneously""" + # select network: local, testnet, mainnet + network = Network.testnet() + composer = ProtoMsgComposer(network=network.string()) + + # initialize grpc client + client = AsyncClient(network, insecure=False) + await client.sync_timeout_height() + + # load account + # private key is that from the validator's wallet + priv_key = PrivateKey.from_hex("f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3") + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + account = await client.get_account(address.to_acc_bech32()) + + # prepare tx msg + validator_address = "injvaloper1ultw9r29l8nxy5u6thcgusjn95vsy2caw722q5" + + msg0 = composer.MsgWithdrawDelegatorReward( + delegator_address=address.to_acc_bech32(), + validator_address=validator_address + ) + + msg1 = composer.MsgWithdrawValidatorCommission( + validator_address=validator_address + ) + + # build sim tx + tx = ( + Transaction() + .with_messages(msg0, msg1) + .with_sequence(client.get_sequence()) + .with_account_num(client.get_number()) + .with_chain_id(network.chain_id) + ) + sim_sign_doc = tx.get_sign_doc(pub_key) + sim_sig = priv_key.sign(sim_sign_doc.SerializeToString()) + sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key) + + # simulate tx + (sim_res, success) = await client.simulate_tx(sim_tx_raw_bytes) + if not success: + print(sim_res) + return + + # build tx + gas_price = 500000000 + gas_limit = sim_res.gas_info.gas_used + 20000 # add 20k for gas, fee computation + gas_fee = '{:.18f}'.format((gas_price * gas_limit) / pow(10, 18)).rstrip('0') + fee = [composer.Coin( + amount=gas_price * gas_limit, + denom=network.fee_denom, + )] + tx = tx.with_gas(gas_limit).with_fee(fee).with_memo('').with_timeout_height(client.timeout_height) + sign_doc = tx.get_sign_doc(pub_key) + sig = priv_key.sign(sign_doc.SerializeToString()) + tx_raw_bytes = tx.get_tx_data(sig, pub_key) + + # broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode + res = await client.send_tx_sync_mode(tx_raw_bytes) + print(res) + print("gas wanted: {}".format(gas_limit)) + print("gas fee: {} INJ".format(gas_fee)) + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) From 3a63cb1a51d9826ba9908827d47fc363ba0c9753 Mon Sep 17 00:00:00 2001 From: abel Date: Wed, 30 Aug 2023 09:20:40 -0300 Subject: [PATCH 35/40] (fix) Made cookie_assistant parameter optional when creating a custom network instance --- pyinjective/core/network.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyinjective/core/network.py b/pyinjective/core/network.py index 50db599f..e49d48e7 100644 --- a/pyinjective/core/network.py +++ b/pyinjective/core/network.py @@ -370,8 +370,9 @@ def custom( grpc_explorer_endpoint, chain_id, env, - cookie_assistant: CookieAssistant, + cookie_assistant: Optional[CookieAssistant] = None, ): + assistant = cookie_assistant or DisabledCookieAssistant() return cls( lcd_endpoint=lcd_endpoint, tm_websocket_endpoint=tm_websocket_endpoint, @@ -381,7 +382,7 @@ def custom( chain_id=chain_id, fee_denom="inj", env=env, - cookie_assistant=cookie_assistant + cookie_assistant=assistant ) def string(self): From 9918722e37fe3e42ead9c0c47410e745b76d11f6 Mon Sep 17 00:00:00 2001 From: abel Date: Wed, 30 Aug 2023 09:30:06 -0300 Subject: [PATCH 36/40] (fix) Updated README.md Changelogs with the latest changes --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fa59c16e..bf1386f9 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,8 @@ make tests * The Composer can still be instantiated without markets and tokens. When markets and tokens are not provided the Composer loads the required information from the Denoms used in previous versions * Change in AsyncClient to be able to create Composer instances for the client network, markets and tokens * Examples have been adapted to create Composer instances using the AsyncClient +* Added new nodes (bare-metal load balancing nodes) for mainnet +* Refactored the cookies management logic into a cookie assistant. Added the required logic to support the new cookies format for bare-metal load balanced nodes **0.7.1.1** * Fixed Testnet network URLs From 36e16d684427f71ec11df75c3cc66ab9e2dcfb92 Mon Sep 17 00:00:00 2001 From: abel Date: Wed, 30 Aug 2023 16:49:07 -0300 Subject: [PATCH 37/40] (fix) Solved issue in the composer logic to unpack messages from a transaction --- pyinjective/composer.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pyinjective/composer.py b/pyinjective/composer.py index f613e0c8..41140aea 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -1,3 +1,4 @@ +import json from configparser import ConfigParser from decimal import Decimal from time import time @@ -979,14 +980,14 @@ def UnpackTransactionMessages(transaction): meta_messages = json.loads(transaction.messages.decode()) header_map = { - "/injective.exchange.v1beta1.MsgCreateSpotLimitOrder": injective_exchange_tx_pb.MsgCreateSpotLimitOrderResponse, - "/injective.exchange.v1beta1.MsgCreateSpotMarketOrder": injective_exchange_tx_pb.MsgCreateSpotMarketOrderResponse, - "/injective.exchange.v1beta1.MsgCreateDerivativeLimitOrder": injective_exchange_tx_pb.MsgCreateDerivativeLimitOrderResponse, - "/injective.exchange.v1beta1.MsgCreateDerivativeMarketOrder": injective_exchange_tx_pb.MsgCreateDerivativeMarketOrderResponse, - "/injective.exchange.v1beta1.MsgCancelSpotOrder": injective_exchange_tx_pb.MsgCancelSpotOrderResponse, - "/injective.exchange.v1beta1.MsgCancelDerivativeOrder": injective_exchange_tx_pb.MsgCancelDerivativeOrderResponse, - "/injective.exchange.v1beta1.MsgBatchCancelSpotOrders": injective_exchange_tx_pb.MsgBatchCancelSpotOrdersResponse, - "/injective.exchange.v1beta1.MsgBatchCancelDerivativeOrders": injective_exchange_tx_pb.MsgBatchCancelDerivativeOrdersResponse, + "/injective.exchange.v1beta1.MsgCreateSpotLimitOrder": injective_exchange_tx_pb.MsgCreateSpotLimitOrder, + "/injective.exchange.v1beta1.MsgCreateSpotMarketOrder": injective_exchange_tx_pb.MsgCreateSpotMarketOrder, + "/injective.exchange.v1beta1.MsgCreateDerivativeLimitOrder": injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder, + "/injective.exchange.v1beta1.MsgCreateDerivativeMarketOrder": injective_exchange_tx_pb.MsgCreateDerivativeMarketOrder, + "/injective.exchange.v1beta1.MsgCancelSpotOrder": injective_exchange_tx_pb.MsgCancelSpotOrder, + "/injective.exchange.v1beta1.MsgCancelDerivativeOrder": injective_exchange_tx_pb.MsgCancelDerivativeOrder, + "/injective.exchange.v1beta1.MsgBatchCancelSpotOrders": injective_exchange_tx_pb.MsgBatchCancelSpotOrders, + "/injective.exchange.v1beta1.MsgBatchCancelDerivativeOrders": injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders, "/injective.exchange.v1beta1.MsgBatchCreateSpotLimitOrders": injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders, "/injective.exchange.v1beta1.MsgBatchCreateDerivativeLimitOrders": injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders, "/injective.exchange.v1beta1.MsgBatchUpdateOrders": injective_exchange_tx_pb.MsgBatchUpdateOrders, From 0ad254c533222f06fc6c2a860c20775c92797278 Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 1 Sep 2023 16:24:38 -0300 Subject: [PATCH 38/40] (feat) Deprecated testnet k8s nodes and replaced them with the bare-metal testnet nodes --- Pipfile.lock | 1497 +++++++++++++++++------------------ README.md | 4 +- pyinjective/__init__.py | 2 +- pyinjective/async_client.py | 7 +- pyinjective/client.py | 692 ---------------- pyinjective/core/network.py | 24 +- pyinjective/transaction.py | 13 +- 7 files changed, 772 insertions(+), 1467 deletions(-) delete mode 100644 pyinjective/client.py diff --git a/Pipfile.lock b/Pipfile.lock index ee240533..58fc968b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -26,96 +26,97 @@ }, "aiohttp": { "hashes": [ - "sha256:03543dcf98a6619254b409be2d22b51f21ec66272be4ebda7b04e6412e4b2e14", - "sha256:03baa76b730e4e15a45f81dfe29a8d910314143414e528737f8589ec60cf7391", - "sha256:0a63f03189a6fa7c900226e3ef5ba4d3bd047e18f445e69adbd65af433add5a2", - "sha256:10c8cefcff98fd9168cdd86c4da8b84baaa90bf2da2269c6161984e6737bf23e", - "sha256:147ae376f14b55f4f3c2b118b95be50a369b89b38a971e80a17c3fd623f280c9", - "sha256:176a64b24c0935869d5bbc4c96e82f89f643bcdf08ec947701b9dbb3c956b7dd", - "sha256:17b79c2963db82086229012cff93ea55196ed31f6493bb1ccd2c62f1724324e4", - "sha256:1a45865451439eb320784918617ba54b7a377e3501fb70402ab84d38c2cd891b", - "sha256:1b3ea7edd2d24538959c1c1abf97c744d879d4e541d38305f9bd7d9b10c9ec41", - "sha256:22f6eab15b6db242499a16de87939a342f5a950ad0abaf1532038e2ce7d31567", - "sha256:3032dcb1c35bc330134a5b8a5d4f68c1a87252dfc6e1262c65a7e30e62298275", - "sha256:33587f26dcee66efb2fff3c177547bd0449ab7edf1b73a7f5dea1e38609a0c54", - "sha256:34ce9f93a4a68d1272d26030655dd1b58ff727b3ed2a33d80ec433561b03d67a", - "sha256:3a80464982d41b1fbfe3154e440ba4904b71c1a53e9cd584098cd41efdb188ef", - "sha256:3b90467ebc3d9fa5b0f9b6489dfb2c304a1db7b9946fa92aa76a831b9d587e99", - "sha256:3d89efa095ca7d442a6d0cbc755f9e08190ba40069b235c9886a8763b03785da", - "sha256:3d8ef1a630519a26d6760bc695842579cb09e373c5f227a21b67dc3eb16cfea4", - "sha256:3f43255086fe25e36fd5ed8f2ee47477408a73ef00e804cb2b5cba4bf2ac7f5e", - "sha256:40653609b3bf50611356e6b6554e3a331f6879fa7116f3959b20e3528783e699", - "sha256:41a86a69bb63bb2fc3dc9ad5ea9f10f1c9c8e282b471931be0268ddd09430b04", - "sha256:493f5bc2f8307286b7799c6d899d388bbaa7dfa6c4caf4f97ef7521b9cb13719", - "sha256:4a6cadebe132e90cefa77e45f2d2f1a4b2ce5c6b1bfc1656c1ddafcfe4ba8131", - "sha256:4c745b109057e7e5f1848c689ee4fb3a016c8d4d92da52b312f8a509f83aa05e", - "sha256:4d347a172f866cd1d93126d9b239fcbe682acb39b48ee0873c73c933dd23bd0f", - "sha256:4dac314662f4e2aa5009977b652d9b8db7121b46c38f2073bfeed9f4049732cd", - "sha256:4ddaae3f3d32fc2cb4c53fab020b69a05c8ab1f02e0e59665c6f7a0d3a5be54f", - "sha256:5393fb786a9e23e4799fec788e7e735de18052f83682ce2dfcabaf1c00c2c08e", - "sha256:59f029a5f6e2d679296db7bee982bb3d20c088e52a2977e3175faf31d6fb75d1", - "sha256:5a7bdf9e57126dc345b683c3632e8ba317c31d2a41acd5800c10640387d193ed", - "sha256:5b3f2e06a512e94722886c0827bee9807c86a9f698fac6b3aee841fab49bbfb4", - "sha256:5ce45967538fb747370308d3145aa68a074bdecb4f3a300869590f725ced69c1", - "sha256:5e14f25765a578a0a634d5f0cd1e2c3f53964553a00347998dfdf96b8137f777", - "sha256:618c901dd3aad4ace71dfa0f5e82e88b46ef57e3239fc7027773cb6d4ed53531", - "sha256:652b1bff4f15f6287550b4670546a2947f2a4575b6c6dff7760eafb22eacbf0b", - "sha256:6c08e8ed6fa3d477e501ec9db169bfac8140e830aa372d77e4a43084d8dd91ab", - "sha256:6ddb2a2026c3f6a68c3998a6c47ab6795e4127315d2e35a09997da21865757f8", - "sha256:6e601588f2b502c93c30cd5a45bfc665faaf37bbe835b7cfd461753068232074", - "sha256:6e74dd54f7239fcffe07913ff8b964e28b712f09846e20de78676ce2a3dc0bfc", - "sha256:7235604476a76ef249bd64cb8274ed24ccf6995c4a8b51a237005ee7a57e8643", - "sha256:7ab43061a0c81198d88f39aaf90dae9a7744620978f7ef3e3708339b8ed2ef01", - "sha256:7c7837fe8037e96b6dd5cfcf47263c1620a9d332a87ec06a6ca4564e56bd0f36", - "sha256:80575ba9377c5171407a06d0196b2310b679dc752d02a1fcaa2bc20b235dbf24", - "sha256:80a37fe8f7c1e6ce8f2d9c411676e4bc633a8462844e38f46156d07a7d401654", - "sha256:8189c56eb0ddbb95bfadb8f60ea1b22fcfa659396ea36f6adcc521213cd7b44d", - "sha256:854f422ac44af92bfe172d8e73229c270dc09b96535e8a548f99c84f82dde241", - "sha256:880e15bb6dad90549b43f796b391cfffd7af373f4646784795e20d92606b7a51", - "sha256:8b631e26df63e52f7cce0cce6507b7a7f1bc9b0c501fcde69742130b32e8782f", - "sha256:8c29c77cc57e40f84acef9bfb904373a4e89a4e8b74e71aa8075c021ec9078c2", - "sha256:91f6d540163f90bbaef9387e65f18f73ffd7c79f5225ac3d3f61df7b0d01ad15", - "sha256:92c0cea74a2a81c4c76b62ea1cac163ecb20fb3ba3a75c909b9fa71b4ad493cf", - "sha256:9bcb89336efa095ea21b30f9e686763f2be4478f1b0a616969551982c4ee4c3b", - "sha256:a1f4689c9a1462f3df0a1f7e797791cd6b124ddbee2b570d34e7f38ade0e2c71", - "sha256:a3fec6a4cb5551721cdd70473eb009d90935b4063acc5f40905d40ecfea23e05", - "sha256:a5d794d1ae64e7753e405ba58e08fcfa73e3fad93ef9b7e31112ef3c9a0efb52", - "sha256:a86d42d7cba1cec432d47ab13b6637bee393a10f664c425ea7b305d1301ca1a3", - "sha256:adfbc22e87365a6e564c804c58fc44ff7727deea782d175c33602737b7feadb6", - "sha256:aeb29c84bb53a84b1a81c6c09d24cf33bb8432cc5c39979021cc0f98c1292a1a", - "sha256:aede4df4eeb926c8fa70de46c340a1bc2c6079e1c40ccf7b0eae1313ffd33519", - "sha256:b744c33b6f14ca26b7544e8d8aadff6b765a80ad6164fb1a430bbadd593dfb1a", - "sha256:b7a00a9ed8d6e725b55ef98b1b35c88013245f35f68b1b12c5cd4100dddac333", - "sha256:bb96fa6b56bb536c42d6a4a87dfca570ff8e52de2d63cabebfd6fb67049c34b6", - "sha256:bbcf1a76cf6f6dacf2c7f4d2ebd411438c275faa1dc0c68e46eb84eebd05dd7d", - "sha256:bca5f24726e2919de94f047739d0a4fc01372801a3672708260546aa2601bf57", - "sha256:bf2e1a9162c1e441bf805a1fd166e249d574ca04e03b34f97e2928769e91ab5c", - "sha256:c4eb3b82ca349cf6fadcdc7abcc8b3a50ab74a62e9113ab7a8ebc268aad35bb9", - "sha256:c6cc15d58053c76eacac5fa9152d7d84b8d67b3fde92709195cb984cfb3475ea", - "sha256:c6cd05ea06daca6ad6a4ca3ba7fe7dc5b5de063ff4daec6170ec0f9979f6c332", - "sha256:c844fd628851c0bc309f3c801b3a3d58ce430b2ce5b359cd918a5a76d0b20cb5", - "sha256:c9cb1565a7ad52e096a6988e2ee0397f72fe056dadf75d17fa6b5aebaea05622", - "sha256:cab9401de3ea52b4b4c6971db5fb5c999bd4260898af972bf23de1c6b5dd9d71", - "sha256:cd468460eefef601ece4428d3cf4562459157c0f6523db89365202c31b6daebb", - "sha256:d1e6a862b76f34395a985b3cd39a0d949ca80a70b6ebdea37d3ab39ceea6698a", - "sha256:d1f9282c5f2b5e241034a009779e7b2a1aa045f667ff521e7948ea9b56e0c5ff", - "sha256:d265f09a75a79a788237d7f9054f929ced2e69eb0bb79de3798c468d8a90f945", - "sha256:db3fc6120bce9f446d13b1b834ea5b15341ca9ff3f335e4a951a6ead31105480", - "sha256:dbf3a08a06b3f433013c143ebd72c15cac33d2914b8ea4bea7ac2c23578815d6", - "sha256:de04b491d0e5007ee1b63a309956eaed959a49f5bb4e84b26c8f5d49de140fa9", - "sha256:e4b09863aae0dc965c3ef36500d891a3ff495a2ea9ae9171e4519963c12ceefd", - "sha256:e595432ac259af2d4630008bf638873d69346372d38255774c0e286951e8b79f", - "sha256:e75b89ac3bd27d2d043b234aa7b734c38ba1b0e43f07787130a0ecac1e12228a", - "sha256:ea9eb976ffdd79d0e893869cfe179a8f60f152d42cb64622fca418cd9b18dc2a", - "sha256:eafb3e874816ebe2a92f5e155f17260034c8c341dad1df25672fb710627c6949", - "sha256:ee3c36df21b5714d49fc4580247947aa64bcbe2939d1b77b4c8dcb8f6c9faecc", - "sha256:f352b62b45dff37b55ddd7b9c0c8672c4dd2eb9c0f9c11d395075a84e2c40f75", - "sha256:fabb87dd8850ef0f7fe2b366d44b77d7e6fa2ea87861ab3844da99291e81e60f", - "sha256:fe11310ae1e4cd560035598c3f29d86cef39a83d244c7466f95c27ae04850f10", - "sha256:fe7ba4a51f33ab275515f66b0a236bcde4fb5561498fe8f898d4e549b2e4509f" + "sha256:00ad4b6f185ec67f3e6562e8a1d2b69660be43070bd0ef6fcec5211154c7df67", + "sha256:0175d745d9e85c40dcc51c8f88c74bfbaef9e7afeeeb9d03c37977270303064c", + "sha256:01d4c0c874aa4ddfb8098e85d10b5e875a70adc63db91f1ae65a4b04d3344cda", + "sha256:043d2299f6dfdc92f0ac5e995dfc56668e1587cea7f9aa9d8a78a1b6554e5755", + "sha256:0c413c633d0512df4dc7fd2373ec06cc6a815b7b6d6c2f208ada7e9e93a5061d", + "sha256:0d21c684808288a98914e5aaf2a7c6a3179d4df11d249799c32d1808e79503b5", + "sha256:0e584a10f204a617d71d359fe383406305a4b595b333721fa50b867b4a0a1548", + "sha256:1274477e4c71ce8cfe6c1ec2f806d57c015ebf84d83373676036e256bc55d690", + "sha256:13bf85afc99ce6f9ee3567b04501f18f9f8dbbb2ea11ed1a2e079670403a7c84", + "sha256:153c2549f6c004d2754cc60603d4668899c9895b8a89397444a9c4efa282aaf4", + "sha256:1f7372f7341fcc16f57b2caded43e81ddd18df53320b6f9f042acad41f8e049a", + "sha256:23fb25a9f0a1ca1f24c0a371523546366bb642397c94ab45ad3aedf2941cec6a", + "sha256:28c543e54710d6158fc6f439296c7865b29e0b616629767e685a7185fab4a6b9", + "sha256:2a482e6da906d5e6e653be079b29bc173a48e381600161c9932d89dfae5942ef", + "sha256:2ad5c3c4590bb3cc28b4382f031f3783f25ec223557124c68754a2231d989e2b", + "sha256:2ce2ac5708501afc4847221a521f7e4b245abf5178cf5ddae9d5b3856ddb2f3a", + "sha256:2cf57fb50be5f52bda004b8893e63b48530ed9f0d6c96c84620dc92fe3cd9b9d", + "sha256:2e1b1e51b0774408f091d268648e3d57f7260c1682e7d3a63cb00d22d71bb945", + "sha256:2e2e9839e14dd5308ee773c97115f1e0a1cb1d75cbeeee9f33824fa5144c7634", + "sha256:2e460be6978fc24e3df83193dc0cc4de46c9909ed92dd47d349a452ef49325b7", + "sha256:312fcfbacc7880a8da0ae8b6abc6cc7d752e9caa0051a53d217a650b25e9a691", + "sha256:33279701c04351a2914e1100b62b2a7fdb9a25995c4a104259f9a5ead7ed4802", + "sha256:33776e945d89b29251b33a7e7d006ce86447b2cfd66db5e5ded4e5cd0340585c", + "sha256:34dd0c107799dcbbf7d48b53be761a013c0adf5571bf50c4ecad5643fe9cfcd0", + "sha256:3562b06567c06439d8b447037bb655ef69786c590b1de86c7ab81efe1c9c15d8", + "sha256:368a42363c4d70ab52c2c6420a57f190ed3dfaca6a1b19afda8165ee16416a82", + "sha256:4149d34c32f9638f38f544b3977a4c24052042affa895352d3636fa8bffd030a", + "sha256:461908b2578955045efde733719d62f2b649c404189a09a632d245b445c9c975", + "sha256:4a01951fabc4ce26ab791da5f3f24dca6d9a6f24121746eb19756416ff2d881b", + "sha256:4e874cbf8caf8959d2adf572a78bba17cb0e9d7e51bb83d86a3697b686a0ab4d", + "sha256:4f21e83f355643c345177a5d1d8079f9f28b5133bcd154193b799d380331d5d3", + "sha256:5443910d662db951b2e58eb70b0fbe6b6e2ae613477129a5805d0b66c54b6cb7", + "sha256:5798a9aad1879f626589f3df0f8b79b3608a92e9beab10e5fda02c8a2c60db2e", + "sha256:5d20003b635fc6ae3f96d7260281dfaf1894fc3aa24d1888a9b2628e97c241e5", + "sha256:5db3a5b833764280ed7618393832e0853e40f3d3e9aa128ac0ba0f8278d08649", + "sha256:5ed1c46fb119f1b59304b5ec89f834f07124cd23ae5b74288e364477641060ff", + "sha256:62360cb771707cb70a6fd114b9871d20d7dd2163a0feafe43fd115cfe4fe845e", + "sha256:6809a00deaf3810e38c628e9a33271892f815b853605a936e2e9e5129762356c", + "sha256:68c5a82c8779bdfc6367c967a4a1b2aa52cd3595388bf5961a62158ee8a59e22", + "sha256:6e4a280e4b975a2e7745573e3fc9c9ba0d1194a3738ce1cbaa80626cc9b4f4df", + "sha256:6e6783bcc45f397fdebc118d772103d751b54cddf5b60fbcc958382d7dd64f3e", + "sha256:72a860c215e26192379f57cae5ab12b168b75db8271f111019509a1196dfc780", + "sha256:7607ec3ce4993464368505888af5beb446845a014bc676d349efec0e05085905", + "sha256:773dd01706d4db536335fcfae6ea2440a70ceb03dd3e7378f3e815b03c97ab51", + "sha256:78d847e4cde6ecc19125ccbc9bfac4a7ab37c234dd88fbb3c5c524e8e14da543", + "sha256:7dde0009408969a43b04c16cbbe252c4f5ef4574ac226bc8815cd7342d2028b6", + "sha256:80bd372b8d0715c66c974cf57fe363621a02f359f1ec81cba97366948c7fc873", + "sha256:841cd8233cbd2111a0ef0a522ce016357c5e3aff8a8ce92bcfa14cef890d698f", + "sha256:84de26ddf621d7ac4c975dbea4c945860e08cccde492269db4e1538a6a6f3c35", + "sha256:84f8ae3e09a34f35c18fa57f015cc394bd1389bce02503fb30c394d04ee6b938", + "sha256:8af740fc2711ad85f1a5c034a435782fbd5b5f8314c9a3ef071424a8158d7f6b", + "sha256:8b929b9bd7cd7c3939f8bcfffa92fae7480bd1aa425279d51a89327d600c704d", + "sha256:910bec0c49637d213f5d9877105d26e0c4a4de2f8b1b29405ff37e9fc0ad52b8", + "sha256:96943e5dcc37a6529d18766597c491798b7eb7a61d48878611298afc1fca946c", + "sha256:a0215ce6041d501f3155dc219712bc41252d0ab76474615b9700d63d4d9292af", + "sha256:a3cf433f127efa43fee6b90ea4c6edf6c4a17109d1d037d1a52abec84d8f2e42", + "sha256:a6ce61195c6a19c785df04e71a4537e29eaa2c50fe745b732aa937c0c77169f3", + "sha256:a7a75ef35f2df54ad55dbf4b73fe1da96f370e51b10c91f08b19603c64004acc", + "sha256:a94159871304770da4dd371f4291b20cac04e8c94f11bdea1c3478e557fbe0d8", + "sha256:aa1990247f02a54185dc0dff92a6904521172a22664c863a03ff64c42f9b5410", + "sha256:ab88bafedc57dd0aab55fa728ea10c1911f7e4d8b43e1d838a1739f33712921c", + "sha256:ad093e823df03bb3fd37e7dec9d4670c34f9e24aeace76808fc20a507cace825", + "sha256:ae871a964e1987a943d83d6709d20ec6103ca1eaf52f7e0d36ee1b5bebb8b9b9", + "sha256:b0ba0d15164eae3d878260d4c4df859bbdc6466e9e6689c344a13334f988bb53", + "sha256:b5411d82cddd212644cf9360879eb5080f0d5f7d809d03262c50dad02f01421a", + "sha256:b9552ec52cc147dbf1944ac7ac98af7602e51ea2dcd076ed194ca3c0d1c7d0bc", + "sha256:bfb9162dcf01f615462b995a516ba03e769de0789de1cadc0f916265c257e5d8", + "sha256:c0a9034379a37ae42dea7ac1e048352d96286626251862e448933c0f59cbd79c", + "sha256:c1161b345c0a444ebcf46bf0a740ba5dcf50612fd3d0528883fdc0eff578006a", + "sha256:c11f5b099adafb18e65c2c997d57108b5bbeaa9eeee64a84302c0978b1ec948b", + "sha256:c44e65da1de4403d0576473e2344828ef9c4c6244d65cf4b75549bb46d40b8dd", + "sha256:c48c5c0271149cfe467c0ff8eb941279fd6e3f65c9a388c984e0e6cf57538e14", + "sha256:c7a815258e5895d8900aec4454f38dca9aed71085f227537208057853f9d13f2", + "sha256:cae533195e8122584ec87531d6df000ad07737eaa3c81209e85c928854d2195c", + "sha256:cc14be025665dba6202b6a71cfcdb53210cc498e50068bc088076624471f8bb9", + "sha256:cd56db019015b6acfaaf92e1ac40eb8434847d9bf88b4be4efe5bfd260aee692", + "sha256:d827176898a2b0b09694fbd1088c7a31836d1a505c243811c87ae53a3f6273c1", + "sha256:df72ac063b97837a80d80dec8d54c241af059cc9bb42c4de68bd5b61ceb37caa", + "sha256:e5980a746d547a6ba173fd5ee85ce9077e72d118758db05d229044b469d9029a", + "sha256:e5d47ae48db0b2dcf70bc8a3bc72b3de86e2a590fc299fdbbb15af320d2659de", + "sha256:e91d635961bec2d8f19dfeb41a539eb94bd073f075ca6dae6c8dc0ee89ad6f91", + "sha256:ea353162f249c8097ea63c2169dd1aa55de1e8fecbe63412a9bc50816e87b761", + "sha256:eaeed7abfb5d64c539e2db173f63631455f1196c37d9d8d873fc316470dfbacd", + "sha256:eca4bf3734c541dc4f374ad6010a68ff6c6748f00451707f39857f429ca36ced", + "sha256:f83a552443a526ea38d064588613aca983d0ee0038801bc93c0c916428310c28", + "sha256:fb1558def481d84f03b45888473fc5a1f35747b5f334ef4e7a571bc0dfcb11f8", + "sha256:fd1ed388ea7fbed22c4968dd64bab0198de60750a25fe8c0c9d4bef5abe13824" ], "index": "pypi", - "version": "==3.8.4" + "markers": "python_version >= '3.6'", + "version": "==3.8.5" }, "aiosignal": { "hashes": [ @@ -134,11 +135,11 @@ }, "async-timeout": { "hashes": [ - "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15", - "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c" + "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", + "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028" ], - "markers": "python_version >= '3.6'", - "version": "==4.0.2" + "markers": "python_version >= '3.7'", + "version": "==4.0.3" }, "asyncio": { "hashes": [ @@ -172,6 +173,7 @@ "sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981" ], "index": "pypi", + "markers": "python_version >= '3.5'", "version": "==1.2.0" }, "bip32": { @@ -184,118 +186,118 @@ }, "bitarray": { "hashes": [ - "sha256:0052e0cfa15810b0dbb1e347b2e4676caa1a7a65c6f6838f50aca6518e8bc153", - "sha256:0400c5a6d68dcf4546e763b10239f916fc7145d909b7e72f0fcb372bf1d44b81", - "sha256:0655cb36ac48c7253af3de83e7c1132d04cf999c065a3afdf970d8f0fa0ed180", - "sha256:07a604d41e2a9ee88fb6f8dd6744b4c1845a537970321588485e4a55bd09e403", - "sha256:0d60f26cbfbea04d3960e442ff1d2e439dc0accc10412e0551ec743b399c1595", - "sha256:0d78d26ab9ab3b0bf684fcb4b947af71e164d2c6def892914d10d6b512383d52", - "sha256:11367e4e29d79295b83a3bbfaa9a928531b958e9db37f80497b7c6100950d049", - "sha256:128f398b119751c39abba1395764ff43995d5756844005c9d4db0e97867e6474", - "sha256:14dc0e1938955b340dc364591422a28e7c5d9c4cbb42ba215b6855b7edd5b9dc", - "sha256:15046a69aac33940fe14bdfc049a9ade5e8bd680eb662704e2581d2860be5ff7", - "sha256:158d099722ebf7294385f2071734b90e5665bba3ad56418c81b3fe3f9d39f720", - "sha256:1617c6fbe36f91e4aaa1552da57270e102a8733008d53239eac1d9f2cf15b265", - "sha256:1d8d5df5d0872edb1e1c50cd0d7fc04b0f373ad7b678ff1b1b48228d28c91f25", - "sha256:22a48b5682a6eb235d1a2ac82147e17bb4bb045afcb5869f53f42d1ba34e2bab", - "sha256:252bd62619339818a520d6ef0763086986611a2d27d2f3c0681d3d6ff7d78213", - "sha256:25321952806d070bd12fc652416047438a2f1984011f1e23e4f2391f7e3ab3d2", - "sha256:263e6239203e453a1e33b2232978012966a4e1fec47a1a519f715936e605b4e6", - "sha256:26cd0ec1a556fb5062d0bda13d8664f3bf5b0f9023a0254fbd76db366cd12673", - "sha256:2c5ed8ef5366a33a92bccb423529a8215b6dcc1a1ad095fab360eac9be94bcae", - "sha256:2e9e69d24b557fc614360e61d373b8e3114204c590c84b26ff31ac212a398052", - "sha256:37fb5777f155e5f2abc98e6db00c8bf7def8bcf2e36d736db025fa3cd7ad044e", - "sha256:38bda909b392f80b1fc04d2f86511cdec05e4a6151d0a660a50589ee0da394ae", - "sha256:3f4f8fd69642313e1ec288a22eb2ef49b8b0e6a6fb98afab0fb227a35a06543c", - "sha256:4024882e77dcb19c6e874faca47f637b97e02a9fcddc20289eabd427c641e902", - "sha256:41ef308abe02aed03058451ed17dad1365d4b4d32a7e63efa81a0becbc36b5ff", - "sha256:42b740e565858b51e8e64160ed204a8dd874293d9c78d513548da8b640b2d3c9", - "sha256:4819ad0640348da61d88e4820f2fbc66927cf6378c4fd609259a000c170660b7", - "sha256:4b729d2ee6a8b9ed9573ffd7fb3f66c5b340658013a73e334c8f7dc09d8e2bba", - "sha256:4bf7b7da77a275e937c2a42fcb846af581fc3f698683b9629827acda40bf96d1", - "sha256:4cfd9590a81606fb08adb7e08aefe1eae0b38ef65c82263b08cdb8daca1f6763", - "sha256:4d3503017ba68689b118f921b008750c955b8dd12ede9148cf99b97125670067", - "sha256:4d801f31a88f544b46c707dbfc095d427f81d02bffcfc1732a3359702550b87b", - "sha256:52baaf7c23f4416fc6ab4654cc7290ed0048950775125bed40b89bc331ede0d8", - "sha256:555f7fd1ec7b2d1b911929615df272bc831ff7b57e0d56bd6aefba427ed79c58", - "sha256:5677ca0196bf340c41c72038141e4da9ed0ac8159b7644ed4ae507d016f12787", - "sha256:576f1fd95043959cb2c04aa6835cafaa25c7f8c1b191ce99dbdd41137c6356eb", - "sha256:59b02a18100a0c94dd79d62903d29f830517291dc32fa5e36d08aea37277ae1a", - "sha256:5a862f19c387b9c53423bc5bed097c0394cead5b85dd1b55941d029889c681c3", - "sha256:5b7cdb62535b2c0851011856bb4eed233dfd183b06a254c7826a7b4b7cfaa714", - "sha256:5dabc0c23af19e48470740d4ab22cb04871f636ef297d7ae4e6a0b7f746e5500", - "sha256:67a740475995a6a53f58a922210c3d267d14780dae3cbd997a0ffc0640416fe6", - "sha256:6fd7b5c762a922df8b75080e6f976f4ce62d2b7e7648bb277b44ed482e19cf31", - "sha256:7606369109a1451623837a272c04020d47c92ea9af1bc6d074cbcceb9f9481f2", - "sha256:761bfac893c18d90b82bbdcc243e887ff315059c63f13459397e3d955834e4e9", - "sha256:761cc24012b0be2acebc2929eeaee3d9036655478974c847a0b5d5ac24d54d70", - "sha256:78b88c247ef366ad07b6877fd13fc96e363d791b200bed10706c4b5522853371", - "sha256:7e25891c8b3c29d785c18716202eacc237a9b65361e17d22d433639a3b1c0126", - "sha256:7e8ab9fa522c878afe2a049087ea723d932bbb15b0a08239d572945158731636", - "sha256:801639ec1663cde71eec343c81936aa6e2480d1ce1345560df7f63c9d49a6a4f", - "sha256:81f7c02f4a8ac119751d6350da0dba64dd4a5b4f1dd61da882b4adce0c1e3e4d", - "sha256:83ec9ea40f74bdbd4018a6d05f2ab68b20935e9c32fc1bdd3164db0a7214764a", - "sha256:8536467187b027bf40cdb1b20c0d2f0087893e427218f0db3cde0a9bd93548c6", - "sha256:85a3c39d55945f86541bc74fcecf107b0a8098b3b7f14f5126b515c9ec61857e", - "sha256:878f2c840ed693351d3531a127424af5e38e2c059727b8d47c0b8a56dc6800f2", - "sha256:8a0f3f1bb9c485f5120f49f37e18ca000beaad4c5bcb709be9a2f0061dcbdee4", - "sha256:8cf406ac78997bad3fc1b1eb99799934b309014177f0ebe46fc52d5e11e381a3", - "sha256:8de204abcb13bcfbea964e50e08dc1ee8d493b6a2da424fac1a866c24aab8557", - "sha256:9061e217e3b6041cd8eeff029681026e4c8f8c96821803e9358dc3cd2f21ce97", - "sha256:91b9de7c52fba6627c38aefda3acafc049a62aae398d0a7af6303b15dd1ad7bc", - "sha256:9225c310b34ba37627b917d49bb9ab9fb3192afdc15c4a2e466fdc3a1f3f7656", - "sha256:94871d66db2370409830b0f3a147e0bc83ebcdc7a233dfe856b989687ea29ab5", - "sha256:994de983cd6153931b98b28a3a37b14e3297d367975031f3a1610e716026bb98", - "sha256:9b66bc21240b150d14310464fe70d8b64350d3d7d1ba377251e75873d9980f2b", - "sha256:a40f3014e579372713a2f589a22dc2a95c46d04cb5c96111cc1e02b5fec398e8", - "sha256:a53f104555788164c3cc44c6e23ff2700b2aee53165d129577db0d21a697cb0d", - "sha256:a670877159565154d68c261e4a0eed151cae1ca05459d4967bfa7ed8f97785e7", - "sha256:a7fed384fc49b280533ba685aec6e3a2e0f72cd70819688991b01a23d6632f89", - "sha256:a81f6815ea3612aa490dccfb9a22274349fe4c7e83c97c6c97a6a57fb1e779b5", - "sha256:b1bdcb3c0e58087b2f38d27e91faa871a872fc8d5e7ceab4e89dd5029943030f", - "sha256:b363105ae888f305addf543471fa6bfe272a7db34c56f3e777f86c32f66c9f88", - "sha256:b43ea42693715a6a7ca11d8eb8b13c8148306559ce277a29c85afa48e9739b54", - "sha256:b44ad887182dd1b6236bc49b4f422e3360edadc0c31511764c82d5da272498b5", - "sha256:b4bc74c81184a2571b6b35bff9b0d749e8e3934ea682e5ea64b53f2b759fe111", - "sha256:b82dbc0a0b6ed67b4c9fa411c945ba642ff40a91799c0d6ce68ef623d951e468", - "sha256:b9b56d36e57ddf1b17d91597a4666adb947c38b76cba59e315ef58fa7a4d5ca9", - "sha256:bb26c370a4001cfe65115ffb564fc09401a8cf51a2cdc20def7526d253656146", - "sha256:bc3a297b9cef1210b43435d74ad8c5aea07c947676fe32306573ec42d94ff426", - "sha256:bc5a6a68fbb716a07a8cce47a9bae6db360cceb0fb60e304a51715f324f73bc8", - "sha256:becfb1f803fe380d5bcdf985e439cd4ae0ed06e19e52d5130bef2186908e350d", - "sha256:c528f2ee881e135b95306612b023c46556a811afa2ec509eab7b8d0559395bcb", - "sha256:c8bfcc26140486e52bbfb70e95fba8d4bd18f72b2aeb9659ecd2ee44f2514af0", - "sha256:ca9133085bec365957040aa88778dce400cbb9620e31a133233769d9c57567b4", - "sha256:d16fe3da83a6d7afc21313ebb17d63d820e34f736a0cf8c2da689c4c46cbc76e", - "sha256:d335e0cf7fd81ff687cfffe35ea862be582b1164fee6276ff3dec86de7dc7dfe", - "sha256:d356b956ee20a74ebe625be1cbf6536302bc09cc8ee39e29faf1ae671dee4263", - "sha256:d36b6b14ef5fa5108290c16f9af4e486e95b362468154c0ba654523674c3b877", - "sha256:d420b298a76acf7400df1d4296ab37d19157aa3397ececf3b5c288d6a76a2f8c", - "sha256:d5a76f9c263b0ed622d2ca99ad07b65dd0ebbd6d4ef4937cdd2a060ada5c6df4", - "sha256:d9e1ea490cb2760b1369b5033445b7389364c6b457d0d90524eced6c262f6bfc", - "sha256:e01bf467c3291e56ddaefb18599434c925479465d8658e5771bada6261926db9", - "sha256:e4bb54dcf8880722678e4f9fa32e7b7bfe4bd5281fd43441426767fe0afd8244", - "sha256:e73109715d748b6890c807b8a70d68939fedfda665a15ebe72009e1538f3d6fc", - "sha256:e86d7ffff696b11867c3624615461f7e91aa415ab53e3b0a08a595da78c653dc", - "sha256:e92212abfba29b903138b3be5c59d082e9dfe1e7054ed287a15f119d569046a3", - "sha256:ea1ec56b9e90ad186af7396cab8c44db720e77d34e9664c3e448c3d8b9234ea4", - "sha256:ede561bd1b20e7a647ecd00a84c15db4ba31d43bf36738337ec36f5c0ac01d31", - "sha256:f05e813ff8a06e1ef6feb23176e3d11ca4348ccd0e6715ed0e0888cb38886815", - "sha256:f66366166632e36a878e519cb91afba5ea067a65253cda747436236cd1637017", - "sha256:f89b9d0b1e09ca711e8100e78e1883b6fa6eb086f49dc8c8b4d53657188dce6e", - "sha256:fca906f07f9e3e782204366a34ddd55b405de50fd73c1c7b97e9c542076e2964", - "sha256:fe9aab0aca202df3170833c390496ca1f91ff7899076a4f7e9edf2cb04cc4d0c", - "sha256:ff91db785adc05f4f4ad6e9aa57333cb30346d2177c6470f3dbc8860121140bc" - ], - "version": "==2.7.5" + "sha256:00ff372dfaced7dd6cc2dffd052fafc118053cf81a442992b9a23367479d77d7", + "sha256:0cc066c7290151600b8872865708d2d00fb785c5db8a0df20d70d518e02f172b", + "sha256:0de1bc5f971aba46de88a4eb0dbb5779e30bbd7514f4dcbff743c209e0c02667", + "sha256:1414582b3b7516d2282433f0914dd9846389b051b2aea592ae7cc165806c24ac", + "sha256:17c32ba584e8fb9322419390e0e248769ed7d59de3ffa7432562a4c0ec4f1f82", + "sha256:18530ed3ddd71e9ff95440afce531efc3df7a3e0657f1c201c2c3cb41dd65869", + "sha256:1a0d27aad02d8abcb1d3b7d85f463877c4937e71adf9b6adb9367f2cdad91a52", + "sha256:1e859c664500d57526fe07140889a3b58dca54ff3b16ac6dc6d534a65c933084", + "sha256:214c05a7642040f6174e29f3e099549d3c40ac44616405081bf230dcafb38767", + "sha256:28dee92edd0d21655e56e1870c22468d0dabe557df18aa69f6d06b1543614180", + "sha256:29e19cb80a69f6d1a64097bfbe1766c418e1a785d901b583ef0328ea10a30399", + "sha256:2aa2267eb6d2b88ef7d139e79a6daaa84cd54d241b9797478f10dcb95a9cd620", + "sha256:2ab81c74a1805fe74330859b38e70d7525cdd80953461b59c06660046afaffcf", + "sha256:2b0f754a5791635b8239abdcc0258378111b8ee7a8eb3e2bbc24bcc48a0f0b08", + "sha256:2b977c39e3734e73540a2e3a71501c2c6261c70c6ce59d427bb7c4ecf6331c7e", + "sha256:2d38ceca90ed538706e3f111513073590f723f90659a7af0b992b29776a6e816", + "sha256:2d3f28a80f2e6bb96e9360a4baf3fbacb696b5aba06a14c18a15488d4b6f398f", + "sha256:2dc064a63445366f6b26eaf77230d326b9463e903ba59d6ff5efde0c5ec1ea0e", + "sha256:3024ab4c4906c3681408ca17c35833237d18813ebb9f24ae9f9e3157a4a66939", + "sha256:3243e4b8279ff2fe4c6e7869f0e6930c17799ee9f8d07317f68d44a66b46281e", + "sha256:3994f7dc48d21af40c0d69fca57d8040b02953f4c7c3652c2341d8947e9cbedf", + "sha256:3b999fb66980f885961d197d97d7ff5a13b7ab524ccf45ccb4704f4b82ce02e3", + "sha256:3bb5f2954dd897b0bac13b5449e5c977534595b688120c8af054657a08b01f46", + "sha256:443726af4bd60515e4e41ea36c5dbadb29a59bc799bcbf431011d1c6fd4363e3", + "sha256:4677477a406f2a9e064920463f69172b865e4d69117e1f2160064d3f5912b0bd", + "sha256:46fdd27c8fa4186d8b290bf74a28cbd91b94127b1b6a35c265a002e394fa9324", + "sha256:4a637bcd199c1366c65b98f18884f0d0b87403f04676b21e4635831660d722a7", + "sha256:4ce2ef9291a193a0e0cd5e23970bf3b682cc8b95220561d05b775b8d616d665f", + "sha256:542358b178b025dcc95e7fb83389e9954f701c41d312cbb66bdd763cbe5414b5", + "sha256:55020d6fb9b72bd3606969f5431386c592ed3666133bd475af945aa0fa9e84ec", + "sha256:57aeab27120a8a50917845bb81b0976e33d4759f2156b01359e2b43d445f5127", + "sha256:5934e3a623a1d485e1dcfc1990246e3c32c6fc6e7f0fd894750800d35fdb5794", + "sha256:5b0493ab66c6b8e17e9fde74c646b39ee09c236cf28a787cb8cbd3a83c05bff7", + "sha256:5f6175c1cf07dadad3213d60075704cf2e2f1232975cfd4ac8328c24a05e8f78", + "sha256:6033303431a7c85a535b3f1b0ec28abc2ebc2167c263f244993b56ccb87cae6b", + "sha256:62ac31059a3c510ef64ed93d930581b262fd4592e6d95ede79fca91e8d3d3ef6", + "sha256:63fa75e87ad8c57d5722cc87902ca148ef8bbbba12b5c5b3c3730a1bc9ac2886", + "sha256:67e8fb18df51e649adbc81359e1db0f202d72708fba61b06f5ac8db47c08d107", + "sha256:69ab51d551d50e4d6ca35abc95c9d04b33ad28418019bb5481ab09bdbc0df15c", + "sha256:6be965028785413a6163dd55a639b898b22f67f9b6ed554081c23e94a602031e", + "sha256:6c26a923080bc211cab8f5a5e242e3657b32951fec8980db0616e9239aade482", + "sha256:6df04efdba4e1bf9d93a1735e42005f8fcf812caf40c03934d9322412d563499", + "sha256:6ea51ba4204d086d5b76e84c31d2acbb355ed1b075ded54eb9b7070b0b95415d", + "sha256:741c3a2c0997c8f8878edfc65a4a8f7aa72eede337c9bc0b7bd8a45cf6e70dbc", + "sha256:74cd1725d08325b6669e6e9a5d09cec29e7c41f7d58e082286af5387414d046d", + "sha256:75104c3076676708c1ac2484ebf5c26464fb3850312de33a5b5bf61bfa7dbec5", + "sha256:797de3465f5f6c6be9a412b4e99eb6e8cdb86b83b6756655c4d83a65d0b9a376", + "sha256:7b29d4bf3d3da1847f2be9e30105bf51caaf5922e94dc827653e250ed33f4e8a", + "sha256:7c17dd8fb146c2c680bf1cb28b358f9e52a14076e44141c5442148863ee95d7d", + "sha256:81e83ed7e0b1c09c5a33b97712da89e7a21fd3e5598eff3975c39540f5619792", + "sha256:82bfb6ab9b1b5451a5483c9a2ae2a8f83799d7503b384b54f6ab56ea74abb305", + "sha256:8367768ab797105eb97dfbd4577fcde281618de4d8d3b16ad62c477bb065f347", + "sha256:843af12991161b358b6379a8dc5f6636798f3dacdae182d30995b6a2df3b263e", + "sha256:848af80518d0ed2aee782018588c7c88805f51b01271935df5b256c8d81c726e", + "sha256:861850d6a58e7b6a7096d0b0efed9c6d993a6ab8b9d01e781df1f4d80cc00efa", + "sha256:8c361201e1c3ee6d6b2266f8b7a645389880bccab1b29e22e7a6b7b6e7831ad5", + "sha256:904719fb7304d4115228b63c178f0cc725ad3b73e285c4b328e45a99a8e3fad6", + "sha256:9061c0a50216f24c97fb2325de84200e5ad5555f25c854ddcb3ceb6f12136055", + "sha256:9186cf8135ca170cd907d8c4df408a87747570d192d89ec4ff23805611c702a0", + "sha256:9336300fd0acf07ede92e424930176dc4b43ef1b298489e93ba9a1695e8ea752", + "sha256:9aad7b4670f090734b272c072c9db375c63bd503512be9a9393e657dcacfc7e2", + "sha256:9b65d487451e0e287565c8436cf4da45260f958f911299f6122a20d7ec76525c", + "sha256:9d5df3d6358425c9dfb6bdbd4f576563ec4173d24693a9042d05aadcb23c0b98", + "sha256:9d6a9c72354327c7aa9890ff87904cbe86830cb1fb58c39750a0afac8df5e051", + "sha256:9fed8aba8d1b09cf641b50f1e6dd079c31677106ea4b63ec29f4c49adfabd63f", + "sha256:a04d4851e83730f03c4a6aac568c7d8b42f78f0f9cc8231d6db66192b030ce1e", + "sha256:a0f6d705860f59721d7282496a4d29b5fd78690e1c1473503832c983e762b01b", + "sha256:aa08a9b03888c768b9b2383949a942804d50d8164683b39fe62f0bfbfd9b4204", + "sha256:ad440c17ef2ff42e94286186b5bcf82bf87c4026f91822675239102ebe1f7035", + "sha256:ae32ac7217e83646b9f64d7090bf7b737afaa569665621f110a05d9738ca841a", + "sha256:b2015a9dd718393e814ff7b9e80c58190eb1cef7980f86a97a33e8440e158ce2", + "sha256:b2560475c5a1ff96fcab01fae7cf6b9a6da590f02659556b7fccc7991e401884", + "sha256:b65a04b2e029b0694b52d60786732afd15b1ec6517de61a36afbb7808a2ffac1", + "sha256:b67733a240a96f09b7597af97ac4d60c59140cfcfd180f11a7221863b82f023a", + "sha256:b8d6e5ff385fea25caf26fd58b43f087deb763dcaddd18d3df2895235cf1b484", + "sha256:bc03bb358ae3917247d257207c79162e666d407ac473718d1b95316dac94162b", + "sha256:bf80804014e3736515b84044c2be0e70080616b4ceddd4e38d85f3167aeb8165", + "sha256:c2426dc7a0d92d8254def20ab7a231626397ce5b6fb3d4f44be74cc1370a60c3", + "sha256:c54b0af16be45de534af9d77e8a180126cd059f72db8b6550f62dda233868942", + "sha256:c5582dd7d906e6f9ec1704f99d56d812f7d395d28c02262bc8b50834d51250c3", + "sha256:c9efcee311d9ba0c619743060585af9a9b81496e97b945843d5e954c67722a75", + "sha256:cbe54685cf6b17b3e15faf6c4b76773bc1c484bc447020737d2550a9dde5f6e6", + "sha256:cf38871ed4cd89df9db7c70f729b948fa3e2848a07c69f78e4ddfbe4f23db63c", + "sha256:d175e16419a52d54c0ac44c93309ba76dc2cfd33ee9d20624f1a5eb86b8e162e", + "sha256:d2f13b7d0694ce2024c82fc595e6ccc3918e7f069747c3de41b1ce72a9a1e346", + "sha256:d32ccd2c0d906eae103ef84015f0545a395052b0b6eb0e02e9023ca0132557f6", + "sha256:d34790a919f165b6f537935280ef5224957d9ce8ab11d339f5e6d0319a683ccc", + "sha256:dc7acffee09822b334d1b46cd384e969804abdf18f892c82c05c2328066cd2ae", + "sha256:dd76bbf5a4b2ab84b8ffa229f5648e80038ba76bf8d7acc5de9dd06031b38117", + "sha256:df9d8a9a46c46950f306394705512553c552b633f8bf3c11359c4204289f11e3", + "sha256:e48c45ea7944225bcee026c457a70eaea61db3659d9603f07fc8a643ab7e633b", + "sha256:e4cd81ffd2d58ef68c22c825aff89f4a47bd721e2ada0a3a96793169f370ae21", + "sha256:e68ceef35a88625d16169550768fcc8d3894913e363c24ecbf6b8c07eb02c8f3", + "sha256:e7f7231ef349e8f4955d9b39561f4683a418a73443cfce797a4eddbee1ba9664", + "sha256:e88a706f92ad1e0e1e66f6811d10b6155d5f18f0de9356ee899a7966a4e41992", + "sha256:ea71e0a50060f96ad0821e0ac785e91e44807f8b69555970979d81934961d5bd", + "sha256:ee772c20dcb56b03d666a4e4383d0b5b942b0ccc27815e42fe0737b34cba2082", + "sha256:f0af01e1f61fe627f63648c0c6f52de8eac56710a2ef1dbce4851d867084cc7e", + "sha256:f30cdce22af3dc7c73e70af391bfd87c4574cc40c74d651919e20efc26e014b5", + "sha256:f3128234bde3629ab301a501950587e847d30031a9cbf04d95f35cbf44469a9e", + "sha256:f7d2ec2174d503cbb092f8353527842633c530b4e03b9922411640ac9c018a19", + "sha256:f9a66745682e175e143a180524a63e692acb2b8c86941073f6dd4ee906e69608" + ], + "version": "==2.8.1" }, "certifi": { "hashes": [ - "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7", - "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716" + "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", + "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" ], "markers": "python_version >= '3.6'", - "version": "==2023.5.7" + "version": "==2023.7.22" }, "cffi": { "hashes": [ @@ -368,84 +370,84 @@ }, "charset-normalizer": { "hashes": [ - "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6", - "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1", - "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e", - "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373", - "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62", - "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230", - "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be", - "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c", - "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0", - "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448", - "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f", - "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649", - "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d", - "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0", - "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706", - "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a", - "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59", - "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23", - "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5", - "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb", - "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e", - "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e", - "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c", - "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28", - "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d", - "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41", - "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974", - "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce", - "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f", - "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1", - "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d", - "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8", - "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017", - "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31", - "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7", - "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8", - "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e", - "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14", - "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd", - "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d", - "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795", - "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b", - "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b", - "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b", - "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203", - "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f", - "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19", - "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1", - "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a", - "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac", - "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9", - "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0", - "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137", - "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f", - "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6", - "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5", - "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909", - "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f", - "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0", - "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324", - "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755", - "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb", - "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854", - "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c", - "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60", - "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84", - "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0", - "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b", - "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1", - "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531", - "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1", - "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11", - "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326", - "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df", - "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.0" + "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", + "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", + "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", + "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", + "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", + "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", + "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", + "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", + "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", + "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", + "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", + "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", + "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", + "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", + "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", + "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", + "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", + "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", + "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", + "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", + "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", + "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", + "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", + "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", + "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", + "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", + "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", + "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", + "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", + "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", + "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", + "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", + "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", + "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", + "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", + "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", + "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", + "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", + "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", + "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", + "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", + "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", + "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", + "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", + "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", + "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", + "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", + "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", + "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", + "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", + "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", + "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", + "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", + "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", + "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", + "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", + "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", + "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", + "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", + "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", + "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", + "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", + "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", + "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", + "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", + "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", + "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", + "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", + "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", + "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", + "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", + "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", + "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", + "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", + "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.2.0" }, "coincurve": { "hashes": [ @@ -493,6 +495,7 @@ "sha256:fceca9d6ecaa1e8f891675e4f4ff530d54e41c648fc6e8a816835ffa640fa899" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==18.0.0" }, "croniter": { @@ -505,107 +508,102 @@ }, "cytoolz": { "hashes": [ - "sha256:02975e2b1e61e47e9afa311f4c1783d155136fad37c54a1cebfe991c5a0798a1", - "sha256:03ab22c9aeb1535f8647d23b6520b0c3d41aaa18d04ef42b352dde1931f2e2b1", - "sha256:061387aa39b9c1576c25d0c59142513c09e77a2a07bd5d6211a43c7a758b6f45", - "sha256:06d38a40fe153f23cda0e823413fe9d9ebee89dd461827285316eff929fb121e", - "sha256:0d474dacbafbdbb44c7de986bbf71ff56ae62df0d52ab3b6fa966784dc88737a", - "sha256:117871f036926e42d3abcee587eafa9dc7383f1064ac53a806d33e76604de311", - "sha256:14f4dbc3f0ec8f6fc68865489af21dcf042ff007d2737c27bfd73296f15db544", - "sha256:1a1eae39656a1685e8b3f433eecfd72015ce5c1d7519e9c8f9402153c68331bb", - "sha256:1b6761791973b1e839b8309d5853b40eeb413368e31beaf5f2b6ed44c6fc7cf0", - "sha256:1be368623e46ad3c1ce807e7a436acb119c26001507b31f92ceb21b86e08c386", - "sha256:1c29dd04e282ddfd45b457e3551075beec9128aa9271245e58ce924bf6e055f8", - "sha256:23c3f57c48eb939d2986eba4aeaeedf930ebf94d58c91a42d4e0fc45ed5427dc", - "sha256:25ff13c468c06da9ef26651dc389e7e8bb7af548f8c1dfb96305f57f18d398a8", - "sha256:2a48940ff0449ffcf690310bf9228bb57885f7571406ed2fe05c98e299987195", - "sha256:2b245b824f4705aef0e4a03fafef3ad6cb59ef43cc564cdbf683ee28dfc11ad5", - "sha256:2ec296f01c29c809698eaf677211b6255691295c2b35caab2131e1e7eaadfbac", - "sha256:2eed428b5e68c28abf2c71195e799850e040d67a27c05f7785319c611665b86a", - "sha256:2f32452e833f0605b871626e6c61b71b0cba24233aad0e04accc3240497d4995", - "sha256:3032c0ba42dee5836d6b57a72a569b65df2c29e8ed266cb900d569003cf933a9", - "sha256:30936ae8fa68b6a1ac8ad6c4bacb5a8a00d51bc6c89f9614a1557b0105d09f8a", - "sha256:31131b54a0c72efc0eb432dc66df546c6a54f2a7d396c9a34cf65ac1c26b1df8", - "sha256:35fae4eaa0eaf9072a5fe2d244a79e65baae4e5ddbe9cc629c5037af800213a2", - "sha256:37320669c364f7d370392af33cc1034b4563da66c22cd3261e3530f4d30dbe4b", - "sha256:37c53f456a1c84566a7d911eec57c4c6280b915ab0600e7671582793cc2769fe", - "sha256:3c9a16a5b4f54d5c0a131f56b0ca65998a9a74958b5b36840c280edba4f8b907", - "sha256:3cb95d23defb2322cddf70efb4af6dac191d95edaa343e8c1f58f1afa4f92ecd", - "sha256:3d6d0b0075731832343eb88229cea4bf39e96f3fc7acbc449aadbdfec2842703", - "sha256:421b224dc4157a0d66625acb5798cf50858cfa06a5232d39a8bd6cf1fa88aca3", - "sha256:4284120c978fb7039901bf6e66832cb3e82ac1b2a107512e735bdb04fd5533ed", - "sha256:42c9e5cd2a48a257b1f2402334b48122501f249b8dcf77082f569f2680f185eb", - "sha256:4534cbfad73cdb1a6dad495530d4186d57d73089c01e9cb0558caab50e46cb3b", - "sha256:48bc2f30d1b2646d675bb8e7778ab59379bf9edc59fe06fb0e7f85ba1271bf44", - "sha256:49911cb533c96d275e31e7eaeb0742ac3f7afe386a1d8c40937814d75039a0f7", - "sha256:499af2aff04f65b4c23de1df08e1d1484a93b23ddaaa0163e44b5070b68356eb", - "sha256:4a0055943074c6c85b77fcc3f42f7c54010a3478daa2ed9d6243d0411c84a4d3", - "sha256:4d700e011156ff112966c6d77faaae125fcaf538f4cec2b9ce8957de82858f0f", - "sha256:50db41e875e36aec11881b8b12bc69c6f4836b7dd9e88a9e5bbf26c2cb3ba6cd", - "sha256:5158ae6d8dd112d003f677039a3613ca7d2592bfe35d7accf23684edb961fc26", - "sha256:56e1ebf6eb4438b8c45cbe7e7b22fc65df0c9efa97a70d3bf2f51e08b19756a5", - "sha256:59641eb1f41cb688b3cb2f98c9003c493a5024325f76b5c02333d08dd972127c", - "sha256:5af43ca7026ead3dd08b261e4f7163cd2cf3ceaa74fa5a81f7b7ea5d445e41d6", - "sha256:5c59bb4ca88e1c69931468bf21f91c8f64d8bf1999eb163b7a2df336f60c304a", - "sha256:633f19d1990b1cf9c67dce9c28bf8b5a18e42785d15548607a100e1236384d5d", - "sha256:6716855f9c669c9e25a185d88e0f169839bf8553d16496796325acd114607c11", - "sha256:6805b007af3557ee6c20dab491b6e55a8177f5b6845d9e6c653374d540366ba7", - "sha256:695dd8231e4f1bfb9a2363775a6e4e56ad9d2058058f817203a49614f4bfe33b", - "sha256:6fa7009c843667868aa8bdb3d68e5ef3d6356dd418b17ed5ca4e1340e82483a5", - "sha256:794cce219bbcb2f36ca220f27d5afd64eaa854e04901bd6f240be156a578b607", - "sha256:7b60caf0fa5f1b49f1062f7dc0f66c7b23e2736bad50fa8296bfb845995e3051", - "sha256:7e903df991f0957e2b271a37bb25d28e0d260c52825ae67507d15ca55a935961", - "sha256:7eb9e6fa8a82c3d2f519f7d3942898a97792e3895569e9501b9431048289b82f", - "sha256:816c2038008ebf50d81171ddfae377f1af9e71d504ec609469dcb0906bfcf2ae", - "sha256:849f461bffa1e7700ccfcb5186df29cd4cdcc9efdb7199cb8b5681dc37045d72", - "sha256:8506d1863f30d26f577c4ed59d2cfd03d2f39569f9cbaa02a764a9de73d312d5", - "sha256:867bebe6be30ee36a836f9b835790762a74f46be8cc339ea57b68dcecdbc1133", - "sha256:97a24c0d0806fcf9a6e75fc18aeb95adc37eb0baf6451f10a2de23ffd815329d", - "sha256:980e7eb7205e01816a92f3290cfc80507957e64656b9271a0dfebb85fe3718c0", - "sha256:9bae431a5985cdb2014be09d37206c288e0d063940cf9539e9769bd2ec26b220", - "sha256:9bebe58f7a160db7838eb70990c704db4bdc2d58bd364290fd69be0587be8bac", - "sha256:9e324a94856d88ecf10f34c102d0ded67d7c3cf644153d77e34a29720ce6aa47", - "sha256:a6e63fc67b23830947b51e0a488992e3c904fce825ead565f3904dcf621d05f7", - "sha256:a72440305f634604827f96810e4469877b89f5c060d6852267650a49b0e3768c", - "sha256:a734511144309ea6e105406633affb74e303a3df07d8a3954f9b01946e27ecb1", - "sha256:a816bff6bf424753e1ac2441902ceaf37ae6718b745a53f6aa1a60c617fb4f5f", - "sha256:a8a7a325b8fe885a6dd91093616c703134f2dacbd869bc519970df3849c2a15b", - "sha256:aa61e3da751a2dfe95aeca603f3ef510071a136ba9905f61ae6cb5d0696271ad", - "sha256:ac5895d5f78dbd8646fe37266655ba4995f9cfec38a86595282fee69e41787da", - "sha256:ac6784cc43aec51a86cf9058a2a343084f8cf46a9281bea5762bfa608127c53b", - "sha256:b1bd8017ef0da935a20106272c5f5ff6b1114add1ccb09cfed1ff7ec5cc01c6d", - "sha256:b2ac288f27a2689d9e39f4cf4df5437a8eb038eaae515169586c77f9f8fb343a", - "sha256:b30cd083ef8af4ba66d9fe5cc75c653ede3f2655f97a032db1a14cc8a006719c", - "sha256:b46ebc463bb45f278a2b94e630061c26e10077cb68d4c93583d8f4199699a5ef", - "sha256:b575393dd431b8e211de35bd593d831dac870172b16e2b7934f3566b8fc89377", - "sha256:b6569f6038133909cd658dbdcc6fc955f791dc47a7f5b55d2066f742253dcbfe", - "sha256:b8b8f88251b84b3877254cdd59c86a1dc6b2b39a03c6c9c067d344ef879562e0", - "sha256:b8eceaa12b7f152b046b67cb053ec2b5b00f73593983de69bc5e63a8aca4a7a8", - "sha256:ba74c239fc6cb6e962eabc420967c7565f3f363b776c89b3df5234caecf1f463", - "sha256:be5a454a95797343d0fb1ed02caecae73a023b1393c112951c84f17ec9f4076c", - "sha256:bef934bd3e024d512c6c0ad1c66eb173f61d9ccb4dbca8d75f727a5604f7c2f6", - "sha256:c1964dcb5f250fd13fac210944b20810d61ef4094a17fbbe502ab7a7eaeeace7", - "sha256:c34e69be4429633fc614febe3127fa03aa418a1abb9252f29d9ba5b3394573a5", - "sha256:c576bd63495150385b8d05eaae775387f378be2fd9805d3ffb4d17c87271fbad", - "sha256:cb8b10405960a8e6801a4702af98ea640130ec6ecfc1208195762de3f5503ba9", - "sha256:cc3645cf6b9246cb8e179db2803e4f0d148211d2a2cf22d5c9b5219111cd91a0", - "sha256:cd35c0be4c46274129dd1678bb911dd4e93d23968b26f4e39cd55bc7cb3b1bac", - "sha256:d540e9c34a61b53b6a374ea108794a48388178f7889d772e364cdbd6df37774c", - "sha256:d72415b0110f7958dd3a5ee98a70166f47bd42ede85e3535669c794d06f57406", - "sha256:dbae37d48ef5a0ab90cfaf2b9312d96f034b1c828208a9cbe25377a1b19ba129", - "sha256:e1c5434db53f3a94a37ad8aedb231901e001995d899af6ed1165f3d27fa04a6a", - "sha256:e75e287787e6adafed9d8c3d3e7647c0b5eb460221f9f92d7dfe48b45ba77c0d", - "sha256:e797c4afb1b7962d3205b1959e1051f7e6bfbba29da44042a9efc2391f1feb38", - "sha256:efd1b2da3ee577fcfa723a214f73186aef9674dd5b28242d90443c7a82722b0f", - "sha256:f5b43ce952a5a31441556c55f5f5f5a8e62c28581a0ff2a2c31c04ef992d73bd", - "sha256:f7194a22a4a24f3561cb6ad1cca9c9b2f2cf34cc8d4bce6d6a24c80960323fa8", - "sha256:f8101ab6de5aa0b26a2b5032bc488d430010c91863e701812d65836b03a12f61", - "sha256:fc33909397481c90de3cec831bfb88d97e220dc91939d996920202f184b4648e", - "sha256:fcc378fa97f02fbcef090b3611305425d72bd1c0afdd13ef4a82dc67d40638b6", - "sha256:ff478682e8ee6dbaa37201bb71bf4a6eee744006ab000e8f5cea05066fc7c845" + "sha256:00547da587f124b32b072ce52dd5e4b37cf199fedcea902e33c67548523e4678", + "sha256:0295289c4510efa41174850e75bc9188f82b72b1b54d0ea57d1781729c2924d5", + "sha256:03b58f843f09e73414e82e57f7e8d88f087eaabf8f276b866a40661161da6c51", + "sha256:0568d4da0a9ee9f9f5ab318f6501557f1cfe26d18c96c8e0dac7332ae04c6717", + "sha256:08a0e03f287e45eb694998bb55ac1643372199c659affa8319dfbbdec7f7fb3c", + "sha256:0a9d12436fd64937bd2c9609605f527af7f1a8db6e6637639b44121c0fe715d6", + "sha256:101b5bd32badfc8b1f9c7be04ba3ae04fb47f9c8736590666ce9449bff76e0b1", + "sha256:14108cafb140dd68fdda610c2bbc6a37bf052cd48cfebf487ed44145f7a2b67f", + "sha256:18580d060fa637ff01541640ecde6de832a248df02b8fb57e6dd578f189d62c7", + "sha256:18a0f838677f9510aef0330c0096778dd6406d21d4ff9504bf79d85235a18460", + "sha256:1ce324d1b413636ea5ee929f79637821f13c9e55e9588f38228947294944d2ed", + "sha256:246368e983eaee9851b15d7755f82030eab4aa82098d2a34f6bef9c689d33fcc", + "sha256:24c0d71e9ac91f4466b1bd280f7de43aa4d94682daaf34d85d867a9b479b87cc", + "sha256:275d53fd769df2102d6c9fc98e553bd8a9a38926f54d6b20cf29f0dd00bf3b75", + "sha256:294d24edc747ef4e1b28e54365f713becb844e7898113fafbe3e9165dc44aeea", + "sha256:2fb740482794a72e2e5fec58e4d9b00dcd5a60a8cef68431ff12f2ba0e0d9a7e", + "sha256:31d4b0455d72d914645f803d917daf4f314d115c70de0578d3820deb8b101f66", + "sha256:388f840fd911d61a96e9e595eaf003f9dc39e847c9060b8e623ab29e556f009b", + "sha256:3e993804e6b04113d61fdb9541b6df2f096ec265a506dad7437517470919c90f", + "sha256:4180b2785d1278e6abb36a72ac97c92432db53fa2df00ee943d2c15a33627d31", + "sha256:4416ee86a87180b6a28e7483102c92debc077bec59c67eda8cc63fc52a218ac0", + "sha256:45c7b4eac7571707269ebc2893facdf87e359cd5c7cfbfa9e6bd8b33fb1079c5", + "sha256:460c05238fbfe6d848141669d17a751a46c923f9f0c9fd8a3a462ab737623a44", + "sha256:478051e5ef8278b2429864c8d148efcebdc2be948a61c9a44757cd8c816c98f5", + "sha256:481e3129a76ea01adcc0e7097ccb8dbddab1cfc40b6f0e32c670153512957c0f", + "sha256:48425107fbb1af3f0f2410c004f16be10ffc9374358e5600b57fa543f46f8def", + "sha256:4a7d8b869ded171f6cdf584fc2fc6ae03b30a0e1e37a9daf213a59857a62ed90", + "sha256:4bff49986c9bae127928a2f9fd6313146a342bfae8292f63e562f872bd01b871", + "sha256:51d3495235af09f21aa92a7cdd51504bda640b108b6be834448b774f52852c09", + "sha256:5556acde785a61d4cf8b8534ae109b023cbd2f9df65ee2afbe070be47c410f8c", + "sha256:55e94124af9c8fbb1df54195cc092688fdad0765641b738970b6f1d5ea72e776", + "sha256:5616d386dfbfba7c39e9418ba668c734f6ceaacc0130877e8a100cad11e6838b", + "sha256:57233e1600560ceb719bed759dc78393edd541b9a3e7fefc3079abd83c26a6ea", + "sha256:593e89e2518eaf81e96edcc9ef2c5fca666e8fc922b03d5cb7a7b8964dbee336", + "sha256:5998f81bf6a2b28a802521efe14d9fc119f74b64e87b62ad1b0e7c3d8366d0c7", + "sha256:5e4e612b7ecc9596e7c859cd9e0cd085e6d0c576b4f0d917299595eb56bf9c05", + "sha256:5fef7b602ccf8a3c77ab483479ccd7a952a8c5bb1c263156671ba7aaa24d1035", + "sha256:63b31345e20afda2ae30dba246955517a4264464d75e071fc2fa641e88c763ec", + "sha256:663911786dcde3e4a5d88215c722c531c7548903dc07d418418c0d1c768072c0", + "sha256:673d6e9e3aa86949343b46ac2b7be266c36e07ce77fa1d40f349e6987a814d6e", + "sha256:68ae7091cc73a752f0b938f15bb193de80ca5edf5ae2ea6360d93d3e9228357b", + "sha256:698da4fa1f7baeea0607738cb1f9877ed1ba50342b29891b0223221679d6f729", + "sha256:6a93644d7996fd696ab7f1f466cd75d718d0a00d5c8118b9fe8c64231dc1f85e", + "sha256:6c8d0dff4865da54ae825d43e1721925721b19f3b9aca8e730c2ce73dee2c630", + "sha256:732d08228fa8d366fec284f7032cc868d28a99fa81fc71e3adf7ecedbcf33a0f", + "sha256:735147aa41b8eeb104da186864b55e2a6623c758000081d19c93d759cd9523e3", + "sha256:7a92aab8dd1d427ac9bc7480cfd3481dbab0ef024558f2f5a47de672d8a5ffaa", + "sha256:7d352d4de060604e605abdc5c8a5d0429d5f156cb9866609065d3003454d4cea", + "sha256:81074edf3c74bc9bd250d223408a5df0ff745d1f7a462597536cd26b9390e2d6", + "sha256:81e6a9a8fda78a2f4901d2915b25bf620f372997ca1f20a14f7cefef5ad6f6f4", + "sha256:843500cd3e4884b92fd4037912bc42d5f047108d2c986d36352e880196d465b0", + "sha256:89247ac220031a4f9f689688bcee42b38fd770d4cce294e5d914afc53b630abe", + "sha256:8bb624dbaef4661f5e3625c1e39ad98ecceef281d1380e2774d8084ad0810275", + "sha256:9007bb1290c79402be6b84bcf9e7a622a073859d61fcee146dc7bc47afe328f3", + "sha256:9070ae35c410d644e6df98a8f69f3ed2807e657d0df2a26b2643127cbf6944a5", + "sha256:908c13f305d34322e11b796de358edaeea47dd2d115c33ca22909c5e8fb036fd", + "sha256:9480b4b327be83c4d29cb88bcace761b11f5e30198ffe2287889455c6819e934", + "sha256:960d85ebaa974ecea4e71fa56d098378fa51fd670ee744614cbb95bf95e28fc7", + "sha256:96796594c770bc6587376e74ddc7d9c982d68f47116bb69d90873db5e0ea88b6", + "sha256:97cf514a9f3426228d8daf880f56488330e4b2948a6d183a106921217850d9eb", + "sha256:997b7e0960072f6bb445402da162f964ea67387b9f18bda2361edcc026e13597", + "sha256:9b28787eaf2174e68f0acb3c66f9c6b98bdfeb0930c0d0b08e1941c7aedc8d27", + "sha256:9bf51354e15520715f068853e6ab8190e77139940e8b8b633bdb587956a08fb0", + "sha256:9e5075e30be626ef0f9bedf7a15f55ed4d7209e832bc314fdc232dbd61dcbf44", + "sha256:a08b4346350660799d81d4016e748bcb134a9083301d41f9618f64a6077f89f2", + "sha256:a67f75cc51a2dc7229a8ac84291e4d61dc5abfc8940befcf37a2836d95873340", + "sha256:a973f5286758f76824ecf19ae1999f6697371a9121c8f163295d181d19a819d7", + "sha256:ab911033e5937fc221a2c165acce7f66ae5ac9d3e54bec56f3c9c197a96be574", + "sha256:ad92e37be0b106fdbc575a3a669b43b364a5ef334495c9764de4c2d7541f7a99", + "sha256:ad9ea4a50d2948738351790047d45f2b1a023facc01bf0361988109b177e8b2f", + "sha256:b029bdd5a8b6c9a7c0e8fdbe4fc25ffaa2e09b77f6f3462314696e3a20511829", + "sha256:b41a85b9b9a2530b72b0d3d10e383fc3c2647ae88169d557d5e216f881860318", + "sha256:baf020f4b708f800b353259cd7575e335a79f1ac912d9dda55b2aa0bf3616e42", + "sha256:c08094b9e5d1b6dfb0845a0253cc2655ca64ce70d15162dfdb102e28c8993493", + "sha256:c26805b6c8dc8565ed91045c44040bf6c0fe5cb5b390c78cd1d9400d08a6cd39", + "sha256:c6ee222671eed5c5b16a5ad2aea07f0a715b8b199ee534834bc1dd2798f1ade7", + "sha256:c820608e7077416f766b148d75e158e454881961881b657cff808529d261dd24", + "sha256:cb081b2b02bf4405c804de1ece6f904916838ab0e057f1446e4ac12fac827960", + "sha256:cbe038bb78d599b5a29d09c438905defaa615a522bc7e12f8016823179439497", + "sha256:cd461e402e24929d866f05061d2f8337e3a8456e75e21b72c125abff2477c7f7", + "sha256:cde6dbb788a4cbc4a80a72aa96386ba4c2b17bdfff3ace0709799adbe16d6476", + "sha256:ce7889dc3701826d519ede93cdff11940fb5567dbdc165dce0e78047eece02b7", + "sha256:d0086ba8d41d73647b13087a3ca9c020f6bfec338335037e8f5172b4c7c8dce5", + "sha256:d29988bde28a90a00367edcf92afa1a2f7ecf43ea3ae383291b7da6d380ccc25", + "sha256:d494befe648c13c98c0f3d56d05489c839c9228a32f58e9777305deb6c2c1cee", + "sha256:df4e32badb2ccf1773e1e74020b7e3b8caf9e92f842c6be7d14888ecdefc2c6c", + "sha256:e6de6a4bdfaee382c2de2a3580b3ae76fce6105da202bbd835e5efbeae6a9c6e", + "sha256:f039c5373f7b314b151432c73219216857b19ab9cb834f0eb5d880f74fc7851c", + "sha256:f6e86ac2b45a95f75c6f744147483e0fc9697ce7dfe1726083324c236f873f8b", + "sha256:f9c690b359f503f18bf1c46a6456370e4f6f3fc4320b8774ae69c4f85ecc6c94", + "sha256:fa436abd4ac9ca71859baf5794614e6ec8fa27362f0162baedcc059048da55f7", + "sha256:fa44215bc31675a6380cd896dadb7f2054a7b94cfb87e53e52af844c65406a54", + "sha256:ff451d614ca1d4227db0ffa627fb51df71968cf0d9baf0210528dad10fdbc3ab" ], "markers": "implementation_name == 'cpython'", - "version": "==0.12.1" + "version": "==0.12.2" }, "dataclassy": { "hashes": [ @@ -621,6 +619,7 @@ "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd" ], "index": "pypi", + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", "version": "==0.18.0" }, "eip712": { @@ -629,15 +628,16 @@ "sha256:c984c577358d1c7e5d4e52802bf4bd0432e965ba7326448998f95fcc1b6d5269" ], "index": "pypi", + "markers": "python_version >= '3.8' and python_version < '4'", "version": "==0.2.1" }, "eth-abi": { "hashes": [ - "sha256:15f9870ca054c09a8e474d2d7e81aff0c32421aebdac896193183fc143e31b50", - "sha256:fe738cdb24983adfe89abf727c723c288f8d0029e97fb08160b20bb5290ab475" + "sha256:0d50469de2f9948bacd764fc3f8f337a090bbb6ac3a759ef22c094bf56c1e6d9", + "sha256:a9adae5e0c2b9a35703b76856d6db3a0498effdf1243011b2d56280165db1cdd" ], "markers": "python_full_version >= '3.7.2' and python_version < '4'", - "version": "==4.1.0" + "version": "==4.2.0" }, "eth-account": { "hashes": [ @@ -690,193 +690,182 @@ }, "eth-utils": { "hashes": [ - "sha256:4938ab742f91cdf19bae024261af090664f63ccf83bdb1213e7146c14209e899", - "sha256:7cccfb0b0749431d0d001e327e9a7289bf07308316a73850ae3895020e5682f4" + "sha256:7f1a9e10400ee332432a778c321f446abaedb8f538df550e7c9964f446f7e265", + "sha256:d6e107d522f83adff31237a95bdcc329ac0819a3ac698fe43c8a56fd80813eab" ], "markers": "python_version >= '3.7' and python_version < '4'", - "version": "==2.1.1" + "version": "==2.2.0" }, "frozenlist": { "hashes": [ - "sha256:008a054b75d77c995ea26629ab3a0c0d7281341f2fa7e1e85fa6153ae29ae99c", - "sha256:02c9ac843e3390826a265e331105efeab489ffaf4dd86384595ee8ce6d35ae7f", - "sha256:034a5c08d36649591be1cbb10e09da9f531034acfe29275fc5454a3b101ce41a", - "sha256:05cdb16d09a0832eedf770cb7bd1fe57d8cf4eaf5aced29c4e41e3f20b30a784", - "sha256:0693c609e9742c66ba4870bcee1ad5ff35462d5ffec18710b4ac89337ff16e27", - "sha256:0771aed7f596c7d73444c847a1c16288937ef988dc04fb9f7be4b2aa91db609d", - "sha256:0af2e7c87d35b38732e810befb9d797a99279cbb85374d42ea61c1e9d23094b3", - "sha256:14143ae966a6229350021384870458e4777d1eae4c28d1a7aa47f24d030e6678", - "sha256:180c00c66bde6146a860cbb81b54ee0df350d2daf13ca85b275123bbf85de18a", - "sha256:1841e200fdafc3d51f974d9d377c079a0694a8f06de2e67b48150328d66d5483", - "sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8", - "sha256:2b07ae0c1edaa0a36339ec6cce700f51b14a3fc6545fdd32930d2c83917332cf", - "sha256:2c926450857408e42f0bbc295e84395722ce74bae69a3b2aa2a65fe22cb14b99", - "sha256:2e24900aa13212e75e5b366cb9065e78bbf3893d4baab6052d1aca10d46d944c", - "sha256:303e04d422e9b911a09ad499b0368dc551e8c3cd15293c99160c7f1f07b59a48", - "sha256:352bd4c8c72d508778cf05ab491f6ef36149f4d0cb3c56b1b4302852255d05d5", - "sha256:3843f84a6c465a36559161e6c59dce2f2ac10943040c2fd021cfb70d58c4ad56", - "sha256:394c9c242113bfb4b9aa36e2b80a05ffa163a30691c7b5a29eba82e937895d5e", - "sha256:3bbdf44855ed8f0fbcd102ef05ec3012d6a4fd7c7562403f76ce6a52aeffb2b1", - "sha256:40de71985e9042ca00b7953c4f41eabc3dc514a2d1ff534027f091bc74416401", - "sha256:41fe21dc74ad3a779c3d73a2786bdf622ea81234bdd4faf90b8b03cad0c2c0b4", - "sha256:47df36a9fe24054b950bbc2db630d508cca3aa27ed0566c0baf661225e52c18e", - "sha256:4ea42116ceb6bb16dbb7d526e242cb6747b08b7710d9782aa3d6732bd8d27649", - "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a", - "sha256:5c11e43016b9024240212d2a65043b70ed8dfd3b52678a1271972702d990ac6d", - "sha256:5cf820485f1b4c91e0417ea0afd41ce5cf5965011b3c22c400f6d144296ccbc0", - "sha256:5d8860749e813a6f65bad8285a0520607c9500caa23fea6ee407e63debcdbef6", - "sha256:6327eb8e419f7d9c38f333cde41b9ae348bec26d840927332f17e887a8dcb70d", - "sha256:65a5e4d3aa679610ac6e3569e865425b23b372277f89b5ef06cf2cdaf1ebf22b", - "sha256:66080ec69883597e4d026f2f71a231a1ee9887835902dbe6b6467d5a89216cf6", - "sha256:783263a4eaad7c49983fe4b2e7b53fa9770c136c270d2d4bbb6d2192bf4d9caf", - "sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef", - "sha256:7fdfc24dcfce5b48109867c13b4cb15e4660e7bd7661741a391f821f23dfdca7", - "sha256:810860bb4bdce7557bc0febb84bbd88198b9dbc2022d8eebe5b3590b2ad6c842", - "sha256:841ea19b43d438a80b4de62ac6ab21cfe6827bb8a9dc62b896acc88eaf9cecba", - "sha256:84610c1502b2461255b4c9b7d5e9c48052601a8957cd0aea6ec7a7a1e1fb9420", - "sha256:899c5e1928eec13fd6f6d8dc51be23f0d09c5281e40d9cf4273d188d9feeaf9b", - "sha256:8bae29d60768bfa8fb92244b74502b18fae55a80eac13c88eb0b496d4268fd2d", - "sha256:8df3de3a9ab8325f94f646609a66cbeeede263910c5c0de0101079ad541af332", - "sha256:8fa3c6e3305aa1146b59a09b32b2e04074945ffcfb2f0931836d103a2c38f936", - "sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816", - "sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91", - "sha256:9545a33965d0d377b0bc823dcabf26980e77f1b6a7caa368a365a9497fb09420", - "sha256:9ac5995f2b408017b0be26d4a1d7c61bce106ff3d9e3324374d66b5964325448", - "sha256:9bbbcedd75acdfecf2159663b87f1bb5cfc80e7cd99f7ddd9d66eb98b14a8411", - "sha256:a4ae8135b11652b08a8baf07631d3ebfe65a4c87909dbef5fa0cdde440444ee4", - "sha256:a6394d7dadd3cfe3f4b3b186e54d5d8504d44f2d58dcc89d693698e8b7132b32", - "sha256:a97b4fe50b5890d36300820abd305694cb865ddb7885049587a5678215782a6b", - "sha256:ae4dc05c465a08a866b7a1baf360747078b362e6a6dbeb0c57f234db0ef88ae0", - "sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530", - "sha256:b1e2c1185858d7e10ff045c496bbf90ae752c28b365fef2c09cf0fa309291669", - "sha256:b4395e2f8d83fbe0c627b2b696acce67868793d7d9750e90e39592b3626691b7", - "sha256:b756072364347cb6aa5b60f9bc18e94b2f79632de3b0190253ad770c5df17db1", - "sha256:ba64dc2b3b7b158c6660d49cdb1d872d1d0bf4e42043ad8d5006099479a194e5", - "sha256:bed331fe18f58d844d39ceb398b77d6ac0b010d571cba8267c2e7165806b00ce", - "sha256:c188512b43542b1e91cadc3c6c915a82a5eb95929134faf7fd109f14f9892ce4", - "sha256:c21b9aa40e08e4f63a2f92ff3748e6b6c84d717d033c7b3438dd3123ee18f70e", - "sha256:ca713d4af15bae6e5d79b15c10c8522859a9a89d3b361a50b817c98c2fb402a2", - "sha256:cd4210baef299717db0a600d7a3cac81d46ef0e007f88c9335db79f8979c0d3d", - "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9", - "sha256:d5cd3ab21acbdb414bb6c31958d7b06b85eeb40f66463c264a9b343a4e238642", - "sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0", - "sha256:e235688f42b36be2b6b06fc37ac2126a73b75fb8d6bc66dd632aa35286238703", - "sha256:eb82dbba47a8318e75f679690190c10a5e1f447fbf9df41cbc4c3afd726d88cb", - "sha256:ebb86518203e12e96af765ee89034a1dbb0c3c65052d1b0c19bbbd6af8a145e1", - "sha256:ee78feb9d293c323b59a6f2dd441b63339a30edf35abcb51187d2fc26e696d13", - "sha256:eedab4c310c0299961ac285591acd53dc6723a1ebd90a57207c71f6e0c2153ab", - "sha256:efa568b885bca461f7c7b9e032655c0c143d305bf01c30caf6db2854a4532b38", - "sha256:efce6ae830831ab6a22b9b4091d411698145cb9b8fc869e1397ccf4b4b6455cb", - "sha256:f163d2fd041c630fed01bc48d28c3ed4a3b003c00acd396900e11ee5316b56bb", - "sha256:f20380df709d91525e4bee04746ba612a4df0972c1b8f8e1e8af997e678c7b81", - "sha256:f30f1928162e189091cf4d9da2eac617bfe78ef907a761614ff577ef4edfb3c8", - "sha256:f470c92737afa7d4c3aacc001e335062d582053d4dbe73cda126f2d7031068dd", - "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4" - ], - "markers": "python_version >= '3.7'", - "version": "==1.3.3" + "sha256:007df07a6e3eb3e33e9a1fe6a9db7af152bbd8a185f9aaa6ece10a3529e3e1c6", + "sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01", + "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251", + "sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9", + "sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b", + "sha256:10ff5faaa22786315ef57097a279b833ecab1a0bfb07d604c9cbb1c4cdc2ed87", + "sha256:17ae5cd0f333f94f2e03aaf140bb762c64783935cc764ff9c82dff626089bebf", + "sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f", + "sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0", + "sha256:1e78fb68cf9c1a6aa4a9a12e960a5c9dfbdb89b3695197aa7064705662515de2", + "sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b", + "sha256:2b8bcf994563466db019fab287ff390fffbfdb4f905fc77bc1c1d604b1c689cc", + "sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c", + "sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467", + "sha256:491e014f5c43656da08958808588cc6c016847b4360e327a62cb308c791bd2d9", + "sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1", + "sha256:556de4430ce324c836789fa4560ca62d1591d2538b8ceb0b4f68fb7b2384a27a", + "sha256:5833593c25ac59ede40ed4de6d67eb42928cca97f26feea219f21d0ed0959b79", + "sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167", + "sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300", + "sha256:6c38721585f285203e4b4132a352eb3daa19121a035f3182e08e437cface44bf", + "sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea", + "sha256:7211ef110a9194b6042449431e08c4d80c0481e5891e58d429df5899690511c2", + "sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab", + "sha256:7645a8e814a3ee34a89c4a372011dcd817964ce8cb273c8ed6119d706e9613e3", + "sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb", + "sha256:7f4f399d28478d1f604c2ff9119907af9726aed73680e5ed1ca634d377abb087", + "sha256:88f7bc0fcca81f985f78dd0fa68d2c75abf8272b1f5c323ea4a01a4d7a614efc", + "sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8", + "sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62", + "sha256:93ea75c050c5bb3d98016b4ba2497851eadf0ac154d88a67d7a6816206f6fa7f", + "sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326", + "sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c", + "sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431", + "sha256:a0c6da9aee33ff0b1a451e867da0c1f47408112b3391dd43133838339e410963", + "sha256:a6c8097e01886188e5be3e6b14e94ab365f384736aa1fca6a0b9e35bd4a30bc7", + "sha256:aa384489fefeb62321b238e64c07ef48398fe80f9e1e6afeff22e140e0850eef", + "sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3", + "sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956", + "sha256:b826d97e4276750beca7c8f0f1a4938892697a6bcd8ec8217b3312dad6982781", + "sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472", + "sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc", + "sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839", + "sha256:c11b0746f5d946fecf750428a95f3e9ebe792c1ee3b1e96eeba145dc631a9672", + "sha256:c5374b80521d3d3f2ec5572e05adc94601985cc526fb276d0c8574a6d749f1b3", + "sha256:ca265542ca427bf97aed183c1676e2a9c66942e822b14dc6e5f42e038f92a503", + "sha256:ce31ae3e19f3c902de379cf1323d90c649425b86de7bbdf82871b8a2a0615f3d", + "sha256:ceb6ec0a10c65540421e20ebd29083c50e6d1143278746a4ef6bcf6153171eb8", + "sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b", + "sha256:d5655a942f5f5d2c9ed93d72148226d75369b4f6952680211972a33e59b1dfdc", + "sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f", + "sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559", + "sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b", + "sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95", + "sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb", + "sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963", + "sha256:e66d2a64d44d50d2543405fb183a21f76b3b5fd16f130f5c99187c3fb4e64919", + "sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f", + "sha256:f0ed05f5079c708fe74bf9027e95125334b6978bf07fd5ab923e9e55e5fbb9d3", + "sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1", + "sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e" + ], + "markers": "python_version >= '3.8'", + "version": "==1.4.0" }, "grpcio": { "hashes": [ - "sha256:0212e2f7fdf7592e4b9d365087da30cb4d71e16a6f213120c89b4f8fb35a3ab3", - "sha256:09d4bfd84686cd36fd11fd45a0732c7628308d094b14d28ea74a81db0bce2ed3", - "sha256:1e623e0cf99a0ac114f091b3083a1848dbc64b0b99e181473b5a4a68d4f6f821", - "sha256:2288d76e4d4aa7ef3fe7a73c1c470b66ea68e7969930e746a8cd8eca6ef2a2ea", - "sha256:2296356b5c9605b73ed6a52660b538787094dae13786ba53080595d52df13a98", - "sha256:2a1e601ee31ef30a9e2c601d0867e236ac54c922d32ed9f727b70dd5d82600d5", - "sha256:2be88c081e33f20630ac3343d8ad9f1125f32987968e9c8c75c051c9800896e8", - "sha256:33d40954199bddbb6a78f8f6f2b2082660f381cd2583ec860a6c2fa7c8400c08", - "sha256:40e1cbf69d6741b40f750f3cccc64326f927ac6145a9914d33879e586002350c", - "sha256:46a057329938b08e5f0e12ea3d7aed3ecb20a0c34c4a324ef34e00cecdb88a12", - "sha256:4864f99aac207e3e45c5e26c6cbb0ad82917869abc2f156283be86c05286485c", - "sha256:4c44e1a765b31e175c391f22e8fc73b2a2ece0e5e6ff042743d8109b5d2eff9f", - "sha256:4cb283f630624ebb16c834e5ac3d7880831b07cbe76cb08ab7a271eeaeb8943e", - "sha256:5008964885e8d23313c8e5ea0d44433be9bfd7e24482574e8cc43c02c02fc796", - "sha256:50a9f075eeda5097aa9a182bb3877fe1272875e45370368ac0ee16ab9e22d019", - "sha256:51630c92591d6d3fe488a7c706bd30a61594d144bac7dee20c8e1ce78294f474", - "sha256:5cc928cfe6c360c1df636cf7991ab96f059666ac7b40b75a769410cc6217df9c", - "sha256:61f7203e2767800edee7a1e1040aaaf124a35ce0c7fe0883965c6b762defe598", - "sha256:66233ccd2a9371158d96e05d082043d47dadb18cbb294dc5accfdafc2e6b02a7", - "sha256:70fcac7b94f4c904152809a050164650ac81c08e62c27aa9f156ac518029ebbe", - "sha256:714242ad0afa63a2e6dabd522ae22e1d76e07060b5af2ddda5474ba4f14c2c94", - "sha256:782f4f8662a2157c4190d0f99eaaebc602899e84fb1e562a944e5025929e351c", - "sha256:7fc2b4edb938c8faa4b3c3ea90ca0dd89b7565a049e8e4e11b77e60e4ed2cc05", - "sha256:881d058c5ccbea7cc2c92085a11947b572498a27ef37d3eef4887f499054dca8", - "sha256:89dde0ac72a858a44a2feb8e43dc68c0c66f7857a23f806e81e1b7cc7044c9cf", - "sha256:8cdbcbd687e576d48f7886157c95052825ca9948c0ed2afdc0134305067be88b", - "sha256:8d6192c37a30a115f4663592861f50e130caed33efc4eec24d92ec881c92d771", - "sha256:96a41817d2c763b1d0b32675abeb9179aa2371c72aefdf74b2d2b99a1b92417b", - "sha256:9bdbb7624d65dc0ed2ed8e954e79ab1724526f09b1efa88dcd9a1815bf28be5f", - "sha256:9bf88004fe086c786dc56ef8dd6cb49c026833fdd6f42cb853008bce3f907148", - "sha256:a08920fa1a97d4b8ee5db2f31195de4a9def1a91bc003544eb3c9e6b8977960a", - "sha256:a2f5a1f1080ccdc7cbaf1171b2cf384d852496fe81ddedeb882d42b85727f610", - "sha256:b04202453941a63b36876a7172b45366dc0cde10d5fd7855c0f4a4e673c0357a", - "sha256:b38b3de8cff5bc70f8f9c615f51b48eff7313fc9aca354f09f81b73036e7ddfa", - "sha256:b52d00d1793d290c81ad6a27058f5224a7d5f527867e5b580742e1bd211afeee", - "sha256:b74ae837368cfffeb3f6b498688a123e6b960951be4dec0e869de77e7fa0439e", - "sha256:be48496b0e00460717225e7680de57c38be1d8629dc09dadcd1b3389d70d942b", - "sha256:c0e3155fc5335ec7b3b70f15230234e529ca3607b20a562b6c75fb1b1218874c", - "sha256:c2392f5b5d84b71d853918687d806c1aa4308109e5ca158a16e16a6be71041eb", - "sha256:c72956972e4b508dd39fdc7646637a791a9665b478e768ffa5f4fe42123d5de1", - "sha256:dc80c9c6b608bf98066a038e0172013a49cfa9a08d53335aefefda2c64fc68f4", - "sha256:e416c8baf925b5a1aff31f7f5aecc0060b25d50cce3a5a7255dc5cf2f1d4e5eb", - "sha256:f8da84bbc61a4e92af54dc96344f328e5822d574f767e9b08e1602bb5ddc254a", - "sha256:f900ed4ad7a0f1f05d35f955e0943944d5a75f607a836958c6b8ab2a81730ef2", - "sha256:fd6c6c29717724acf9fc1847c4515d57e4dc12762452457b9cb37461f30a81bb" + "sha256:00258cbe3f5188629828363ae8ff78477ce976a6f63fb2bb5e90088396faa82e", + "sha256:092fa155b945015754bdf988be47793c377b52b88d546e45c6a9f9579ac7f7b6", + "sha256:0f80bf37f09e1caba6a8063e56e2b87fa335add314cf2b78ebf7cb45aa7e3d06", + "sha256:20ec6fc4ad47d1b6e12deec5045ec3cd5402d9a1597f738263e98f490fe07056", + "sha256:2313b124e475aa9017a9844bdc5eafb2d5abdda9d456af16fc4535408c7d6da6", + "sha256:23e7d8849a0e58b806253fd206ac105b328171e01b8f18c7d5922274958cc87e", + "sha256:2f708a6a17868ad8bf586598bee69abded4996b18adf26fd2d91191383b79019", + "sha256:2f7349786da979a94690cc5c2b804cab4e8774a3cf59be40d037c4342c906649", + "sha256:34950353539e7d93f61c6796a007c705d663f3be41166358e3d88c45760c7d98", + "sha256:40b72effd4c789de94ce1be2b5f88d7b9b5f7379fe9645f198854112a6567d9a", + "sha256:4b089f7ad1eb00a104078bab8015b0ed0ebcb3b589e527ab009c53893fd4e613", + "sha256:4faea2cfdf762a664ab90589b66f416274887641ae17817de510b8178356bf73", + "sha256:5371bcd861e679d63b8274f73ac281751d34bd54eccdbfcd6aa00e692a82cd7b", + "sha256:5613a2fecc82f95d6c51d15b9a72705553aa0d7c932fad7aed7afb51dc982ee5", + "sha256:57b183e8b252825c4dd29114d6c13559be95387aafc10a7be645462a0fc98bbb", + "sha256:5b7a4ce8f862fe32b2a10b57752cf3169f5fe2915acfe7e6a1e155db3da99e79", + "sha256:5e5b58e32ae14658085c16986d11e99abd002ddbf51c8daae8a0671fffb3467f", + "sha256:60fe15288a0a65d5c1cb5b4a62b1850d07336e3ba728257a810317be14f0c527", + "sha256:6907b1cf8bb29b058081d2aad677b15757a44ef2d4d8d9130271d2ad5e33efca", + "sha256:76c44efa4ede1f42a9d5b2fed1fe9377e73a109bef8675fb0728eb80b0b8e8f2", + "sha256:7a635589201b18510ff988161b7b573f50c6a48fae9cb567657920ca82022b37", + "sha256:7b400807fa749a9eb286e2cd893e501b110b4d356a218426cb9c825a0474ca56", + "sha256:82640e57fb86ea1d71ea9ab54f7e942502cf98a429a200b2e743d8672171734f", + "sha256:871f9999e0211f9551f368612460442a5436d9444606184652117d6a688c9f51", + "sha256:9338bacf172e942e62e5889b6364e56657fbf8ac68062e8b25c48843e7b202bb", + "sha256:a8a8e560e8dbbdf29288872e91efd22af71e88b0e5736b0daf7773c1fecd99f0", + "sha256:aed90d93b731929e742967e236f842a4a2174dc5db077c8f9ad2c5996f89f63e", + "sha256:b363bbb5253e5f9c23d8a0a034dfdf1b7c9e7f12e602fc788c435171e96daccc", + "sha256:b4098b6b638d9e0ca839a81656a2fd4bc26c9486ea707e8b1437d6f9d61c3941", + "sha256:b53333627283e7241fcc217323f225c37783b5f0472316edcaa4479a213abfa6", + "sha256:b670c2faa92124b7397b42303e4d8eb64a4cd0b7a77e35a9e865a55d61c57ef9", + "sha256:bb396952cfa7ad2f01061fbc7dc1ad91dd9d69243bcb8110cf4e36924785a0fe", + "sha256:c60b83c43faeb6d0a9831f0351d7787a0753f5087cc6fa218d78fdf38e5acef0", + "sha256:c6ebecfb7a31385393203eb04ed8b6a08f5002f53df3d59e5e795edb80999652", + "sha256:d78d8b86fcdfa1e4c21f8896614b6cc7ee01a2a758ec0c4382d662f2a62cf766", + "sha256:d7f8df114d6b4cf5a916b98389aeaf1e3132035420a88beea4e3d977e5f267a5", + "sha256:e1cb52fa2d67d7f7fab310b600f22ce1ff04d562d46e9e0ac3e3403c2bb4cc16", + "sha256:e3fdf04e402f12e1de8074458549337febb3b45f21076cc02ef4ff786aff687e", + "sha256:e503cb45ed12b924b5b988ba9576dc9949b2f5283b8e33b21dcb6be74a7c58d0", + "sha256:f19ac6ac0a256cf77d3cc926ef0b4e64a9725cc612f97228cd5dc4bd9dbab03b", + "sha256:f1fb0fd4a1e9b11ac21c30c169d169ef434c6e9344ee0ab27cfa6f605f6387b2", + "sha256:fada6b07ec4f0befe05218181f4b85176f11d531911b64c715d1875c4736d73a", + "sha256:fd173b4cf02b20f60860dc2ffe30115c18972d7d6d2d69df97ac38dee03be5bf", + "sha256:fe752639919aad9ffb0dee0d87f29a6467d1ef764f13c4644d212a9a853a078d", + "sha256:fee387d2fab144e8a34e0e9c5ca0f45c9376b99de45628265cfa9886b1dbe62b" ], "index": "pypi", - "version": "==1.54.2" + "markers": "python_version >= '3.7'", + "version": "==1.57.0" }, "grpcio-tools": { "hashes": [ - "sha256:0239b929eb8b3b30b2397eef3b9abb245087754d77c3721e3be43c44796de87d", - "sha256:0ab1b323905d449298523db5d34fa5bf5fffd645bd872b25598e2f8a01f0ea39", - "sha256:0de05c7698c655e9a240dc34ae91d6017b93143ac89e5b20046d7ca3bd09c27c", - "sha256:0f952c8a5c47e9204fe8959f7e9add149e660f6579d67cf65024c32736d34caf", - "sha256:10dd41862f579d185c60f629b5ee89103e216f63b576079d258d974d980bad87", - "sha256:11939c9a8a39bd4815c7e88cb2fee48e1948775b59dbb06de8fcae5991e84f9e", - "sha256:129de5579f95d6a55dde185f188b4cbe19d1e2f1471425431d9930c31d300d70", - "sha256:1b8ee3099c51ce987fa8a08e6b93fc342b10228415dd96b5c0caa0387f636a6f", - "sha256:21b1467e31e44429d2a78b50135c9cdbd4b8f6d3b5cd548bc98985d3bdc352d0", - "sha256:21b9d2dee80f3f77e4097252e7f0db89772335a7300b72ab3d2e5c280872b1db", - "sha256:27671c68c7e0e3c5ff9967f5500799f65a04e7b153b8ce10243c87c43199039d", - "sha256:2b96f5f17d3156058be247fd25b062b4768138665694c00b056659618b8fb418", - "sha256:30a49b8b168aced2a4ff40959e6c4383ad6cfd7a20839a47a215e9837eb722dc", - "sha256:3237149beec39e897fd62cef4aa1e1cd9422d7a95661d24bd0a79200b167e730", - "sha256:37393ef90674964175923afe3859fc5a208e1ece565f642b4f76a8c0224a0993", - "sha256:39fd530cfdf58dc05125775cc233b05554d553d27478f14ae5fd8a6306f0cb28", - "sha256:3bb9ec4aea0f2b3006fb002fa59e5c10f92b48fc374619fbffd14d2b0e388c3e", - "sha256:49c2846dcc4803476e839d8bd4db8845e928f19130e0ea86121f2d1f43d2b452", - "sha256:4abfc1892380abe6cef381eab86f9350cbd703bfe5d834095aa66fd91c886b6d", - "sha256:4f285f8ef3de422717a36bd372239ae778b8cc112ce780ca3c7fe266dadc49fb", - "sha256:503ef1351c62fb1d6747eaf74932b609d8fdd4345b3591ef910adef8fa9969d0", - "sha256:5ef30c2dbc63c1e0a462423ca4f95001814d26ef4fe66208e53fcf220ea3b717", - "sha256:6037f123905dc0141f7c8383ca616ef0195e79cd3b4d82faaee789d4045e891b", - "sha256:72d15de4c4b6a764a76c4ae69d99c35f7a0751223688c3f7e62dfa95eb4f61be", - "sha256:7b24fbab9e7598518ce4549e066df00aab79c2bf9bedcdde23fb5ef6a3cf532f", - "sha256:7baa210c20f71a242d9ae0e02734628f6948e8bee3bf538647894af427d28800", - "sha256:7d7e6e8d62967b3f037f952620cb7381cc39a4bd31790c75fcfba56cc975d70b", - "sha256:7f4624ef2e76a3a5313c4e61a81be38bcc16b59a68a85d30758b84cd2102b161", - "sha256:8742122782953d2fd038f0a199f047a24e941cc9718b1aac90876dbdb7167739", - "sha256:8e4531267736d88fde1022b36dd42ed8163e3575bcbd12bfed96662872aa93fe", - "sha256:8e4c5a48f7b2e8798ce381498ee7b9a83c65b87ae66ee5022387394e5eb51771", - "sha256:9acf443dcf6f68fbea3b7fb519e1716e014db1a561939f5aecc4abda74e4015d", - "sha256:a0b7049814442f918b522d66b1d015286afbeb9e6d141af54bbfafe31710a3c8", - "sha256:a3ce0b98fb581c471424d2cda45120f57658ed97677c6fec4d6decf5d7c1b976", - "sha256:b80585e06c4f0082327eb5c9ad96fbdb2b0e7c14971ea5099fe78c22f4608451", - "sha256:b82ca472db9c914c44e39a41e9e8bd3ed724523dd7aff5ce37592b8d16920ed9", - "sha256:c4128c01cd6f5ea8f7c2db405dbfd8582cd967d36e6fa0952565436633b0e591", - "sha256:d512de051342a576bb89777476d13c5266d9334cf4badb6468aed9dc8f5bdec1", - "sha256:df079479fb1b9e488334312e35ebbf30cbf5ecad6c56599f1a961800b33ab7c1", - "sha256:e11c2c2aee53f340992e8e4d6a59172cbbbd0193f1351de98c4f810a5041d5ca", - "sha256:e3d0e5188ff8dbaddac2ee44731d36f09c4eccd3eac7328e547862c44f75cacd", - "sha256:e543f457935ba7b763b121f1bf893974393b4d30065042f947f85a8d81081b80", - "sha256:e5c7292dd899ad8fa09a2be96719648cee37b17909fe8c12007e3bff58ebee61", - "sha256:f39d8e8806b8857fb473ca6a9c7bd800b0673dfdb7283ff569af0345a222f32c", - "sha256:f6787d07fdab31a32c433c1ba34883dea6559d8a3fbe08fb93d834ca34136b71" + "sha256:02d78c034109f46032c7217260066d49d41e6bcaf588fa28fa40fe2f83445347", + "sha256:0cf5fc0a1c23f8ea34b408b72fb0e90eec0f404ad4dba98e8f6da3c9ce34e2ed", + "sha256:1c0e8a1a32973a5d59fbcc19232f925e5c48116e9411f788033a31c5ca5130b4", + "sha256:1f9e917a9f18087f6c14b4d4508fb94fca5c2f96852363a89232fb9b2124ac1f", + "sha256:26e69d08a515554e0cfe1ec4d31568836f4b17f0ff82294f957f629388629eb9", + "sha256:2b417c97936d94874a3ce7ed8deab910f2233e3612134507cfee4af8735c38a6", + "sha256:2db25f15ed44327f2e02d0c4fe741ac966f9500e407047d8a7c7fccf2df65616", + "sha256:2f16130d869ce27ecd623194547b649dd657333ec7e8644cc571c645781a9b85", + "sha256:34b36217b17b5bea674a414229913e1fd80ede328be51e1b531fcc62abd393b0", + "sha256:35bf0dad8a3562043345236c26d0053a856fb06c04d7da652f2ded914e508ae7", + "sha256:495e2946406963e0b9f063f76d5af0f2a19517dac2b367b5b044432ac9194296", + "sha256:4a7ad7f328e28fc97c356d0f10fb10d8b5151bb65aa7cf14bf8084513f0b7306", + "sha256:4fb8a8468031f858381a576078924af364a08833d8f8f3237018252c4573a802", + "sha256:5bc3e6d338aefb052e19cedabe00452be46d0c10a4ed29ee77abb00402e438fe", + "sha256:6fa52972c9647876ea35f6dc2b51002a74ed900ec7894586cbb2fe76f64f99de", + "sha256:76c0eea89d7542719594e50e2283f51a072978b953e8b3e9fd7c59a2c762d4c1", + "sha256:784574709b9690dc28696617ea69352e2132352fdfc9bc89afa8e39f99ae538e", + "sha256:7b46fc6aa8eb7edd18cafcd21fd98703cb6c09e46b507de335fca7f0161dfccb", + "sha256:81ec4dbb696e095057b2528d11a8da04be6bbe2b967fa07d4ea9ba6354338cbf", + "sha256:850cbda0ec5d24c39e7215ede410276040692ca45d105fbbeada407fa03f0ac0", + "sha256:85ac4e62eb44428cde025fd9ab7554002315fc7880f791c553fc5a0015cc9931", + "sha256:8a42dc220eb5305f470855c9284f4c8e85ae59d6d742cd07946b0cbe5e9ca186", + "sha256:9053c2f655589545be08b9d6a673e92970173a4bf11a4b9f18cd6e9af626b587", + "sha256:90d10d9038ba46a595a223a34f136c9230e3d6d7abc2433dbf0e1c31939d3a8b", + "sha256:9867f2817b1a0c93c523f89ac6c9d8625548af4620a7ce438bf5a76e23327284", + "sha256:9a3d60fb8d46ede26c1907c146561b3a9caa20a7aff961bc661ef8226f85a2e9", + "sha256:9f2aefa8a37bd2c4db1a3f1aca11377e2766214520fb70e67071f4ff8d8b0fa5", + "sha256:a0256f8786ac9e4db618a1aa492bb3472569a0946fd3ee862ffe23196323da55", + "sha256:aac98ecad8f7bd4301855669d42a5d97ef7bb34bec2b1e74c7a0641d47e313cf", + "sha256:c026bdf5c1366ce88b7bbe2d8207374d675afd3fd911f60752103de3da4a41d2", + "sha256:c39a3656576b6fdaaf28abe0467f7a7231df4230c1bee132322dbc3209419e7f", + "sha256:cdd020cb68b51462983b7c2dfbc3eb6ede032b8bf438d4554df0c3f08ce35c76", + "sha256:d2a134756f4db34759a5cc7f7e43f7eb87540b68d1cca62925593c6fb93924f7", + "sha256:dbde4004a0688400036342ff73e3706e8940483e2871547b1354d59e93a38277", + "sha256:dc771d4db5701f280957bbcee91745e0686d00ed1c6aa7e05ba30a58b02d70a1", + "sha256:dfb6f6120587b8e228a3cae5ee4985b5bdc18501bad05c49df61965dfc9d70a9", + "sha256:e868cd6feb3ef07d4b35be104fe1fd0657db05259ff8f8ec5e08f4f89ca1191d", + "sha256:ec9aab2fb6783c7fc54bc28f58eb75f1ca77594e6b0fd5e5e7a8114a95169fe0", + "sha256:ed85a0291fff45b67f2557fe7f117d3bc7af8b54b8619d27bf374b5c8b7e3ca2", + "sha256:f3ac06703c412f8167a9062eaf6099409967e33bf98fa5b02be4b4689b6bdf39", + "sha256:f3da5240211252fc70a6451fe00c143e2ab2f7bfc2445695ad2ed056b8e48d96", + "sha256:f54081b08419a39221cd646363b5708857c696b3ad4784f1dcf310891e33a5f7", + "sha256:f64f8ab22d27d4a5693310748d35a696061c3b5c7b8c4fb4ab3b4bc1068b6b56", + "sha256:f717cce5093e6b6049d9ea6d12fdf3658efdb1a80772f7737db1f8510b876df6", + "sha256:fb81ff861692111fa81bd85f64584e624cb4013bd66fbce8a209b8893f5ce398" ], "index": "pypi", - "version": "==1.54.2" + "markers": "python_version >= '3.7'", + "version": "==1.57.0" }, "hdwallets": { "hashes": [ @@ -884,6 +873,7 @@ "sha256:c85d08b59c3fd3bc5b29398583d7d7dc46f95456f69ff15a3ab0353084ee7529" ], "index": "pypi", + "markers": "python_version >= '3.6'", "version": "==0.1.2" }, "hexbytes": { @@ -908,6 +898,7 @@ "sha256:acd2168872d0379e7a10873bb3e12bf6c91b35de758135c4fbd1015ef18fafc5" ], "index": "pypi", + "markers": "python_version >= '3.5'", "version": "==0.20" }, "multidict": { @@ -998,22 +989,23 @@ }, "protobuf": { "hashes": [ - "sha256:0149053336a466e3e0b040e54d0b615fc71de86da66791c592cc3c8d18150bf8", - "sha256:08fe19d267608d438aa37019236db02b306e33f6b9902c3163838b8e75970223", - "sha256:29660574cd769f2324a57fb78127cda59327eb6664381ecfe1c69731b83e8288", - "sha256:2991f5e7690dab569f8f81702e6700e7364cc3b5e572725098215d3da5ccc6ac", - "sha256:3b01a5274ac920feb75d0b372d901524f7e3ad39c63b1a2d55043f3887afe0c1", - "sha256:3bcbeb2bf4bb61fe960dd6e005801a23a43578200ea8ceb726d1f6bd0e562ba1", - "sha256:447b9786ac8e50ae72cae7a2eec5c5df6a9dbf9aa6f908f1b8bda6032644ea62", - "sha256:514b6bbd54a41ca50c86dd5ad6488afe9505901b3557c5e0f7823a0cf67106fb", - "sha256:5cb9e41188737f321f4fce9a4337bf40a5414b8d03227e1d9fbc59bc3a216e35", - "sha256:7a92beb30600332a52cdadbedb40d33fd7c8a0d7f549c440347bc606fb3fe34b", - "sha256:84ea0bd90c2fdd70ddd9f3d3fc0197cc24ecec1345856c2b5ba70e4d99815359", - "sha256:aca6e86a08c5c5962f55eac9b5bd6fce6ed98645d77e8bfc2b952ecd4a8e4f6a", - "sha256:cc14358a8742c4e06b1bfe4be1afbdf5c9f6bd094dff3e14edb78a1513893ff5" + "sha256:237b9a50bd3b7307d0d834c1b0eb1a6cd47d3f4c2da840802cd03ea288ae8880", + "sha256:25ae91d21e3ce8d874211110c2f7edd6384816fb44e06b2867afe35139e1fd1c", + "sha256:2b23bd6e06445699b12f525f3e92a916f2dcf45ffba441026357dea7fa46f42b", + "sha256:3b7b170d3491ceed33f723bbf2d5a260f8a4e23843799a3906f16ef736ef251e", + "sha256:4e69965e7e54de4db989289a9b971a099e626f6167a9351e9d112221fc691bc1", + "sha256:58e12d2c1aa428ece2281cef09bbaa6938b083bcda606db3da4e02e991a0d924", + "sha256:6bd26c1fa9038b26c5c044ee77e0ecb18463e957fefbaeb81a3feb419313a54e", + "sha256:77700b55ba41144fc64828e02afb41901b42497b8217b558e4a001f18a85f2e3", + "sha256:7fda70797ddec31ddfa3576cbdcc3ddbb6b3078b737a1a87ab9136af0570cd6e", + "sha256:839952e759fc40b5d46be319a265cf94920174d88de31657d5622b5d8d6be5cd", + "sha256:bb7aa97c252279da65584af0456f802bd4b2de429eb945bbc9b3d61a42a8cd16", + "sha256:c00c3c7eb9ad3833806e21e86dca448f46035242a680f81c3fe068ff65e79c74", + "sha256:c5cdd486af081bf752225b26809d2d0a85e575b80a84cde5172a05bbb1990099" ], "index": "pypi", - "version": "==4.23.3" + "markers": "python_version >= '3.7'", + "version": "==4.24.2" }, "pycparser": { "hashes": [ @@ -1069,97 +1061,97 @@ }, "regex": { "hashes": [ - "sha256:0385e73da22363778ef2324950e08b689abdf0b108a7d8decb403ad7f5191938", - "sha256:051da80e6eeb6e239e394ae60704d2b566aa6a7aed6f2890a7967307267a5dc6", - "sha256:05ed27acdf4465c95826962528f9e8d41dbf9b1aa8531a387dee6ed215a3e9ef", - "sha256:0654bca0cdf28a5956c83839162692725159f4cda8d63e0911a2c0dc76166525", - "sha256:09e4a1a6acc39294a36b7338819b10baceb227f7f7dbbea0506d419b5a1dd8af", - "sha256:0b49c764f88a79160fa64f9a7b425620e87c9f46095ef9c9920542ab2495c8bc", - "sha256:0b71e63226e393b534105fcbdd8740410dc6b0854c2bfa39bbda6b0d40e59a54", - "sha256:0c29ca1bd61b16b67be247be87390ef1d1ef702800f91fbd1991f5c4421ebae8", - "sha256:10590510780b7541969287512d1b43f19f965c2ece6c9b1c00fc367b29d8dce7", - "sha256:10cb847aeb1728412c666ab2e2000ba6f174f25b2bdc7292e7dd71b16db07568", - "sha256:12b74fbbf6cbbf9dbce20eb9b5879469e97aeeaa874145517563cca4029db65c", - "sha256:20326216cc2afe69b6e98528160b225d72f85ab080cbdf0b11528cbbaba2248f", - "sha256:2239d95d8e243658b8dbb36b12bd10c33ad6e6933a54d36ff053713f129aa536", - "sha256:25be746a8ec7bc7b082783216de8e9473803706723b3f6bef34b3d0ed03d57e2", - "sha256:271f0bdba3c70b58e6f500b205d10a36fb4b58bd06ac61381b68de66442efddb", - "sha256:29cdd471ebf9e0f2fb3cac165efedc3c58db841d83a518b082077e612d3ee5df", - "sha256:2d44dc13229905ae96dd2ae2dd7cebf824ee92bc52e8cf03dcead37d926da019", - "sha256:3676f1dd082be28b1266c93f618ee07741b704ab7b68501a173ce7d8d0d0ca18", - "sha256:36efeba71c6539d23c4643be88295ce8c82c88bbd7c65e8a24081d2ca123da3f", - "sha256:3e5219bf9e75993d73ab3d25985c857c77e614525fac9ae02b1bebd92f7cecac", - "sha256:43e1dd9d12df9004246bacb79a0e5886b3b6071b32e41f83b0acbf293f820ee8", - "sha256:457b6cce21bee41ac292d6753d5e94dcbc5c9e3e3a834da285b0bde7aa4a11e9", - "sha256:463b6a3ceb5ca952e66550a4532cef94c9a0c80dc156c4cc343041951aec1697", - "sha256:4959e8bcbfda5146477d21c3a8ad81b185cd252f3d0d6e4724a5ef11c012fb06", - "sha256:4d3850beab9f527f06ccc94b446c864059c57651b3f911fddb8d9d3ec1d1b25d", - "sha256:5708089ed5b40a7b2dc561e0c8baa9535b77771b64a8330b684823cfd5116036", - "sha256:5c6b48d0fa50d8f4df3daf451be7f9689c2bde1a52b1225c5926e3f54b6a9ed1", - "sha256:61474f0b41fe1a80e8dfa70f70ea1e047387b7cd01c85ec88fa44f5d7561d787", - "sha256:6343c6928282c1f6a9db41f5fd551662310e8774c0e5ebccb767002fcf663ca9", - "sha256:65ba8603753cec91c71de423a943ba506363b0e5c3fdb913ef8f9caa14b2c7e0", - "sha256:687ea9d78a4b1cf82f8479cab23678aff723108df3edeac098e5b2498879f4a7", - "sha256:6b2675068c8b56f6bfd5a2bda55b8accbb96c02fd563704732fd1c95e2083461", - "sha256:7117d10690c38a622e54c432dfbbd3cbd92f09401d622902c32f6d377e2300ee", - "sha256:7178bbc1b2ec40eaca599d13c092079bf529679bf0371c602edaa555e10b41c3", - "sha256:72d1a25bf36d2050ceb35b517afe13864865268dfb45910e2e17a84be6cbfeb0", - "sha256:742e19a90d9bb2f4a6cf2862b8b06dea5e09b96c9f2df1779e53432d7275331f", - "sha256:74390d18c75054947e4194019077e243c06fbb62e541d8817a0fa822ea310c14", - "sha256:74419d2b50ecb98360cfaa2974da8689cb3b45b9deff0dcf489c0d333bcc1477", - "sha256:824bf3ac11001849aec3fa1d69abcb67aac3e150a933963fb12bda5151fe1bfd", - "sha256:83320a09188e0e6c39088355d423aa9d056ad57a0b6c6381b300ec1a04ec3d16", - "sha256:837328d14cde912af625d5f303ec29f7e28cdab588674897baafaf505341f2fc", - "sha256:841d6e0e5663d4c7b4c8099c9997be748677d46cbf43f9f471150e560791f7ff", - "sha256:87b2a5bb5e78ee0ad1de71c664d6eb536dc3947a46a69182a90f4410f5e3f7dd", - "sha256:890e5a11c97cf0d0c550eb661b937a1e45431ffa79803b942a057c4fb12a2da2", - "sha256:8abbc5d54ea0ee80e37fef009e3cec5dafd722ed3c829126253d3e22f3846f1e", - "sha256:8e3f1316c2293e5469f8f09dc2d76efb6c3982d3da91ba95061a7e69489a14ef", - "sha256:8f56fcb7ff7bf7404becdfc60b1e81a6d0561807051fd2f1860b0d0348156a07", - "sha256:9427a399501818a7564f8c90eced1e9e20709ece36be701f394ada99890ea4b3", - "sha256:976d7a304b59ede34ca2921305b57356694f9e6879db323fd90a80f865d355a3", - "sha256:9a5bfb3004f2144a084a16ce19ca56b8ac46e6fd0651f54269fc9e230edb5e4a", - "sha256:9beb322958aaca059f34975b0df135181f2e5d7a13b84d3e0e45434749cb20f7", - "sha256:9edcbad1f8a407e450fbac88d89e04e0b99a08473f666a3f3de0fd292badb6aa", - "sha256:9edce5281f965cf135e19840f4d93d55b3835122aa76ccacfd389e880ba4cf82", - "sha256:a4c3b7fa4cdaa69268748665a1a6ff70c014d39bb69c50fda64b396c9116cf77", - "sha256:a8105e9af3b029f243ab11ad47c19b566482c150c754e4c717900a798806b222", - "sha256:a99b50300df5add73d307cf66abea093304a07eb017bce94f01e795090dea87c", - "sha256:aad51907d74fc183033ad796dd4c2e080d1adcc4fd3c0fd4fd499f30c03011cd", - "sha256:af4dd387354dc83a3bff67127a124c21116feb0d2ef536805c454721c5d7993d", - "sha256:b28f5024a3a041009eb4c333863d7894d191215b39576535c6734cd88b0fcb68", - "sha256:b4598b1897837067a57b08147a68ac026c1e73b31ef6e36deeeb1fa60b2933c9", - "sha256:b6192d5af2ccd2a38877bfef086d35e6659566a335b1492786ff254c168b1693", - "sha256:b862c2b9d5ae38a68b92e215b93f98d4c5e9454fa36aae4450f61dd33ff48487", - "sha256:b956231ebdc45f5b7a2e1f90f66a12be9610ce775fe1b1d50414aac1e9206c06", - "sha256:bb60b503ec8a6e4e3e03a681072fa3a5adcbfa5479fa2d898ae2b4a8e24c4591", - "sha256:bbb02fd4462f37060122e5acacec78e49c0fbb303c30dd49c7f493cf21fc5b27", - "sha256:bdff5eab10e59cf26bc479f565e25ed71a7d041d1ded04ccf9aee1d9f208487a", - "sha256:c123f662be8ec5ab4ea72ea300359023a5d1df095b7ead76fedcd8babbedf969", - "sha256:c2b867c17a7a7ae44c43ebbeb1b5ff406b3e8d5b3e14662683e5e66e6cc868d3", - "sha256:c5f8037000eb21e4823aa485149f2299eb589f8d1fe4b448036d230c3f4e68e0", - "sha256:c6a57b742133830eec44d9b2290daf5cbe0a2f1d6acee1b3c7b1c7b2f3606df7", - "sha256:ccf91346b7bd20c790310c4147eee6ed495a54ddb6737162a36ce9dbef3e4751", - "sha256:cf67ca618b4fd34aee78740bea954d7c69fdda419eb208c2c0c7060bb822d747", - "sha256:d2da3abc88711bce7557412310dfa50327d5769a31d1c894b58eb256459dc289", - "sha256:d4f03bb71d482f979bda92e1427f3ec9b220e62a7dd337af0aa6b47bf4498f72", - "sha256:d54af539295392611e7efbe94e827311eb8b29668e2b3f4cadcfe6f46df9c777", - "sha256:d77f09bc4b55d4bf7cc5eba785d87001d6757b7c9eec237fe2af57aba1a071d9", - "sha256:d831c2f8ff278179705ca59f7e8524069c1a989e716a1874d6d1aab6119d91d1", - "sha256:dbbbfce33cd98f97f6bffb17801b0576e653f4fdb1d399b2ea89638bc8d08ae1", - "sha256:dcba6dae7de533c876255317c11f3abe4907ba7d9aa15d13e3d9710d4315ec0e", - "sha256:e0bb18053dfcfed432cc3ac632b5e5e5c5b7e55fb3f8090e867bfd9b054dbcbf", - "sha256:e2fbd6236aae3b7f9d514312cdb58e6494ee1c76a9948adde6eba33eb1c4264f", - "sha256:e5087a3c59eef624a4591ef9eaa6e9a8d8a94c779dade95d27c0bc24650261cd", - "sha256:e8915cc96abeb8983cea1df3c939e3c6e1ac778340c17732eb63bb96247b91d2", - "sha256:ea353ecb6ab5f7e7d2f4372b1e779796ebd7b37352d290096978fea83c4dba0c", - "sha256:ee2d1a9a253b1729bb2de27d41f696ae893507c7db224436abe83ee25356f5c1", - "sha256:f415f802fbcafed5dcc694c13b1292f07fe0befdb94aa8a52905bd115ff41e88", - "sha256:fb5ec16523dc573a4b277663a2b5a364e2099902d3944c9419a40ebd56a118f9", - "sha256:fea75c3710d4f31389eed3c02f62d0b66a9da282521075061ce875eb5300cf23" + "sha256:0085da0f6c6393428bf0d9c08d8b1874d805bb55e17cb1dfa5ddb7cfb11140bf", + "sha256:06c57e14ac723b04458df5956cfb7e2d9caa6e9d353c0b4c7d5d54fcb1325c46", + "sha256:09b7f4c66aa9d1522b06e31a54f15581c37286237208df1345108fcf4e050c18", + "sha256:0c59122ceccb905a941fb23b087b8eafc5290bf983ebcb14d2301febcbe199c7", + "sha256:1005c60ed7037be0d9dea1f9c53cc42f836188227366370867222bda4c3c6bd7", + "sha256:14898830f0a0eb67cae2bbbc787c1a7d6e34ecc06fbd39d3af5fe29a4468e2c9", + "sha256:14dc6f2d88192a67d708341f3085df6a4f5a0c7b03dec08d763ca2cd86e9f559", + "sha256:1e7d84d64c84ad97bf06f3c8cb5e48941f135ace28f450d86af6b6512f1c9a71", + "sha256:2162ae2eb8b079622176a81b65d486ba50b888271302190870b8cc488587d280", + "sha256:22283c769a7b01c8ac355d5be0715bf6929b6267619505e289f792b01304d898", + "sha256:239c3c2a339d3b3ddd51c2daef10874410917cd2b998f043c13e2084cb191684", + "sha256:293352710172239bf579c90a9864d0df57340b6fd21272345222fb6371bf82b3", + "sha256:2ae54a338191e1356253e7883d9d19f8679b6143703086245fb14d1f20196be9", + "sha256:2e73e5243af12d9cd6a9d6a45a43570dbe2e5b1cdfc862f5ae2b031e44dd95a8", + "sha256:2e9216e0d2cdce7dbc9be48cb3eacb962740a09b011a116fd7af8c832ab116ca", + "sha256:3026cbcf11d79095a32d9a13bbc572a458727bd5b1ca332df4a79faecd45281c", + "sha256:3611576aff55918af2697410ff0293d6071b7e00f4b09e005d614686ac4cd57c", + "sha256:3ae646c35cb9f820491760ac62c25b6d6b496757fda2d51be429e0e7b67ae0ab", + "sha256:3b8e6ea6be6d64104d8e9afc34c151926f8182f84e7ac290a93925c0db004bfd", + "sha256:3d370ff652323c5307d9c8e4c62efd1956fb08051b0e9210212bc51168b4ff56", + "sha256:3f7454aa427b8ab9101f3787eb178057c5250478e39b99540cfc2b889c7d0586", + "sha256:40f029d73b10fac448c73d6eb33d57b34607f40116e9f6e9f0d32e9229b147d7", + "sha256:423adfa872b4908843ac3e7a30f957f5d5282944b81ca0a3b8a7ccbbfaa06103", + "sha256:4873ef92e03a4309b3ccd8281454801b291b689f6ad45ef8c3658b6fa761d7ac", + "sha256:48c640b99213643d141550326f34f0502fedb1798adb3c9eb79650b1ecb2f177", + "sha256:4ae594c66f4a7e1ea67232a0846649a7c94c188d6c071ac0210c3e86a5f92109", + "sha256:4b694430b3f00eb02c594ff5a16db30e054c1b9589a043fe9174584c6efa8033", + "sha256:51d8ea2a3a1a8fe4f67de21b8b93757005213e8ac3917567872f2865185fa7fb", + "sha256:54de2619f5ea58474f2ac211ceea6b615af2d7e4306220d4f3fe690c91988a61", + "sha256:551ad543fa19e94943c5b2cebc54c73353ffff08228ee5f3376bd27b3d5b9800", + "sha256:5543c055d8ec7801901e1193a51570643d6a6ab8751b1f7dd9af71af467538bb", + "sha256:5cd9cd7170459b9223c5e592ac036e0704bee765706445c353d96f2890e816c8", + "sha256:5ec4b3f0aebbbe2fc0134ee30a791af522a92ad9f164858805a77442d7d18570", + "sha256:67ecd894e56a0c6108ec5ab1d8fa8418ec0cff45844a855966b875d1039a2e34", + "sha256:6ab2ed84bf0137927846b37e882745a827458689eb969028af8032b1b3dac78e", + "sha256:704f63b774218207b8ccc6c47fcef5340741e5d839d11d606f70af93ee78e4d4", + "sha256:7098c524ba9f20717a56a8d551d2ed491ea89cbf37e540759ed3b776a4f8d6eb", + "sha256:7aed90a72fc3654fba9bc4b7f851571dcc368120432ad68b226bd593f3f6c0b7", + "sha256:7ce606c14bb195b0e5108544b540e2c5faed6843367e4ab3deb5c6aa5e681208", + "sha256:7eb95fe8222932c10d4436e7a6f7c99991e3fdd9f36c949eff16a69246dee2dc", + "sha256:80b80b889cb767cc47f31d2b2f3dec2db8126fbcd0cff31b3925b4dc6609dcdb", + "sha256:82cd0a69cd28f6cc3789cc6adeb1027f79526b1ab50b1f6062bbc3a0ccb2dbc3", + "sha256:83215147121e15d5f3a45d99abeed9cf1fe16869d5c233b08c56cdf75f43a504", + "sha256:88900f521c645f784260a8d346e12a1590f79e96403971241e64c3a265c8ecdb", + "sha256:91129ff1bb0619bc1f4ad19485718cc623a2dc433dff95baadbf89405c7f6b57", + "sha256:920974009fb37b20d32afcdf0227a2e707eb83fe418713f7a8b7de038b870d0b", + "sha256:9233ac249b354c54146e392e8a451e465dd2d967fc773690811d3a8c240ac601", + "sha256:941460db8fe3bd613db52f05259c9336f5a47ccae7d7def44cc277184030a116", + "sha256:942f8b1f3b223638b02df7df79140646c03938d488fbfb771824f3d05fc083a8", + "sha256:964b16dcc10c79a4a2be9f1273fcc2684a9eedb3906439720598029a797b46e6", + "sha256:9691a549c19c22d26a4f3b948071e93517bdf86e41b81d8c6ac8a964bb71e5a6", + "sha256:96979d753b1dc3b2169003e1854dc67bfc86edf93c01e84757927f810b8c3c93", + "sha256:987b9ac04d0b38ef4f89fbc035e84a7efad9cdd5f1e29024f9289182c8d99e09", + "sha256:988631b9d78b546e284478c2ec15c8a85960e262e247b35ca5eaf7ee22f6050a", + "sha256:9a96edd79661e93327cfeac4edec72a4046e14550a1d22aa0dd2e3ca52aec921", + "sha256:9b7408511fca48a82a119d78a77c2f5eb1b22fe88b0d2450ed0756d194fe7a9a", + "sha256:9dd6082f4e2aec9b6a0927202c85bc1b09dcab113f97265127c1dc20e2e32495", + "sha256:a2ad5add903eb7cdde2b7c64aaca405f3957ab34f16594d2b78d53b8b1a6a7d6", + "sha256:a8c65c17aed7e15a0c824cdc63a6b104dfc530f6fa8cb6ac51c437af52b481c7", + "sha256:aadf28046e77a72f30dcc1ab185639e8de7f4104b8cb5c6dfa5d8ed860e57236", + "sha256:b076da1ed19dc37788f6a934c60adf97bd02c7eea461b73730513921a85d4235", + "sha256:b2aeab3895d778155054abea5238d0eb9a72e9242bd4b43f42fd911ef9a13470", + "sha256:b82edc98d107cbc7357da7a5a695901b47d6eb0420e587256ba3ad24b80b7d0b", + "sha256:b8a0ccc8f2698f120e9e5742f4b38dc944c38744d4bdfc427616f3a163dd9de5", + "sha256:b993b6f524d1e274a5062488a43e3f9f8764ee9745ccd8e8193df743dbe5ee61", + "sha256:bb34d1605f96a245fc39790a117ac1bac8de84ab7691637b26ab2c5efb8f228c", + "sha256:bd3366aceedf274f765a3a4bc95d6cd97b130d1dda524d8f25225d14123c01db", + "sha256:c12f6f67495ea05c3d542d119d270007090bad5b843f642d418eb601ec0fa7be", + "sha256:c662a4cbdd6280ee56f841f14620787215a171c4e2d1744c9528bed8f5816c96", + "sha256:c884d1a59e69e03b93cf0dfee8794c63d7de0ee8f7ffb76e5f75be8131b6400a", + "sha256:ca339088839582d01654e6f83a637a4b8194d0960477b9769d2ff2cfa0fa36d2", + "sha256:cd2b6c5dfe0929b6c23dde9624483380b170b6e34ed79054ad131b20203a1a63", + "sha256:ce0f9fbe7d295f9922c0424a3637b88c6c472b75eafeaff6f910494a1fa719ef", + "sha256:cf0633e4a1b667bfe0bb10b5e53fe0d5f34a6243ea2530eb342491f1adf4f739", + "sha256:cf9273e96f3ee2ac89ffcb17627a78f78e7516b08f94dc435844ae72576a276e", + "sha256:d909b5a3fff619dc7e48b6b1bedc2f30ec43033ba7af32f936c10839e81b9217", + "sha256:d9b6627408021452dcd0d2cdf8da0534e19d93d070bfa8b6b4176f99711e7f90", + "sha256:de35342190deb7b866ad6ba5cbcccb2d22c0487ee0cbb251efef0843d705f0d4", + "sha256:e51c80c168074faa793685656c38eb7a06cbad7774c8cbc3ea05552d615393d8", + "sha256:e6bd1e9b95bc5614a7a9c9c44fde9539cba1c823b43a9f7bc11266446dd568e3", + "sha256:e7a9aaa5a1267125eef22cef3b63484c3241aaec6f48949b366d26c7250e0357", + "sha256:e951d1a8e9963ea51efd7f150450803e3b95db5939f994ad3d5edac2b6f6e2b4", + "sha256:e9941a4ada58f6218694f382e43fdd256e97615db9da135e77359da257a7168b", + "sha256:f0640913d2c1044d97e30d7c41728195fc37e54d190c5385eacb52115127b882", + "sha256:f0ccf3e01afeb412a1a9993049cb160d0352dba635bbca7762b2dc722aa5742a", + "sha256:f2181c20ef18747d5f4a7ea513e09ea03bdd50884a11ce46066bb90fe4213675", + "sha256:f2200e00b62568cfd920127782c61bc1c546062a879cdc741cfcc6976668dfcf", + "sha256:fcbdc5f2b0f1cd0f6a56cdb46fe41d2cce1e644e3b68832f3eeebc5fb0f7712e" ], "markers": "python_version >= '3.6'", - "version": "==2023.6.3" + "version": "==2023.8.8" }, "requests": { "hashes": [ @@ -1167,6 +1159,7 @@ "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==2.31.0" }, "rlp": { @@ -1185,11 +1178,11 @@ }, "setuptools": { "hashes": [ - "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f", - "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102" + "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d", + "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b" ], - "markers": "python_version >= '3.7'", - "version": "==67.8.0" + "markers": "python_version >= '3.8'", + "version": "==68.1.2" }, "six": { "hashes": [ @@ -1221,6 +1214,7 @@ "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14" ], "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==1.26.16" }, "websockets": { @@ -1297,6 +1291,7 @@ "sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==11.0.3" }, "yarl": { @@ -1383,92 +1378,92 @@ "develop": { "certifi": { "hashes": [ - "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7", - "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716" + "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", + "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" ], "markers": "python_version >= '3.6'", - "version": "==2023.5.7" + "version": "==2023.7.22" }, "charset-normalizer": { "hashes": [ - "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6", - "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1", - "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e", - "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373", - "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62", - "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230", - "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be", - "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c", - "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0", - "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448", - "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f", - "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649", - "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d", - "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0", - "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706", - "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a", - "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59", - "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23", - "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5", - "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb", - "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e", - "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e", - "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c", - "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28", - "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d", - "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41", - "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974", - "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce", - "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f", - "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1", - "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d", - "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8", - "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017", - "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31", - "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7", - "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8", - "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e", - "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14", - "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd", - "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d", - "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795", - "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b", - "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b", - "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b", - "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203", - "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f", - "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19", - "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1", - "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a", - "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac", - "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9", - "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0", - "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137", - "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f", - "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6", - "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5", - "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909", - "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f", - "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0", - "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324", - "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755", - "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb", - "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854", - "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c", - "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60", - "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84", - "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0", - "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b", - "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1", - "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531", - "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1", - "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11", - "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326", - "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df", - "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.0" + "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", + "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", + "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", + "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", + "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", + "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", + "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", + "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", + "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", + "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", + "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", + "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", + "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", + "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", + "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", + "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", + "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", + "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", + "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", + "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", + "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", + "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", + "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", + "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", + "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", + "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", + "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", + "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", + "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", + "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", + "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", + "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", + "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", + "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", + "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", + "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", + "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", + "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", + "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", + "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", + "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", + "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", + "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", + "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", + "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", + "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", + "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", + "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", + "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", + "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", + "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", + "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", + "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", + "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", + "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", + "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", + "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", + "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", + "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", + "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", + "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", + "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", + "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", + "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", + "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", + "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", + "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", + "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", + "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", + "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", + "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", + "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", + "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", + "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", + "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.2.0" }, "idna": { "hashes": [ @@ -1496,27 +1491,29 @@ }, "pluggy": { "hashes": [ - "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", - "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" + "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", + "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" ], - "markers": "python_version >= '3.6'", - "version": "==1.0.0" + "markers": "python_version >= '3.8'", + "version": "==1.3.0" }, "pytest": { "hashes": [ - "sha256:cdcbd012c9312258922f8cd3f1b62a6580fdced17db6014896053d47cddf9295", - "sha256:ee990a3cc55ba808b80795a79944756f315c67c12b56abd3ac993a7b8c17030b" + "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32", + "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a" ], "index": "pypi", - "version": "==7.3.2" + "markers": "python_version >= '3.7'", + "version": "==7.4.0" }, "pytest-asyncio": { "hashes": [ - "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b", - "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c" + "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d", + "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b" ], "index": "pypi", - "version": "==0.21.0" + "markers": "python_version >= '3.7'", + "version": "==0.21.1" }, "pytest-grpc": { "hashes": [ @@ -1532,6 +1529,7 @@ "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==2.31.0" }, "requests-mock": { @@ -1556,6 +1554,7 @@ "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14" ], "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==1.26.16" } } diff --git a/README.md b/README.md index bf1386f9..6012f659 100644 --- a/README.md +++ b/README.md @@ -92,8 +92,10 @@ make tests * The Composer can still be instantiated without markets and tokens. When markets and tokens are not provided the Composer loads the required information from the Denoms used in previous versions * Change in AsyncClient to be able to create Composer instances for the client network, markets and tokens * Examples have been adapted to create Composer instances using the AsyncClient -* Added new nodes (bare-metal load balancing nodes) for mainnet +* Added new nodes (bare-metal load balancing nodes) for mainnet and testnet +* Deprecated the kubernetes load balanced nodes for testnet * Refactored the cookies management logic into a cookie assistant. Added the required logic to support the new cookies format for bare-metal load balanced nodes +* Removed class Client. The only supported now is the async version called AsyncClient. **0.7.1.1** * Fixed Testnet network URLs diff --git a/pyinjective/__init__.py b/pyinjective/__init__.py index e17ef7b1..841ee3e8 100644 --- a/pyinjective/__init__.py +++ b/pyinjective/__init__.py @@ -1,3 +1,3 @@ -from .client import Client +from .async_client import AsyncClient from .transaction import Transaction from .wallet import PrivateKey, PublicKey, Address diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index 5f31e2e0..f1ecb8f6 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -945,7 +945,12 @@ async def _initialize_tokens_and_markets(self): markets_info = (await self.get_spot_markets()).markets for market_info in markets_info: - base_token_symbol, quote_token_symbol = market_info.ticker.split(constant.TICKER_TOKENS_SEPARATOR) + if "/" in market_info.ticker: + base_token_symbol, quote_token_symbol = market_info.ticker.split(constant.TICKER_TOKENS_SEPARATOR) + else: + base_token_symbol = market_info.base_token_meta.symbol + quote_token_symbol = market_info.quote_token_meta.symbol + base_token = self._token_representation( symbol=base_token_symbol, token_meta=market_info.base_token_meta, diff --git a/pyinjective/client.py b/pyinjective/client.py deleted file mode 100644 index bb9baf7d..00000000 --- a/pyinjective/client.py +++ /dev/null @@ -1,692 +0,0 @@ -import os -import time -import grpc -import datetime -import threading -from http.cookies import SimpleCookie -from typing import List, Optional, Tuple, Union - -from .exceptions import NotFoundError - -from .proto.cosmos.base.abci.v1beta1 import abci_pb2 as abci_type - -from .proto.cosmos.base.tendermint.v1beta1 import ( - query_pb2_grpc as tendermint_query_grpc, - query_pb2 as tendermint_query, -) -from .proto.cosmos.auth.v1beta1 import ( - query_pb2_grpc as auth_query_grpc, - query_pb2 as auth_query, - auth_pb2 as auth_type, -) -from .proto.cosmos.authz.v1beta1 import ( - query_pb2_grpc as authz_query_grpc, - query_pb2 as authz_query, - authz_pb2 as authz_type, -) -from .proto.cosmos.tx.v1beta1 import ( - service_pb2_grpc as tx_service_grpc, - service_pb2 as tx_service, -) -from .proto.exchange import ( - injective_accounts_rpc_pb2 as exchange_accounts_rpc_pb, - injective_accounts_rpc_pb2_grpc as exchange_accounts_rpc_grpc, - injective_oracle_rpc_pb2 as oracle_rpc_pb, - injective_oracle_rpc_pb2_grpc as oracle_rpc_grpc, - injective_insurance_rpc_pb2 as insurance_rpc_pb, - injective_insurance_rpc_pb2_grpc as insurance_rpc_grpc, - injective_spot_exchange_rpc_pb2 as spot_exchange_rpc_pb, - injective_spot_exchange_rpc_pb2_grpc as spot_exchange_rpc_grpc, - injective_derivative_exchange_rpc_pb2 as derivative_exchange_rpc_pb, - injective_derivative_exchange_rpc_pb2_grpc as derivative_exchange_rpc_grpc, - injective_meta_rpc_pb2 as exchange_meta_rpc_pb, - injective_meta_rpc_pb2_grpc as exchange_meta_rpc_grpc, - injective_explorer_rpc_pb2 as explorer_rpc_pb, - injective_explorer_rpc_pb2_grpc as explorer_rpc_grpc, - injective_auction_rpc_pb2 as auction_rpc_pb, - injective_auction_rpc_pb2_grpc as auction_rpc_grpc, -) - -from .core.network import Network - -DEFAULT_TIMEOUTHEIGHT_SYNC_INTERVAL = 10 # seconds -DEFAULT_TIMEOUTHEIGHT = 20 # blocks -DEFAULT_SESSION_RENEWAL_OFFSET = 120 # seconds -DEFAULT_BLOCK_TIME = 3 # seconds - -class Client: - def __init__( - self, - network: Network, - insecure: bool = False, - credentials = grpc.ssl_channel_credentials() - ): - - # chain stubs - self.chain_channel = ( - grpc.insecure_channel(network.grpc_endpoint) - if insecure else grpc.secure_channel(network.grpc_endpoint, credentials) - ) - self.stubCosmosTendermint = tendermint_query_grpc.ServiceStub(self.chain_channel) - self.stubAuth = auth_query_grpc.QueryStub(self.chain_channel) - self.stubAuthz = authz_query_grpc.QueryStub(self.chain_channel) - self.stubTx = tx_service_grpc.ServiceStub(self.chain_channel) - self.chain_cookie = "" - self.exchange_cookie = "" - self.timeout_height = 1 - - # exchange stubs - self.exchange_channel = ( - grpc.insecure_channel(network.grpc_exchange_endpoint) - if insecure else grpc.secure_channel(network.grpc_exchange_endpoint, credentials) - ) - - self.stubMeta = exchange_meta_rpc_grpc.InjectiveMetaRPCStub(self.exchange_channel) - self.stubExchangeAccount = exchange_accounts_rpc_grpc.InjectiveAccountsRPCStub( - self.exchange_channel - ) - self.stubOracle = oracle_rpc_grpc.InjectiveOracleRPCStub(self.exchange_channel) - self.stubInsurance = insurance_rpc_grpc.InjectiveInsuranceRPCStub( - self.exchange_channel - ) - self.stubSpotExchange = spot_exchange_rpc_grpc.InjectiveSpotExchangeRPCStub( - self.exchange_channel - ) - self.stubDerivativeExchange = ( - derivative_exchange_rpc_grpc.InjectiveDerivativeExchangeRPCStub( - self.exchange_channel - ) - ) - self.stubExplorer = explorer_rpc_grpc.InjectiveExplorerRPCStub(self.exchange_channel) - self.stubAuction = auction_rpc_grpc.InjectiveAuctionRPCStub(self.exchange_channel) - - def close_exchange_channel(self): - self.exchange_channel.close() - - def close_chain_channel(self): - self.chain_channel.close() - - # timeout height update routine - self.sync_timeout_height() - - def sync_timeout_height(self): - threading.Timer(DEFAULT_TIMEOUTHEIGHT_SYNC_INTERVAL, self.sync_timeout_height).start() - block = self.get_latest_block() - self.timeout_height = block.block.header.height + DEFAULT_TIMEOUTHEIGHT - - # cookie helper methods - def get_cookie(self, type): - metadata = None - if type == "chain": - if self.chain_cookie != "": - metadata = (("cookie", self.chain_cookie),) - - # format cookie date into RFC1123 standard - cookie = SimpleCookie() - cookie.load(self.chain_cookie) - expires_at = cookie.get("grpc-cookie").get("expires") - expires_at = expires_at.replace("-"," ") - yyyy = "20{}".format(expires_at[12:14]) - expires_at = expires_at[:12] + yyyy + expires_at[14:] - - # parse expire field to unix timestamp - expire_timestamp = datetime.datetime.strptime(expires_at, "%a, %d %b %Y %H:%M:%S GMT").timestamp() - - # renew session if timestamp diff < offset - timestamp_diff = expire_timestamp - int(time.time()) - if timestamp_diff < DEFAULT_SESSION_RENEWAL_OFFSET: - # request and set new cookie - req = tendermint_query.GetLatestBlockRequest() - res, call = self.stubCosmosTendermint.GetLatestBlock.with_call(req) - self.set_cookie(call,type="chain") - time.sleep(DEFAULT_BLOCK_TIME) - metadata = (("cookie", self.chain_cookie),) - return metadata - return metadata - - if type == "exchange": - if self.exchange_cookie != "": - metadata = (("cookie", self.exchange_cookie),) - return metadata - - def set_cookie(self, call, type): - new_cookie = None - for k, v in call.initial_metadata(): - if k == "set-cookie": - new_cookie = v - - if new_cookie == None: - return - - if type == "chain": - self.chain_cookie = new_cookie - if type == "exchange": - self.exchange_cookie = new_cookie - - # default client methods - def get_latest_block(self) -> tendermint_query.GetLatestBlockResponse: - return self.stubCosmosTendermint.GetLatestBlock( - tendermint_query.GetLatestBlockRequest() - ) - - def get_account(self, address: str) -> Optional[auth_type.BaseAccount]: - try: - account_any = self.stubAuth.Account( - auth_query.QueryAccountRequest(address=address) - ).account - account = auth_type.BaseAccount() - if account_any.Is(account.DESCRIPTOR): - account_any.Unpack(account) - return account - except: - return None - - def get_request_id_by_tx_hash(self, tx_hash: bytes) -> List[int]: - tx = self.stubTx.GetTx(tx_service.GetTxRequest(hash=tx_hash)) - request_ids = [] - for tx in tx.tx_response.logs: - request_event = [ - event - for event in tx.events - if event.type == "request" or event.type == "report" - ] - if len(request_event) == 1: - attrs = request_event[0].attributes - attr_id = [attr for attr in attrs if attr.key == "id"] - if len(attr_id) == 1: - request_id = attr_id[0].value - request_ids.append(int(request_id)) - if len(request_ids) == 0: - raise NotFoundError("Request Id is not found") - return request_ids - - def simulate_tx( - self, tx_byte: bytes - ) -> Tuple[Union[abci_type.SimulationResponse, grpc.RpcError], bool]: - try: - req = tx_service.SimulateRequest(tx_bytes=tx_byte) - - metadata = self.get_cookie(type="chain") - res, call = self.stubTx.Simulate.with_call(req, metadata=metadata) - self.set_cookie(call,type="chain") - - return res, True - - except grpc.RpcError as err: - return err, False - - def send_tx_sync_mode(self, tx_byte: bytes) -> abci_type.TxResponse: - req = tx_service.BroadcastTxRequest( - tx_bytes=tx_byte, mode=tx_service.BroadcastMode.BROADCAST_MODE_SYNC - ) - metadata = self.get_cookie(type="chain") - res, call = self.stubTx.BroadcastTx.with_call(req, metadata=metadata) - self.set_cookie(call,type="chain") - - return res.tx_response - - def send_tx_async_mode(self, tx_byte: bytes) -> abci_type.TxResponse: - req = tx_service.BroadcastTxRequest( - tx_bytes=tx_byte, - mode=tx_service.BroadcastMode.BROADCAST_MODE_ASYNC - ) - metadata = self.get_cookie(type="chain") - res, call = self.stubTx.BroadcastTx.with_call(req, metadata=metadata) - self.set_cookie(call,type="chain") - - return res.tx_response - - def send_tx_block_mode(self, tx_byte: bytes) -> abci_type.TxResponse: - req = tx_service.BroadcastTxRequest( - tx_bytes=tx_byte, - mode=tx_service.BroadcastMode.BROADCAST_MODE_BLOCK - ) - metadata = self.get_cookie(type="chain") - res, call = self.stubTx.BroadcastTx.with_call(req, metadata=metadata) - self.set_cookie(call,type="chain") - - return res.tx_response - - def get_chain_id(self) -> str: - latest_block = self.get_latest_block() - return latest_block.block.header.chain_id - - def get_grants(self, granter: str, grantee: str, **kwargs): - return self.stubAuthz.Grants( - authz_query.QueryGrantsRequest( - granter=granter, - grantee=grantee, - msg_type_url=kwargs.get("msg_type_url"), - ) - ) - - # Injective Exchange client methods - - # Auction RPC - - def get_auction(self, bid_round: int): - req = auction_rpc_pb.AuctionRequest(round=bid_round) - return self.stubAuction.AuctionEndpoint(req) - - def get_auctions(self): - req = auction_rpc_pb.AuctionsRequest() - return self.stubAuction.Auctions(req) - - def stream_bids(self): - req = auction_rpc_pb.StreamBidsRequest() - return self.stubAuction.StreamBids(req) - - # Meta RPC - - def ping(self): - req = exchange_meta_rpc_pb.PingRequest() - return self.stubMeta.Ping(req) - - def version(self): - req = exchange_meta_rpc_pb.VersionRequest() - return self.stubMeta.Version(req) - - def info(self): - req = exchange_meta_rpc_pb.InfoRequest( - timestamp=int(time.time() * 1000), - ) - return self.stubMeta.Info(req) - - def stream_keepalive(self): - req = exchange_meta_rpc_pb.StreamKeepaliveRequest() - return self.stubMeta.StreamKeepalive(req) - - # Explorer RPC - - def get_tx_by_hash(self, tx_hash: str): - req = explorer_rpc_pb.GetTxByTxHashRequest(hash=tx_hash) - return self.stubExplorer.GetTxByTxHash(req) - - # AccountsRPC - - def stream_subaccount_balance(self, subaccount_id: str): - req = exchange_accounts_rpc_pb.StreamSubaccountBalanceRequest( - subaccount_id=subaccount_id - ) - return self.stubExchangeAccount.StreamSubaccountBalance(req) - - def get_subaccount_balance(self, subaccount_id: str, denom: str): - req = exchange_accounts_rpc_pb.SubaccountBalanceRequest( - subaccount_id=subaccount_id, denom=denom - ) - return self.stubExchangeAccount.SubaccountBalanceEndpoint(req) - - def get_subaccount_list(self, account_address: str): - req = exchange_accounts_rpc_pb.SubaccountsListRequest( - account_address=account_address - ) - return self.stubExchangeAccount.SubaccountsList(req) - - def get_subaccount_balances_list(self, subaccount_id: str): - req = exchange_accounts_rpc_pb.SubaccountBalancesListRequest( - subaccount_id=subaccount_id - ) - return self.stubExchangeAccount.SubaccountBalancesList(req) - - def get_subaccount_history(self, subaccount_id: str, **kwargs): - req = exchange_accounts_rpc_pb.SubaccountHistoryRequest( - subaccount_id=subaccount_id, - denom=kwargs.get("denom"), - transfer_types=kwargs.get("transfer_types"), - ) - return self.stubExchangeAccount.SubaccountHistory(req) - - def get_subaccount_order_summary(self, subaccount_id: str, **kwargs): - req = exchange_accounts_rpc_pb.SubaccountOrderSummaryRequest( - subaccount_id=subaccount_id, - order_direction=kwargs.get("order_direction"), - market_id=kwargs.get("market_id"), - ) - return self.stubExchangeAccount.SubaccountOrderSummary(req) - - def get_order_states(self, **kwargs): - req = exchange_accounts_rpc_pb.OrderStatesRequest( - spot_order_hashes=kwargs.get("spot_order_hashes"), - derivative_order_hashes=kwargs.get("derivative_order_hashes"), - ) - return self.stubExchangeAccount.OrderStates(req) - - def get_portfolio(self, account_address: str): - req = exchange_accounts_rpc_pb.PortfolioRequest(account_address=account_address) - return self.stubExchangeAccount.Portfolio(req) - - def get_rewards(self, **kwargs): - req = exchange_accounts_rpc_pb.RewardsRequest( - account_address=kwargs.get("account_address"), epoch=kwargs.get("epoch") - ) - return self.stubExchangeAccount.Rewards(req) - - # OracleRPC - - def stream_oracle_prices( - self, base_symbol: str, quote_symbol: str, oracle_type: str - ): - req = oracle_rpc_pb.StreamPricesRequest( - base_symbol=base_symbol, quote_symbol=quote_symbol, oracle_type=oracle_type - ) - return self.stubOracle.StreamPrices(req) - - def get_oracle_prices( - self, - base_symbol: str, - quote_symbol: str, - oracle_type: str, - oracle_scale_factor: int, - ): - req = oracle_rpc_pb.PriceRequest( - base_symbol=base_symbol, - quote_symbol=quote_symbol, - oracle_type=oracle_type, - oracle_scale_factor=oracle_scale_factor, - ) - return self.stubOracle.Price(req) - - def get_oracle_list(self): - req = oracle_rpc_pb.OracleListRequest() - return self.stubOracle.OracleList(req) - - # InsuranceRPC - - def get_insurance_funds(self): - req = insurance_rpc_pb.FundsRequest() - return self.stubInsurance.Funds(req) - - def get_redemptions(self, **kwargs): - req = insurance_rpc_pb.RedemptionsRequest( - redeemer=kwargs.get("redeemer"), - redemption_denom=kwargs.get("redemption_denom"), - status=kwargs.get("status"), - ) - return self.stubInsurance.Redemptions(req) - - # SpotRPC - - def get_spot_market(self, market_id: str): - req = spot_exchange_rpc_pb.MarketRequest(market_id=market_id) - return self.stubSpotExchange.Market(req) - - def get_spot_markets(self, **kwargs): - req = spot_exchange_rpc_pb.MarketsRequest( - market_status=kwargs.get("market_status"), - base_denom=kwargs.get("base_denom"), - quote_denom=kwargs.get("quote_denom"), - ) - return self.stubSpotExchange.Markets(req) - - def stream_spot_markets(self, **kwargs): - req = spot_exchange_rpc_pb.StreamMarketsRequest( - market_ids=kwargs.get("market_ids")) - metadata = self.get_cookie(type="exchange") - res = self.stubSpotExchange.StreamMarkets(req, metadata=metadata) - self.set_cookie(res,type="exchange") - return res.tx_response - - def get_spot_orderbook(self, market_id: str): - req = spot_exchange_rpc_pb.OrderbookRequest(market_id=market_id) - return self.stubSpotExchange.Orderbook(req) - - def get_spot_orderbooks(self, market_ids: List): - req = spot_exchange_rpc_pb.OrderbooksRequest(market_ids=market_ids) - return self.stubSpotExchange.Orderbooks(req) - - def get_spot_orderbook_v2(self, market_id: str): - req = spot_exchange_rpc_pb.OrderbookV2Request(market_id=market_id) - return self.stubSpotExchange.OrderbookV2(req) - - def get_spot_orderbooks_v2(self, market_ids: List): - req = spot_exchange_rpc_pb.OrderbooksV2Request(market_ids=market_ids) - return self.stubSpotExchange.OrderbooksV2(req) - - def get_spot_orders(self, market_id: str, **kwargs): - req = spot_exchange_rpc_pb.OrdersRequest( - market_id=market_id, - order_side=kwargs.get("order_side"), - subaccount_id=kwargs.get("subaccount_id"), - ) - return self.stubSpotExchange.Orders(req) - - def get_spot_trades(self, market_id: str, **kwargs): - req = spot_exchange_rpc_pb.TradesRequest( - market_id=market_id, - execution_side=kwargs.get("execution_side"), - direction=kwargs.get("direction"), - subaccount_id=kwargs.get("subaccount_id"), - skip=kwargs.get("skip"), - limit=kwargs.get("limit"), - ) - return self.stubSpotExchange.Trades(req) - - def stream_spot_orderbook(self, market_id: str): - return self.stream_spot_orderbook_snapshot(market_ids=[market_id]) - - def stream_spot_orderbook_snapshot(self, market_ids: List[str]): - req = spot_exchange_rpc_pb.StreamOrderbookSnapshotRequest(market_ids=market_ids) - metadata = self.get_cookie(type="exchange") - res = self.stubSpotExchange.StreamOrderbookSnapshot(req, metadata=metadata) - self.set_cookie(res, type="exchange") - return res - - def stream_spot_orderbook_update(self, market_ids: List[str]): - req = spot_exchange_rpc_pb.StreamOrderbookUpdateRequest(market_ids=market_ids) - metadata = self.get_cookie(type="exchange") - res = self.stubSpotExchange.StreamOrderbookUpdate(req, metadata=metadata) - self.set_cookie(res, type="exchange") - return res - - def stream_spot_orderbooks(self, market_ids: List): - req = spot_exchange_rpc_pb.StreamOrderbookRequest(market_ids=market_ids) - metadata = self.get_cookie(type="exchange") - res = self.stubSpotExchange.StreamOrderbook(req, metadata=metadata) - self.set_cookie(res,type="exchange") - return res - - def stream_spot_orders(self, market_id: str, **kwargs): - req = spot_exchange_rpc_pb.StreamOrdersRequest( - market_id=market_id, - order_side=kwargs.get("order_side"), - subaccount_id=kwargs.get("subaccount_id"), - ) - metadata = self.get_cookie(type="exchange") - res = self.stubSpotExchange.StreamOrders(req, metadata=metadata) - self.set_cookie(res,type="exchange") - return res - - def stream_spot_trades(self, **kwargs): - req = spot_exchange_rpc_pb.StreamTradesRequest( - market_id=kwargs.get("market_id"), - market_ids=kwargs.get("market_ids"), - execution_side=kwargs.get("execution_side"), - direction=kwargs.get("direction"), - subaccount_id=kwargs.get("subaccount_id"), - subaccount_ids=kwargs.get("subaccount_ids"), - skip=kwargs.get("skip"), - limit=kwargs.get("limit"), - ) - metadata = self.get_cookie(type="exchange") - res = self.stubSpotExchange.StreamTrades(req, metadata=metadata) - self.set_cookie(res,type="exchange") - return res - - def get_spot_subaccount_orders(self, subaccount_id: str, **kwargs): - req = spot_exchange_rpc_pb.SubaccountOrdersListRequest( - subaccount_id=subaccount_id, market_id=kwargs.get("market_id") - ) - return self.stubSpotExchange.SubaccountOrdersList(req) - - def get_spot_subaccount_trades(self, subaccount_id: str, **kwargs): - req = spot_exchange_rpc_pb.SubaccountTradesListRequest( - subaccount_id=subaccount_id, - market_id=kwargs.get("market_id"), - execution_type=kwargs.get("execution_type"), - direction=kwargs.get("direction"), - ) - return self.stubSpotExchange.SubaccountTradesList(req) - - # DerivativeRPC - - def get_derivative_market(self, market_id: str): - req = derivative_exchange_rpc_pb.MarketRequest(market_id=market_id) - return self.stubDerivativeExchange.Market(req) - - def get_derivative_markets(self, **kwargs): - req = derivative_exchange_rpc_pb.MarketsRequest( - market_status=kwargs.get("market_status"), - quote_denom=kwargs.get("quote_denom"), - ) - return self.stubDerivativeExchange.Markets(req) - - def stream_derivative_markets(self, **kwargs): - req = derivative_exchange_rpc_pb.StreamMarketRequest( - market_ids=kwargs.get("market_ids")) - metadata = self.get_cookie(type="exchange") - res = self.stubDerivativeExchange.StreamMarket(req, metadata=metadata) - self.set_cookie(res,type="exchange") - return res - - def get_derivative_orderbook(self, market_id: str): - req = derivative_exchange_rpc_pb.OrderbookRequest(market_id=market_id) - return self.stubDerivativeExchange.Orderbook(req) - - def get_derivative_orderbooks(self, market_ids: List): - req = derivative_exchange_rpc_pb.OrderbooksRequest(market_ids=market_ids) - return self.stubDerivativeExchange.Orderbooks(req) - - def get_derivative_orderbook_v2(self, market_id: str): - req = derivative_exchange_rpc_pb.OrderbookV2Request(market_id=market_id) - return self.stubDerivativeExchange.OrderbookV2(req) - - def get_derivative_orderbooks_v2(self, market_ids: List): - req = derivative_exchange_rpc_pb.OrderbooksV2Request(market_ids=market_ids) - return self.stubDerivativeExchange.OrderbooksV2(req) - - def get_derivative_orders(self, market_id: str, **kwargs): - req = derivative_exchange_rpc_pb.OrdersRequest( - market_id=market_id, - order_side=kwargs.get("order_side"), - subaccount_id=kwargs.get("subaccount_id"), - ) - return self.stubDerivativeExchange.Orders(req) - - def get_derivative_trades(self, market_id: str, **kwargs): - req = derivative_exchange_rpc_pb.TradesRequest( - market_id=market_id, - subaccount_id=kwargs.get("subaccount_id"), - execution_side=kwargs.get("execution_side"), - direction=kwargs.get("direction"), - skip=kwargs.get("skip"), - limit=kwargs.get("limit"), - ) - return self.stubDerivativeExchange.Trades(req) - - # deprecated: use stream_derivative_orderbook_snapshot - def stream_derivative_orderbook(self, market_id: str): - return self.stream_derivative_orderbook_snapshot(market_ids=[market_id]) - - def stream_derivative_orderbook_snapshot(self, market_ids: List[str]): - req = derivative_exchange_rpc_pb.StreamOrderbookSnapshotRequest(market_ids=market_ids) - metadata = self.get_cookie(type="exchange") - res = self.stubDerivativeExchange.StreamOrderbookSnapshot(req, metadata=metadata) - self.set_cookie(res, type="exchange") - return res - - def stream_derivative_orderbook_update(self, market_ids: List[str]): - req = derivative_exchange_rpc_pb.StreamOrderbookUpdateRequest(market_ids=market_ids) - metadata = self.get_cookie(type="exchange") - res = self.stubDerivativeExchange.StreamOrderbookUpdate(req, metadata=metadata) - self.set_cookie(res, type="exchange") - return res - - def stream_derivative_orderbooks(self, market_ids: List): - req = derivative_exchange_rpc_pb.StreamOrderbookRequest(market_ids=market_ids) - metadata = self.get_cookie(type="exchange") - res = self.stubDerivativeExchange.StreamOrderbook(req, metadata=metadata) - self.set_cookie(res,type="exchange") - return res - - def stream_derivative_orders(self, market_id: str, **kwargs): - req = derivative_exchange_rpc_pb.StreamOrdersRequest( - market_id=market_id, - order_side=kwargs.get("order_side"), - subaccount_id=kwargs.get("subaccount_id"), - ) - metadata = self.get_cookie(type="exchange") - res = self.stubDerivativeExchange.StreamOrders(req, metadata=metadata) - self.set_cookie(res,type="exchange") - return res - - def stream_derivative_trades(self, **kwargs): - req = derivative_exchange_rpc_pb.StreamTradesRequest( - market_id=kwargs.get("market_id"), - market_ids=kwargs.get("market_ids"), - subaccount_id=kwargs.get("subaccount_id"), - subaccount_ids=kwargs.get("subaccount_ids"), - execution_side=kwargs.get("execution_side"), - direction=kwargs.get("direction"), - skip=kwargs.get("skip"), - limit=kwargs.get("limit"), - ) - metadata = self.get_cookie(type="exchange") - res = self.stubDerivativeExchange.StreamTrades(req, metadata=metadata) - self.set_cookie(res,type="exchange") - return res - - def get_derivative_positions(self, market_id: str, **kwargs): - req = derivative_exchange_rpc_pb.PositionsRequest( - market_id=market_id, subaccount_id=kwargs.get("subaccount_id") - ) - return self.stubDerivativeExchange.Positions(req) - - def stream_derivative_positions(self, **kwargs): - req = derivative_exchange_rpc_pb.StreamPositionsRequest( - market_id=kwargs.get("market_id"), - market_ids=kwargs.get("market_ids"), - subaccount_id=kwargs.get("subaccount_id"), - subaccount_ids=kwargs.get("subaccount_ids") - ) - metadata = self.get_cookie(type="exchange") - res = self.stubDerivativeExchange.StreamPositions(req, metadata=metadata) - self.set_cookie(res,type="exchange") - return res - - def get_derivative_liquidable_positions(self, **kwargs): - req = derivative_exchange_rpc_pb.LiquidablePositionsRequest( - market_id=kwargs.get("market_id") - ) - return self.stubDerivativeExchange.LiquidablePositions(req) - - def get_derivative_subaccount_orders(self, subaccount_id: str, **kwargs): - req = derivative_exchange_rpc_pb.SubaccountOrdersListRequest( - subaccount_id=subaccount_id, market_id=kwargs.get("market_id") - ) - return self.stubDerivativeExchange.SubaccountOrdersList(req) - - def get_derivative_subaccount_trades(self, subaccount_id: str, **kwargs): - req = derivative_exchange_rpc_pb.SubaccountTradesListRequest( - subaccount_id=subaccount_id, - market_id=kwargs.get("market_id"), - execution_type=kwargs.get("execution_type"), - direction=kwargs.get("direction"), - ) - return self.stubDerivativeExchange.SubaccountTradesList(req) - - def get_funding_payments(self, subaccount_id: str, **kwargs): - req = derivative_exchange_rpc_pb.FundingPaymentsRequest( - subaccount_id=subaccount_id, - market_id=kwargs.get("market_id"), - skip=kwargs.get("skip"), - limit=kwargs.get("limit"), - ) - return self.stubDerivativeExchange.FundingPayments(req) - - def get_funding_rates(self, market_id: str, **kwargs): - req = derivative_exchange_rpc_pb.FundingRatesRequest( - market_id=market_id, - skip=kwargs.get("skip"), - limit=kwargs.get("limit"), - ) - return self.stubDerivativeExchange.FundingRates(req) diff --git a/pyinjective/core/network.py b/pyinjective/core/network.py index e49d48e7..ea638920 100644 --- a/pyinjective/core/network.py +++ b/pyinjective/core/network.py @@ -26,7 +26,7 @@ async def exchange_metadata(self, metadata_query_provider: Callable) -> Tuple[Tu return (("cookie", cookie),) -class MainnetKubernetesCookieAssistant(CookieAssistant): +class KubernetesLoadBalancedCookieAssistant(CookieAssistant): def __init__(self): self._chain_cookie: Optional[str] = None @@ -91,7 +91,7 @@ def _is_cookie_expired(self, cookie_data: str) -> bool: return timestamp_diff < self.SESSION_RENEWAL_OFFSET -class MainnetBareMetalCookieAssistant(CookieAssistant): +class BareMetalLoadBalancedCookieAssistant(CookieAssistant): def __init__(self): self._chain_cookie: Optional[str] = None @@ -150,7 +150,7 @@ def _is_cookie_expired(self, cookie_data: str) -> bool: return False -class TestnetCookieAssistant(CookieAssistant): +class TestnetLegacyCookieAssistant(CookieAssistant): def __init__(self): self._chain_cookie: Optional[str] = None @@ -276,17 +276,19 @@ def testnet(cls, node="lb"): raise ValueError("Must be one of {}".format(nodes)) if node == "lb": - lcd_endpoint = "https://k8s.testnet.lcd.injective.network" - tm_websocket_endpoint = "wss://k8s.testnet.tm.injective.network/websocket" - grpc_endpoint = "k8s.testnet.chain.grpc.injective.network:443" - grpc_exchange_endpoint = "k8s.testnet.exchange.grpc.injective.network:443" - grpc_explorer_endpoint = "k8s.testnet.explorer.grpc.injective.network:443" + lcd_endpoint = "https://testnet.sentry.lcd.injective.network:443" + tm_websocket_endpoint = "wss://testnet.sentry.tm.injective.network:443/websocket" + grpc_endpoint = "testnet.sentry.chain.grpc.injective.network:443" + grpc_exchange_endpoint = "testnet.sentry.exchange.grpc.injective.network:443" + grpc_explorer_endpoint = "testnet.sentry.explorer.grpc.injective.network:443" + cookie_assistant = BareMetalLoadBalancedCookieAssistant() else: lcd_endpoint = "https://testnet.lcd.injective.network" tm_websocket_endpoint = "wss://testnet.tm.injective.network/websocket" grpc_endpoint = "testnet.chain.grpc.injective.network" grpc_exchange_endpoint = "testnet.exchange.grpc.injective.network" grpc_explorer_endpoint = "testnet.explorer.grpc.injective.network" + cookie_assistant = TestnetLegacyCookieAssistant() return cls( lcd_endpoint=lcd_endpoint, @@ -297,7 +299,7 @@ def testnet(cls, node="lb"): chain_id="injective-888", fee_denom="inj", env="testnet", - cookie_assistant=TestnetCookieAssistant() + cookie_assistant=cookie_assistant ) @classmethod @@ -318,14 +320,14 @@ def mainnet(cls, node="lb"): grpc_endpoint = "k8s.global.mainnet.chain.grpc.injective.network:443" grpc_exchange_endpoint = "k8s.global.mainnet.exchange.grpc.injective.network:443" grpc_explorer_endpoint = "k8s.global.mainnet.explorer.grpc.injective.network:443" - cookie_assistant = MainnetKubernetesCookieAssistant() + cookie_assistant = KubernetesLoadBalancedCookieAssistant() elif node == "lb_bare_metal": lcd_endpoint = "https://sentry.lcd.injective.network:443" tm_websocket_endpoint = "wss://sentry.tm.injective.network:443/websocket" grpc_endpoint = "sentry.chain.grpc.injective.network:443" grpc_exchange_endpoint = "sentry.exchange.grpc.injective.network:443" grpc_explorer_endpoint = "sentry.explorer.grpc.injective.network:443" - cookie_assistant = MainnetBareMetalCookieAssistant() + cookie_assistant = BareMetalLoadBalancedCookieAssistant() else: lcd_endpoint = f"http://{node}.injective.network:10337" tm_websocket_endpoint = f"ws://{node}.injective.network:26657/websocket" diff --git a/pyinjective/transaction.py b/pyinjective/transaction.py index 7a02228f..afe7bd24 100644 --- a/pyinjective/transaction.py +++ b/pyinjective/transaction.py @@ -5,9 +5,8 @@ from .proto.cosmos.tx.v1beta1 import tx_pb2 as cosmos_tx_type from .proto.cosmos.tx.signing.v1beta1 import signing_pb2 as tx_sign -from .client import Client from .constant import MAX_MEMO_CHARACTERS -from .exceptions import EmptyMsgError, NotFoundError, UndefinedError, ValueTooLargeError +from .exceptions import EmptyMsgError, UndefinedError, ValueTooLargeError from .wallet import PublicKey class Transaction: @@ -44,16 +43,6 @@ def with_messages(self, *msgs: message.Message) -> "Transaction": self.msgs.extend(self.__convert_msgs(msgs)) return self - def with_sender(self, client: Client, sender: str) -> "Transaction": - if len(self.msgs) == 0: - raise EmptyMsgError("message is empty, please use with_messages at least 1 message") - account = client.get_account(sender) - if account: - self.account_num = account.account_number - self.sequence = account.sequence - return self - raise NotFoundError("Account doesn't exist") - def with_account_num(self, account_num: int) -> "Transaction": self.account_num = account_num return self From bc266daaaa910c34b81259d8bba0bf2b646c7829 Mon Sep 17 00:00:00 2001 From: abel Date: Wed, 6 Sep 2023 00:31:41 -0300 Subject: [PATCH 39/40] (feat) Made lb bare-metal node the default for mainnet. Fixed an issue with the cookies manager configuration for testnet sentry node. Moved secure/insecure connection configuration to the Network class --- README.md | 4 + examples/chain_client/0_LocalOrderHash.py | 3 +- .../13_MsgIncreasePositionMargin.py | 2 +- examples/chain_client/15_MsgWithdraw.py | 2 +- .../chain_client/16_MsgSubaccountTransfer.py | 2 +- .../chain_client/17_MsgBatchUpdateOrders.py | 2 +- examples/chain_client/18_MsgBid.py | 2 +- examples/chain_client/19_MsgGrant.py | 2 +- examples/chain_client/1_MsgSend.py | 2 +- examples/chain_client/20_MsgExec.py | 2 +- examples/chain_client/21_MsgRevoke.py | 2 +- examples/chain_client/22_MsgSendToEth.py | 2 +- .../chain_client/23_MsgRelayPriceFeedPrice.py | 2 +- examples/chain_client/24_MsgRewardsOptOut.py | 2 +- examples/chain_client/25_MsgDelegate.py | 2 +- .../26_MsgWithdrawDelegatorReward.py | 2 +- examples/chain_client/27_Grants.py | 2 +- examples/chain_client/28_BankBalances.py | 2 +- examples/chain_client/29_BankBalance.py | 2 +- examples/chain_client/2_MsgDeposit.py | 4 +- examples/chain_client/30_ExternalTransfer.py | 2 +- .../31_MsgCreateBinaryOptionsLimitOrder.py | 2 +- .../32_MsgCreateBinaryOptionsMarketOrder.py | 2 +- .../33_MsgCancelBinaryOptionsOrder.py | 2 +- .../34_MsgAdminUpdateBinaryOptionsMarket.py | 2 +- .../35_MsgInstantBinaryOptionsMarketLaunch.py | 2 +- .../chain_client/36_MsgRelayProviderPrices.py | 2 +- examples/chain_client/37_GetTx.py | 2 +- examples/chain_client/39_Account.py | 2 +- .../chain_client/3_MsgCreateSpotLimitOrder.py | 2 +- .../chain_client/40_MsgExecuteContract.py | 2 +- .../chain_client/41_MsgCreateInsuranceFund.py | 2 +- examples/chain_client/42_MsgUnderwrite.py | 2 +- .../chain_client/43_MsgRequestRedemption.py | 2 +- .../chain_client/44_MessageBroadcaster.py | 1 - ...45_MessageBroadcasterWithGranteeAccount.py | 3 +- .../46_MessageBroadcasterWithoutSimulation.py | 1 - ...sterWithGranteeAccountWithoutSimulation.py | 3 +- .../4_MsgCreateSpotMarketOrder.py | 2 +- examples/chain_client/5_MsgCancelSpotOrder.py | 2 +- .../6_MsgCreateDerivativeLimitOrder.py | 2 +- .../7_MsgCreateDerivativeMarketOrder.py | 2 +- .../8_MsgCancelDerivativeOrder.py | 2 +- .../accounts_rpc/1_StreamSubaccountBalance.py | 2 +- .../accounts_rpc/2_SubaccountBalance.py | 2 +- .../accounts_rpc/3_SubaccountsList.py | 2 +- .../accounts_rpc/4_SubaccountBalancesList.py | 2 +- .../accounts_rpc/5_SubaccountHistory.py | 2 +- .../accounts_rpc/6_SubaccountOrderSummary.py | 2 +- .../accounts_rpc/7_OrderStates.py | 2 +- .../accounts_rpc/8_Portfolio.py | 2 +- .../exchange_client/accounts_rpc/9_Rewards.py | 2 +- .../exchange_client/auctions_rpc/1_Auction.py | 2 +- .../auctions_rpc/2_Auctions.py | 2 +- .../auctions_rpc/3_StreamBids.py | 2 +- .../10_StreamHistoricalOrders.py | 2 +- .../derivative_exchange_rpc/11_Trades.py | 2 +- .../12_StreamTrades.py | 2 +- .../13_SubaccountOrdersList.py | 2 +- .../14_SubaccountTradesList.py | 2 +- .../15_FundingPayments.py | 2 +- .../17_FundingRates.py | 2 +- .../derivative_exchange_rpc/18_Orderbooks.py | 2 +- .../19_Binary_Options_Markets.py | 2 +- .../derivative_exchange_rpc/1_Market.py | 2 +- .../20_Binary_Options_Market.py | 2 +- .../21_Historical_Orders.py | 2 +- .../22_OrderbooksV2.py | 2 +- .../derivative_exchange_rpc/2_Markets.py | 2 +- .../derivative_exchange_rpc/3_StreamMarket.py | 2 +- .../derivative_exchange_rpc/4_Orderbook.py | 2 +- .../5_StreamOrderbooks.py | 2 +- .../6_StreamOrderbookUpdate.py | 2 +- .../derivative_exchange_rpc/7_Positions.py | 2 +- .../9_StreamPositions.py | 2 +- .../explorer_rpc/10_GetIBCTransfers.py | 2 +- .../explorer_rpc/1_GetTxByHash.py | 2 +- .../explorer_rpc/2_AccountTxs.py | 2 +- .../exchange_client/explorer_rpc/3_Blocks.py | 2 +- .../exchange_client/explorer_rpc/4_Block.py | 2 +- .../explorer_rpc/5_TxsRequest.py | 2 +- .../explorer_rpc/6_StreamTxs.py | 2 +- .../explorer_rpc/7_StreamBlocks.py | 2 +- .../explorer_rpc/8_GetPeggyDeposits.py | 2 +- .../explorer_rpc/9_GetPeggyWithdrawals.py | 2 +- .../insurance_rpc/1_InsuranceFunds.py | 2 +- .../insurance_rpc/2_Redemptions.py | 2 +- examples/exchange_client/meta_rpc/1_Ping.py | 2 +- .../exchange_client/meta_rpc/2_Version.py | 2 +- examples/exchange_client/meta_rpc/3_Info.py | 2 +- .../meta_rpc/4_StreamKeepAlive.py | 2 +- .../oracle_rpc/1_StreamPrices.py | 2 +- .../exchange_client/oracle_rpc/2_Price.py | 2 +- .../oracle_rpc/3_OracleList.py | 2 +- .../portfolio_rpc/1_AccountPortfolio.py | 2 +- .../portfolio_rpc/2_StreamAccountPortfolio.py | 2 +- .../spot_exchange_rpc/10_StreamTrades.py | 2 +- .../11_SubaccountOrdersList.py | 2 +- .../12_SubaccountTradesList.py | 2 +- .../spot_exchange_rpc/13_StreamOrderbooks.py | 2 +- .../spot_exchange_rpc/14_Orderbooks.py | 2 +- .../spot_exchange_rpc/15_HistoricalOrders.py | 2 +- .../spot_exchange_rpc/1_Market.py | 2 +- .../spot_exchange_rpc/2_Markets.py | 2 +- .../spot_exchange_rpc/3_StreamMarkets.py | 2 +- .../spot_exchange_rpc/4_Orderbook.py | 2 +- .../spot_exchange_rpc/6_Trades.py | 2 +- .../7_StreamOrderbookSnapshot.py | 2 +- .../8_StreamOrderbookUpdate.py | 2 +- .../9_StreamHistoricalOrders.py | 2 +- pyinjective/async_client.py | 21 ++-- pyinjective/core/broadcaster.py | 12 +-- pyinjective/core/network.py | 99 +++++-------------- pyinjective/utils/fetch_metadata.py | 4 +- pyinjective/utils/metadata_validation.py | 4 +- setup.py | 2 +- ...essage_based_transaction_fee_calculator.py | 14 +-- 117 files changed, 163 insertions(+), 218 deletions(-) diff --git a/README.md b/README.md index f2475615..278b5f7b 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,10 @@ make tests ``` ### Changelogs +**0.8.1** +* Moved the configuration to use a secure or insecure connection inside the Network class. The AsyncClient's `insecure` parameter is no longer used for anything and will be removed in the future. +* Made the new load balanced bare-metal node the default one for mainnet (it is called `lb`). The legacy one (load balanced k8s node) is called `lb_k8s` + **0.8**(change before release) * Refactor Composer to be created with all the markets and tokens. The Composer now uses the real markets and tokens to convert human-readable values to chain format * The Composer can still be instantiated without markets and tokens. When markets and tokens are not provided the Composer loads the required information from the Denoms used in previous versions diff --git a/examples/chain_client/0_LocalOrderHash.py b/examples/chain_client/0_LocalOrderHash.py index 7ce7de68..0e20049b 100644 --- a/examples/chain_client/0_LocalOrderHash.py +++ b/examples/chain_client/0_LocalOrderHash.py @@ -1,6 +1,7 @@ import asyncio from pyinjective.async_client import AsyncClient +from pyinjective.composer import Composer from pyinjective.transaction import Transaction from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey @@ -11,7 +12,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/13_MsgIncreasePositionMargin.py b/examples/chain_client/13_MsgIncreasePositionMargin.py index 2aa66a13..d5e1d7cd 100644 --- a/examples/chain_client/13_MsgIncreasePositionMargin.py +++ b/examples/chain_client/13_MsgIncreasePositionMargin.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/15_MsgWithdraw.py b/examples/chain_client/15_MsgWithdraw.py index 51baf733..fb585719 100644 --- a/examples/chain_client/15_MsgWithdraw.py +++ b/examples/chain_client/15_MsgWithdraw.py @@ -25,7 +25,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/16_MsgSubaccountTransfer.py b/examples/chain_client/16_MsgSubaccountTransfer.py index 80cb0ee5..e3dbde9b 100644 --- a/examples/chain_client/16_MsgSubaccountTransfer.py +++ b/examples/chain_client/16_MsgSubaccountTransfer.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/17_MsgBatchUpdateOrders.py b/examples/chain_client/17_MsgBatchUpdateOrders.py index 4ce2cc56..853b85ee 100644 --- a/examples/chain_client/17_MsgBatchUpdateOrders.py +++ b/examples/chain_client/17_MsgBatchUpdateOrders.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/18_MsgBid.py b/examples/chain_client/18_MsgBid.py index eba03940..001fde7c 100644 --- a/examples/chain_client/18_MsgBid.py +++ b/examples/chain_client/18_MsgBid.py @@ -10,7 +10,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/19_MsgGrant.py b/examples/chain_client/19_MsgGrant.py index 1d58a24b..17a8ffee 100644 --- a/examples/chain_client/19_MsgGrant.py +++ b/examples/chain_client/19_MsgGrant.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/1_MsgSend.py b/examples/chain_client/1_MsgSend.py index ad24b941..f4894b4d 100644 --- a/examples/chain_client/1_MsgSend.py +++ b/examples/chain_client/1_MsgSend.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/20_MsgExec.py b/examples/chain_client/20_MsgExec.py index 12f4526c..e0f6854e 100644 --- a/examples/chain_client/20_MsgExec.py +++ b/examples/chain_client/20_MsgExec.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/21_MsgRevoke.py b/examples/chain_client/21_MsgRevoke.py index db39f714..51b23f8b 100644 --- a/examples/chain_client/21_MsgRevoke.py +++ b/examples/chain_client/21_MsgRevoke.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/22_MsgSendToEth.py b/examples/chain_client/22_MsgSendToEth.py index afaf3030..aed1442f 100644 --- a/examples/chain_client/22_MsgSendToEth.py +++ b/examples/chain_client/22_MsgSendToEth.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/23_MsgRelayPriceFeedPrice.py b/examples/chain_client/23_MsgRelayPriceFeedPrice.py index e17f05a2..d0a96996 100644 --- a/examples/chain_client/23_MsgRelayPriceFeedPrice.py +++ b/examples/chain_client/23_MsgRelayPriceFeedPrice.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/24_MsgRewardsOptOut.py b/examples/chain_client/24_MsgRewardsOptOut.py index da4fc0fc..ef876c35 100644 --- a/examples/chain_client/24_MsgRewardsOptOut.py +++ b/examples/chain_client/24_MsgRewardsOptOut.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/25_MsgDelegate.py b/examples/chain_client/25_MsgDelegate.py index f2f25db6..7df4eb17 100644 --- a/examples/chain_client/25_MsgDelegate.py +++ b/examples/chain_client/25_MsgDelegate.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/26_MsgWithdrawDelegatorReward.py b/examples/chain_client/26_MsgWithdrawDelegatorReward.py index 99d87b62..2ee30e32 100644 --- a/examples/chain_client/26_MsgWithdrawDelegatorReward.py +++ b/examples/chain_client/26_MsgWithdrawDelegatorReward.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/27_Grants.py b/examples/chain_client/27_Grants.py index 2ff81236..e94ce9b8 100644 --- a/examples/chain_client/27_Grants.py +++ b/examples/chain_client/27_Grants.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) granter = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku" grantee = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" msg_type_url = "/injective.exchange.v1beta1.MsgCreateDerivativeLimitOrder" diff --git a/examples/chain_client/28_BankBalances.py b/examples/chain_client/28_BankBalances.py index 84424426..5a52939f 100644 --- a/examples/chain_client/28_BankBalances.py +++ b/examples/chain_client/28_BankBalances.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) address = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r" all_bank_balances = await client.get_bank_balances(address=address) print(all_bank_balances) diff --git a/examples/chain_client/29_BankBalance.py b/examples/chain_client/29_BankBalance.py index 1f38a02d..d5d2d533 100644 --- a/examples/chain_client/29_BankBalance.py +++ b/examples/chain_client/29_BankBalance.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) address = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r" denom = "inj" bank_balance = await client.get_bank_balance(address=address, denom=denom) diff --git a/examples/chain_client/2_MsgDeposit.py b/examples/chain_client/2_MsgDeposit.py index 709c0bf2..1484b1ed 100644 --- a/examples/chain_client/2_MsgDeposit.py +++ b/examples/chain_client/2_MsgDeposit.py @@ -8,10 +8,10 @@ async def main() -> None: # select network: local, testnet, mainnet - network = Network.testnet() + network = Network.testnet(node="sentry") # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/30_ExternalTransfer.py b/examples/chain_client/30_ExternalTransfer.py index ab2b9034..a973e4b2 100644 --- a/examples/chain_client/30_ExternalTransfer.py +++ b/examples/chain_client/30_ExternalTransfer.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py index dfa03aa3..25652212 100644 --- a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py +++ b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py index 62030441..8bd5ae77 100644 --- a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py +++ b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py index 557f1dd9..f3e534b7 100644 --- a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py +++ b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py index 78e7e88e..073529ae 100644 --- a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py +++ b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py index 99510b6b..35c30c39 100644 --- a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py +++ b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/36_MsgRelayProviderPrices.py b/examples/chain_client/36_MsgRelayProviderPrices.py index 41cabe90..23c9ac94 100644 --- a/examples/chain_client/36_MsgRelayProviderPrices.py +++ b/examples/chain_client/36_MsgRelayProviderPrices.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/37_GetTx.py b/examples/chain_client/37_GetTx.py index d2eb72fa..77d13eb9 100644 --- a/examples/chain_client/37_GetTx.py +++ b/examples/chain_client/37_GetTx.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) tx_hash = "7746BC12EB82B4D59D036FBFF2F67BDCA6F62A20B3DBC25661707DD61D4DC1B7" tx_logs = await client.get_tx(tx_hash=tx_hash) print(tx_logs) diff --git a/examples/chain_client/39_Account.py b/examples/chain_client/39_Account.py index b30232ec..4089a5dd 100644 --- a/examples/chain_client/39_Account.py +++ b/examples/chain_client/39_Account.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) address = "inj1knhahceyp57j5x7xh69p7utegnnnfgxavmahjr" acc = await client.get_account(address=address) print(acc) diff --git a/examples/chain_client/3_MsgCreateSpotLimitOrder.py b/examples/chain_client/3_MsgCreateSpotLimitOrder.py index daba1a39..34466874 100644 --- a/examples/chain_client/3_MsgCreateSpotLimitOrder.py +++ b/examples/chain_client/3_MsgCreateSpotLimitOrder.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/40_MsgExecuteContract.py b/examples/chain_client/40_MsgExecuteContract.py index 949caa1d..cde8c480 100644 --- a/examples/chain_client/40_MsgExecuteContract.py +++ b/examples/chain_client/40_MsgExecuteContract.py @@ -12,7 +12,7 @@ async def main() -> None: # initialize grpc client # set custom cookie location (optional) - defaults to current dir - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/41_MsgCreateInsuranceFund.py b/examples/chain_client/41_MsgCreateInsuranceFund.py index 3fb0c5cc..89007e23 100644 --- a/examples/chain_client/41_MsgCreateInsuranceFund.py +++ b/examples/chain_client/41_MsgCreateInsuranceFund.py @@ -11,7 +11,7 @@ async def main() -> None: # initialize grpc client # set custom cookie location (optional) - defaults to current dir - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/42_MsgUnderwrite.py b/examples/chain_client/42_MsgUnderwrite.py index 79cfe5d7..7c143e51 100644 --- a/examples/chain_client/42_MsgUnderwrite.py +++ b/examples/chain_client/42_MsgUnderwrite.py @@ -11,7 +11,7 @@ async def main() -> None: # initialize grpc client # set custom cookie location (optional) - defaults to current dir - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/43_MsgRequestRedemption.py b/examples/chain_client/43_MsgRequestRedemption.py index 8d434368..a32add66 100644 --- a/examples/chain_client/43_MsgRequestRedemption.py +++ b/examples/chain_client/43_MsgRequestRedemption.py @@ -11,7 +11,7 @@ async def main() -> None: # initialize grpc client # set custom cookie location (optional) - defaults to current dir - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/44_MessageBroadcaster.py b/examples/chain_client/44_MessageBroadcaster.py index 10d157fc..4fbeb719 100644 --- a/examples/chain_client/44_MessageBroadcaster.py +++ b/examples/chain_client/44_MessageBroadcaster.py @@ -15,7 +15,6 @@ async def main() -> None: message_broadcaster = MsgBroadcasterWithPk.new_using_simulation( network=network, private_key=private_key_in_hexa, - use_secure_connection=True ) priv_key = PrivateKey.from_hex(private_key_in_hexa) diff --git a/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py b/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py index 81417a1e..dc017f3f 100644 --- a/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py +++ b/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py @@ -13,7 +13,7 @@ async def main() -> None: composer = ProtoMsgComposer(network=network.string()) # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) await client.sync_timeout_height() # load account @@ -25,7 +25,6 @@ async def main() -> None: message_broadcaster = MsgBroadcasterWithPk.new_for_grantee_account_using_simulation( network=network, grantee_private_key=private_key_in_hexa, - use_secure_connection=True ) # prepare tx msg diff --git a/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py b/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py index 4e062d63..dc804b24 100644 --- a/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py +++ b/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py @@ -15,7 +15,6 @@ async def main() -> None: message_broadcaster = MsgBroadcasterWithPk.new_without_simulation( network=network, private_key=private_key_in_hexa, - use_secure_connection=True ) priv_key = PrivateKey.from_hex(private_key_in_hexa) diff --git a/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py b/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py index 371f852d..4221d795 100644 --- a/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py +++ b/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py @@ -13,7 +13,7 @@ async def main() -> None: composer = ProtoMsgComposer(network=network.string()) # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) await client.sync_timeout_height() # load account @@ -25,7 +25,6 @@ async def main() -> None: message_broadcaster = MsgBroadcasterWithPk.new_for_grantee_account_without_simulation( network=network, grantee_private_key=private_key_in_hexa, - use_secure_connection=True ) # prepare tx msg diff --git a/examples/chain_client/4_MsgCreateSpotMarketOrder.py b/examples/chain_client/4_MsgCreateSpotMarketOrder.py index 827e653d..3185cafa 100644 --- a/examples/chain_client/4_MsgCreateSpotMarketOrder.py +++ b/examples/chain_client/4_MsgCreateSpotMarketOrder.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/5_MsgCancelSpotOrder.py b/examples/chain_client/5_MsgCancelSpotOrder.py index 602beb7a..93030ecd 100644 --- a/examples/chain_client/5_MsgCancelSpotOrder.py +++ b/examples/chain_client/5_MsgCancelSpotOrder.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py index dc175e20..add38833 100644 --- a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py +++ b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py index 88a18eb8..f1e71b1c 100644 --- a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py +++ b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/chain_client/8_MsgCancelDerivativeOrder.py b/examples/chain_client/8_MsgCancelDerivativeOrder.py index 3784bdc6..1ea9001c 100644 --- a/examples/chain_client/8_MsgCancelDerivativeOrder.py +++ b/examples/chain_client/8_MsgCancelDerivativeOrder.py @@ -11,7 +11,7 @@ async def main() -> None: network = Network.testnet() # initialize grpc client - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = await client.composer() await client.sync_timeout_height() diff --git a/examples/exchange_client/accounts_rpc/1_StreamSubaccountBalance.py b/examples/exchange_client/accounts_rpc/1_StreamSubaccountBalance.py index bc0017ba..25c6163c 100644 --- a/examples/exchange_client/accounts_rpc/1_StreamSubaccountBalance.py +++ b/examples/exchange_client/accounts_rpc/1_StreamSubaccountBalance.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) subaccount_id = "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001" denoms = ["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"] subaccount = await client.stream_subaccount_balance( diff --git a/examples/exchange_client/accounts_rpc/2_SubaccountBalance.py b/examples/exchange_client/accounts_rpc/2_SubaccountBalance.py index eeabafd1..13a5bfba 100644 --- a/examples/exchange_client/accounts_rpc/2_SubaccountBalance.py +++ b/examples/exchange_client/accounts_rpc/2_SubaccountBalance.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000" denom = "inj" balance = await client.get_subaccount_balance( diff --git a/examples/exchange_client/accounts_rpc/3_SubaccountsList.py b/examples/exchange_client/accounts_rpc/3_SubaccountsList.py index 54abf051..390200e1 100644 --- a/examples/exchange_client/accounts_rpc/3_SubaccountsList.py +++ b/examples/exchange_client/accounts_rpc/3_SubaccountsList.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) account_address = "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt" subacc_list = await client.get_subaccount_list(account_address) print(subacc_list) diff --git a/examples/exchange_client/accounts_rpc/4_SubaccountBalancesList.py b/examples/exchange_client/accounts_rpc/4_SubaccountBalancesList.py index 49320cfa..1bb746b5 100644 --- a/examples/exchange_client/accounts_rpc/4_SubaccountBalancesList.py +++ b/examples/exchange_client/accounts_rpc/4_SubaccountBalancesList.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) subaccount = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000" denoms = ["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"] subacc_balances_list = await client.get_subaccount_balances_list( diff --git a/examples/exchange_client/accounts_rpc/5_SubaccountHistory.py b/examples/exchange_client/accounts_rpc/5_SubaccountHistory.py index 93e75d89..fa871b7f 100644 --- a/examples/exchange_client/accounts_rpc/5_SubaccountHistory.py +++ b/examples/exchange_client/accounts_rpc/5_SubaccountHistory.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) subaccount = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000" denom = "inj" transfer_types = ["withdraw", "deposit"] diff --git a/examples/exchange_client/accounts_rpc/6_SubaccountOrderSummary.py b/examples/exchange_client/accounts_rpc/6_SubaccountOrderSummary.py index eb49ee05..606e75a3 100644 --- a/examples/exchange_client/accounts_rpc/6_SubaccountOrderSummary.py +++ b/examples/exchange_client/accounts_rpc/6_SubaccountOrderSummary.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) subaccount = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000" order_direction = "buy" market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" diff --git a/examples/exchange_client/accounts_rpc/7_OrderStates.py b/examples/exchange_client/accounts_rpc/7_OrderStates.py index 75747360..1c4117e8 100644 --- a/examples/exchange_client/accounts_rpc/7_OrderStates.py +++ b/examples/exchange_client/accounts_rpc/7_OrderStates.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) spot_order_hashes = ["0xce0d9b701f77cd6ddfda5dd3a4fe7b2d53ba83e5d6c054fb2e9e886200b7b7bb", "0x2e2245b5431638d76c6e0cc6268970418a1b1b7df60a8e94b8cf37eae6105542"] derivative_order_hashes = ["0x82113f3998999bdc3892feaab2c4e53ba06c5fe887a2d5f9763397240f24da50", "0xbb1f036001378cecb5fff1cc69303919985b5bf058c32f37d5aaf9b804c07a06"] orders = await client.get_order_states(spot_order_hashes=spot_order_hashes, derivative_order_hashes=derivative_order_hashes) diff --git a/examples/exchange_client/accounts_rpc/8_Portfolio.py b/examples/exchange_client/accounts_rpc/8_Portfolio.py index 3f6fdd48..04e709bc 100644 --- a/examples/exchange_client/accounts_rpc/8_Portfolio.py +++ b/examples/exchange_client/accounts_rpc/8_Portfolio.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) account_address = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku" portfolio = await client.get_portfolio(account_address=account_address) print(portfolio) diff --git a/examples/exchange_client/accounts_rpc/9_Rewards.py b/examples/exchange_client/accounts_rpc/9_Rewards.py index a3139ab2..687f3a1a 100644 --- a/examples/exchange_client/accounts_rpc/9_Rewards.py +++ b/examples/exchange_client/accounts_rpc/9_Rewards.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) # account_address = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku" epoch = -1 rewards = await client.get_rewards( diff --git a/examples/exchange_client/auctions_rpc/1_Auction.py b/examples/exchange_client/auctions_rpc/1_Auction.py index ec6a80ad..02307e00 100644 --- a/examples/exchange_client/auctions_rpc/1_Auction.py +++ b/examples/exchange_client/auctions_rpc/1_Auction.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) bid_round = 31 auction = await client.get_auction(bid_round=bid_round) print(auction) diff --git a/examples/exchange_client/auctions_rpc/2_Auctions.py b/examples/exchange_client/auctions_rpc/2_Auctions.py index 0fa3b5b4..5f161f5d 100644 --- a/examples/exchange_client/auctions_rpc/2_Auctions.py +++ b/examples/exchange_client/auctions_rpc/2_Auctions.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) auctions = await client.get_auctions() print(auctions) diff --git a/examples/exchange_client/auctions_rpc/3_StreamBids.py b/examples/exchange_client/auctions_rpc/3_StreamBids.py index 5078f981..3119670d 100644 --- a/examples/exchange_client/auctions_rpc/3_StreamBids.py +++ b/examples/exchange_client/auctions_rpc/3_StreamBids.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) bids = await client.stream_bids() async for bid in bids: print(bid) diff --git a/examples/exchange_client/derivative_exchange_rpc/10_StreamHistoricalOrders.py b/examples/exchange_client/derivative_exchange_rpc/10_StreamHistoricalOrders.py index 22081c71..429862d1 100644 --- a/examples/exchange_client/derivative_exchange_rpc/10_StreamHistoricalOrders.py +++ b/examples/exchange_client/derivative_exchange_rpc/10_StreamHistoricalOrders.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" order_side = "sell" subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000" diff --git a/examples/exchange_client/derivative_exchange_rpc/11_Trades.py b/examples/exchange_client/derivative_exchange_rpc/11_Trades.py index 665e4651..f822babb 100644 --- a/examples/exchange_client/derivative_exchange_rpc/11_Trades.py +++ b/examples/exchange_client/derivative_exchange_rpc/11_Trades.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000" trades = await client.get_derivative_trades( diff --git a/examples/exchange_client/derivative_exchange_rpc/12_StreamTrades.py b/examples/exchange_client/derivative_exchange_rpc/12_StreamTrades.py index c6b6c48d..03136700 100644 --- a/examples/exchange_client/derivative_exchange_rpc/12_StreamTrades.py +++ b/examples/exchange_client/derivative_exchange_rpc/12_StreamTrades.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_ids = [ "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", "0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff" diff --git a/examples/exchange_client/derivative_exchange_rpc/13_SubaccountOrdersList.py b/examples/exchange_client/derivative_exchange_rpc/13_SubaccountOrdersList.py index d899ba2f..62609850 100644 --- a/examples/exchange_client/derivative_exchange_rpc/13_SubaccountOrdersList.py +++ b/examples/exchange_client/derivative_exchange_rpc/13_SubaccountOrdersList.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000" market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" skip = 1 diff --git a/examples/exchange_client/derivative_exchange_rpc/14_SubaccountTradesList.py b/examples/exchange_client/derivative_exchange_rpc/14_SubaccountTradesList.py index adf2cee5..d6b0bf81 100644 --- a/examples/exchange_client/derivative_exchange_rpc/14_SubaccountTradesList.py +++ b/examples/exchange_client/derivative_exchange_rpc/14_SubaccountTradesList.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000" market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" execution_type = "market" diff --git a/examples/exchange_client/derivative_exchange_rpc/15_FundingPayments.py b/examples/exchange_client/derivative_exchange_rpc/15_FundingPayments.py index 0f15c537..4ff983c5 100644 --- a/examples/exchange_client/derivative_exchange_rpc/15_FundingPayments.py +++ b/examples/exchange_client/derivative_exchange_rpc/15_FundingPayments.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000" skip=0 diff --git a/examples/exchange_client/derivative_exchange_rpc/17_FundingRates.py b/examples/exchange_client/derivative_exchange_rpc/17_FundingRates.py index 04122a7c..47a14794 100644 --- a/examples/exchange_client/derivative_exchange_rpc/17_FundingRates.py +++ b/examples/exchange_client/derivative_exchange_rpc/17_FundingRates.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" skip=0 limit=3 diff --git a/examples/exchange_client/derivative_exchange_rpc/18_Orderbooks.py b/examples/exchange_client/derivative_exchange_rpc/18_Orderbooks.py index cc1c8aca..d3583aff 100644 --- a/examples/exchange_client/derivative_exchange_rpc/18_Orderbooks.py +++ b/examples/exchange_client/derivative_exchange_rpc/18_Orderbooks.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_ids = [ "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", "0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff" diff --git a/examples/exchange_client/derivative_exchange_rpc/19_Binary_Options_Markets.py b/examples/exchange_client/derivative_exchange_rpc/19_Binary_Options_Markets.py index 1fef009f..233dce5f 100644 --- a/examples/exchange_client/derivative_exchange_rpc/19_Binary_Options_Markets.py +++ b/examples/exchange_client/derivative_exchange_rpc/19_Binary_Options_Markets.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_status = "active" quote_denom = "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7" market = await client.get_binary_options_markets( diff --git a/examples/exchange_client/derivative_exchange_rpc/1_Market.py b/examples/exchange_client/derivative_exchange_rpc/1_Market.py index d2c6e80b..520f55c8 100644 --- a/examples/exchange_client/derivative_exchange_rpc/1_Market.py +++ b/examples/exchange_client/derivative_exchange_rpc/1_Market.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" market = await client.get_derivative_market(market_id=market_id) print(market) diff --git a/examples/exchange_client/derivative_exchange_rpc/20_Binary_Options_Market.py b/examples/exchange_client/derivative_exchange_rpc/20_Binary_Options_Market.py index 0d1b9150..7cbf0924 100644 --- a/examples/exchange_client/derivative_exchange_rpc/20_Binary_Options_Market.py +++ b/examples/exchange_client/derivative_exchange_rpc/20_Binary_Options_Market.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x175513943b8677368d138e57bcd6bef53170a0da192e7eaa8c2cd4509b54f8db" market = await client.get_binary_options_market(market_id=market_id) print(market) diff --git a/examples/exchange_client/derivative_exchange_rpc/21_Historical_Orders.py b/examples/exchange_client/derivative_exchange_rpc/21_Historical_Orders.py index eed98d99..ea864397 100644 --- a/examples/exchange_client/derivative_exchange_rpc/21_Historical_Orders.py +++ b/examples/exchange_client/derivative_exchange_rpc/21_Historical_Orders.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" subaccount_id = "0x295639d56c987f0e24d21bb167872b3542a6e05a000000000000000000000000" is_conditional = "false" diff --git a/examples/exchange_client/derivative_exchange_rpc/22_OrderbooksV2.py b/examples/exchange_client/derivative_exchange_rpc/22_OrderbooksV2.py index 8205a694..2a21d145 100644 --- a/examples/exchange_client/derivative_exchange_rpc/22_OrderbooksV2.py +++ b/examples/exchange_client/derivative_exchange_rpc/22_OrderbooksV2.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_ids = [ "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", "0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff" diff --git a/examples/exchange_client/derivative_exchange_rpc/2_Markets.py b/examples/exchange_client/derivative_exchange_rpc/2_Markets.py index 9b7ec94f..275d372f 100644 --- a/examples/exchange_client/derivative_exchange_rpc/2_Markets.py +++ b/examples/exchange_client/derivative_exchange_rpc/2_Markets.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_status = "active" quote_denom = "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5" market = await client.get_derivative_markets( diff --git a/examples/exchange_client/derivative_exchange_rpc/3_StreamMarket.py b/examples/exchange_client/derivative_exchange_rpc/3_StreamMarket.py index b44fa804..d3b15a71 100644 --- a/examples/exchange_client/derivative_exchange_rpc/3_StreamMarket.py +++ b/examples/exchange_client/derivative_exchange_rpc/3_StreamMarket.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) markets = await client.stream_derivative_markets() async for market in markets: print(market) diff --git a/examples/exchange_client/derivative_exchange_rpc/4_Orderbook.py b/examples/exchange_client/derivative_exchange_rpc/4_Orderbook.py index 8d891a6c..9020a949 100644 --- a/examples/exchange_client/derivative_exchange_rpc/4_Orderbook.py +++ b/examples/exchange_client/derivative_exchange_rpc/4_Orderbook.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" market = await client.get_derivative_orderbook(market_id=market_id) print(market) diff --git a/examples/exchange_client/derivative_exchange_rpc/5_StreamOrderbooks.py b/examples/exchange_client/derivative_exchange_rpc/5_StreamOrderbooks.py index 64304ec4..8a5a88f6 100644 --- a/examples/exchange_client/derivative_exchange_rpc/5_StreamOrderbooks.py +++ b/examples/exchange_client/derivative_exchange_rpc/5_StreamOrderbooks.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" markets = await client.stream_derivative_orderbook_snapshot(market_ids=[market_id]) async for market in markets: diff --git a/examples/exchange_client/derivative_exchange_rpc/6_StreamOrderbookUpdate.py b/examples/exchange_client/derivative_exchange_rpc/6_StreamOrderbookUpdate.py index b5f48c5a..4dd446db 100644 --- a/examples/exchange_client/derivative_exchange_rpc/6_StreamOrderbookUpdate.py +++ b/examples/exchange_client/derivative_exchange_rpc/6_StreamOrderbookUpdate.py @@ -50,7 +50,7 @@ async def load_orderbook_snapshot(async_client: AsyncClient, orderbook: Orderboo async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - async_client = AsyncClient(network, insecure=False) + async_client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" orderbook = Orderbook(market_id=market_id) diff --git a/examples/exchange_client/derivative_exchange_rpc/7_Positions.py b/examples/exchange_client/derivative_exchange_rpc/7_Positions.py index 36e871cb..50500c14 100644 --- a/examples/exchange_client/derivative_exchange_rpc/7_Positions.py +++ b/examples/exchange_client/derivative_exchange_rpc/7_Positions.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_ids = [ "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", "0xd97d0da6f6c11710ef06315971250e4e9aed4b7d4cd02059c9477ec8cf243782" diff --git a/examples/exchange_client/derivative_exchange_rpc/9_StreamPositions.py b/examples/exchange_client/derivative_exchange_rpc/9_StreamPositions.py index 32586681..425363ff 100644 --- a/examples/exchange_client/derivative_exchange_rpc/9_StreamPositions.py +++ b/examples/exchange_client/derivative_exchange_rpc/9_StreamPositions.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" subaccount_id = "0xea98e3aa091a6676194df40ac089e40ab4604bf9000000000000000000000000" positions = await client.stream_derivative_positions( diff --git a/examples/exchange_client/explorer_rpc/10_GetIBCTransfers.py b/examples/exchange_client/explorer_rpc/10_GetIBCTransfers.py index 945d5313..68daf8d9 100644 --- a/examples/exchange_client/explorer_rpc/10_GetIBCTransfers.py +++ b/examples/exchange_client/explorer_rpc/10_GetIBCTransfers.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) sender = "inj1cll5cv3ezgal30gagkhnq2um6zf6qrmhw4r6c8" receiver = "cosmos1usr9g5a4s2qrwl63sdjtrs2qd4a7huh622pg82" src_channel = "channel-2" diff --git a/examples/exchange_client/explorer_rpc/1_GetTxByHash.py b/examples/exchange_client/explorer_rpc/1_GetTxByHash.py index ad1be37f..7fd480f8 100644 --- a/examples/exchange_client/explorer_rpc/1_GetTxByHash.py +++ b/examples/exchange_client/explorer_rpc/1_GetTxByHash.py @@ -9,7 +9,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = Composer(network=network.string()) tx_hash = "0F3EBEC1882E1EEAC5B7BDD836E976250F1CD072B79485877CEACCB92ACDDF52" transaction_response = await client.get_tx_by_hash(tx_hash=tx_hash) diff --git a/examples/exchange_client/explorer_rpc/2_AccountTxs.py b/examples/exchange_client/explorer_rpc/2_AccountTxs.py index f0f7cca0..2fc3958b 100644 --- a/examples/exchange_client/explorer_rpc/2_AccountTxs.py +++ b/examples/exchange_client/explorer_rpc/2_AccountTxs.py @@ -9,7 +9,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) composer = Composer(network=network.string()) address = "inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex" message_type = "cosmos.bank.v1beta1.MsgSend" diff --git a/examples/exchange_client/explorer_rpc/3_Blocks.py b/examples/exchange_client/explorer_rpc/3_Blocks.py index 0035c51d..23d30dba 100644 --- a/examples/exchange_client/explorer_rpc/3_Blocks.py +++ b/examples/exchange_client/explorer_rpc/3_Blocks.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) limit = 2 block = await client.get_blocks(limit=limit) print(block) diff --git a/examples/exchange_client/explorer_rpc/4_Block.py b/examples/exchange_client/explorer_rpc/4_Block.py index 6ac9982f..92b17b12 100644 --- a/examples/exchange_client/explorer_rpc/4_Block.py +++ b/examples/exchange_client/explorer_rpc/4_Block.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) block_height = "5825046" block = await client.get_block(block_height=block_height) print(block) diff --git a/examples/exchange_client/explorer_rpc/5_TxsRequest.py b/examples/exchange_client/explorer_rpc/5_TxsRequest.py index e01a7066..434b0779 100644 --- a/examples/exchange_client/explorer_rpc/5_TxsRequest.py +++ b/examples/exchange_client/explorer_rpc/5_TxsRequest.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) limit = 2 txs = await client.get_txs(limit=limit) print(txs) diff --git a/examples/exchange_client/explorer_rpc/6_StreamTxs.py b/examples/exchange_client/explorer_rpc/6_StreamTxs.py index 52cde6d3..6c173091 100644 --- a/examples/exchange_client/explorer_rpc/6_StreamTxs.py +++ b/examples/exchange_client/explorer_rpc/6_StreamTxs.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) stream_txs = await client.stream_txs( ) async for tx in stream_txs: diff --git a/examples/exchange_client/explorer_rpc/7_StreamBlocks.py b/examples/exchange_client/explorer_rpc/7_StreamBlocks.py index a460ee14..96b83935 100644 --- a/examples/exchange_client/explorer_rpc/7_StreamBlocks.py +++ b/examples/exchange_client/explorer_rpc/7_StreamBlocks.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) stream_blocks = await client.stream_blocks( ) async for block in stream_blocks: diff --git a/examples/exchange_client/explorer_rpc/8_GetPeggyDeposits.py b/examples/exchange_client/explorer_rpc/8_GetPeggyDeposits.py index 32a8f01a..97a8ab10 100644 --- a/examples/exchange_client/explorer_rpc/8_GetPeggyDeposits.py +++ b/examples/exchange_client/explorer_rpc/8_GetPeggyDeposits.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) receiver = "inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex" peggy_deposits = await client.get_peggy_deposits(receiver=receiver) print(peggy_deposits) diff --git a/examples/exchange_client/explorer_rpc/9_GetPeggyWithdrawals.py b/examples/exchange_client/explorer_rpc/9_GetPeggyWithdrawals.py index 889b46df..12264475 100644 --- a/examples/exchange_client/explorer_rpc/9_GetPeggyWithdrawals.py +++ b/examples/exchange_client/explorer_rpc/9_GetPeggyWithdrawals.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) sender = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku" limit = 2 peggy_deposits = await client.get_peggy_withdrawals( diff --git a/examples/exchange_client/insurance_rpc/1_InsuranceFunds.py b/examples/exchange_client/insurance_rpc/1_InsuranceFunds.py index 6e0885d1..487e64df 100644 --- a/examples/exchange_client/insurance_rpc/1_InsuranceFunds.py +++ b/examples/exchange_client/insurance_rpc/1_InsuranceFunds.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) insurance_funds = await client.get_insurance_funds() print(insurance_funds) diff --git a/examples/exchange_client/insurance_rpc/2_Redemptions.py b/examples/exchange_client/insurance_rpc/2_Redemptions.py index 66e94ad9..8db3238b 100644 --- a/examples/exchange_client/insurance_rpc/2_Redemptions.py +++ b/examples/exchange_client/insurance_rpc/2_Redemptions.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) redeemer = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku" redemption_denom = "share4" status = "disbursed" diff --git a/examples/exchange_client/meta_rpc/1_Ping.py b/examples/exchange_client/meta_rpc/1_Ping.py index ce7bd3e3..dc505a7a 100644 --- a/examples/exchange_client/meta_rpc/1_Ping.py +++ b/examples/exchange_client/meta_rpc/1_Ping.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) resp = await client.ping() print('Health OK?', resp) diff --git a/examples/exchange_client/meta_rpc/2_Version.py b/examples/exchange_client/meta_rpc/2_Version.py index 1cd63d81..48cb0b4c 100644 --- a/examples/exchange_client/meta_rpc/2_Version.py +++ b/examples/exchange_client/meta_rpc/2_Version.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) resp = await client.version() print('Version:', resp) diff --git a/examples/exchange_client/meta_rpc/3_Info.py b/examples/exchange_client/meta_rpc/3_Info.py index bd925f20..9c3c2693 100644 --- a/examples/exchange_client/meta_rpc/3_Info.py +++ b/examples/exchange_client/meta_rpc/3_Info.py @@ -9,7 +9,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) resp = await client.info() print('[!] Info:') print(resp) diff --git a/examples/exchange_client/meta_rpc/4_StreamKeepAlive.py b/examples/exchange_client/meta_rpc/4_StreamKeepAlive.py index 53092a05..5d3c531b 100644 --- a/examples/exchange_client/meta_rpc/4_StreamKeepAlive.py +++ b/examples/exchange_client/meta_rpc/4_StreamKeepAlive.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) task1 = asyncio.create_task(get_markets(client)) task2 = asyncio.create_task(keepalive(client, [task1])) diff --git a/examples/exchange_client/oracle_rpc/1_StreamPrices.py b/examples/exchange_client/oracle_rpc/1_StreamPrices.py index 3707aa72..788f02f2 100644 --- a/examples/exchange_client/oracle_rpc/1_StreamPrices.py +++ b/examples/exchange_client/oracle_rpc/1_StreamPrices.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) base_symbol = 'BTC' quote_symbol = 'USDT' oracle_type = 'bandibc' diff --git a/examples/exchange_client/oracle_rpc/2_Price.py b/examples/exchange_client/oracle_rpc/2_Price.py index cf92aa1e..094d82d7 100644 --- a/examples/exchange_client/oracle_rpc/2_Price.py +++ b/examples/exchange_client/oracle_rpc/2_Price.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) base_symbol = 'BTC' quote_symbol = 'USDT' oracle_type = 'bandibc' diff --git a/examples/exchange_client/oracle_rpc/3_OracleList.py b/examples/exchange_client/oracle_rpc/3_OracleList.py index 2ff2152c..94cbd70b 100644 --- a/examples/exchange_client/oracle_rpc/3_OracleList.py +++ b/examples/exchange_client/oracle_rpc/3_OracleList.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) oracle_list = await client.get_oracle_list() print(oracle_list) diff --git a/examples/exchange_client/portfolio_rpc/1_AccountPortfolio.py b/examples/exchange_client/portfolio_rpc/1_AccountPortfolio.py index 83b46d57..707f602a 100644 --- a/examples/exchange_client/portfolio_rpc/1_AccountPortfolio.py +++ b/examples/exchange_client/portfolio_rpc/1_AccountPortfolio.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) account_address = "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt" portfolio = await client.get_account_portfolio( account_address=account_address diff --git a/examples/exchange_client/portfolio_rpc/2_StreamAccountPortfolio.py b/examples/exchange_client/portfolio_rpc/2_StreamAccountPortfolio.py index bc587bb9..33c064f8 100644 --- a/examples/exchange_client/portfolio_rpc/2_StreamAccountPortfolio.py +++ b/examples/exchange_client/portfolio_rpc/2_StreamAccountPortfolio.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) account_address = "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt" updates = await client.stream_account_portfolio(account_address=account_address) async for update in updates: diff --git a/examples/exchange_client/spot_exchange_rpc/10_StreamTrades.py b/examples/exchange_client/spot_exchange_rpc/10_StreamTrades.py index d906378c..8f488d9b 100644 --- a/examples/exchange_client/spot_exchange_rpc/10_StreamTrades.py +++ b/examples/exchange_client/spot_exchange_rpc/10_StreamTrades.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_ids = [ "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0" diff --git a/examples/exchange_client/spot_exchange_rpc/11_SubaccountOrdersList.py b/examples/exchange_client/spot_exchange_rpc/11_SubaccountOrdersList.py index a7ab90ef..40a198db 100644 --- a/examples/exchange_client/spot_exchange_rpc/11_SubaccountOrdersList.py +++ b/examples/exchange_client/spot_exchange_rpc/11_SubaccountOrdersList.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) subaccount_id = "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001" market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" skip = 10 diff --git a/examples/exchange_client/spot_exchange_rpc/12_SubaccountTradesList.py b/examples/exchange_client/spot_exchange_rpc/12_SubaccountTradesList.py index 090b1fc3..9c6fbd5b 100644 --- a/examples/exchange_client/spot_exchange_rpc/12_SubaccountTradesList.py +++ b/examples/exchange_client/spot_exchange_rpc/12_SubaccountTradesList.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000" market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" execution_type = "market" diff --git a/examples/exchange_client/spot_exchange_rpc/13_StreamOrderbooks.py b/examples/exchange_client/spot_exchange_rpc/13_StreamOrderbooks.py index 7171595b..5592878b 100644 --- a/examples/exchange_client/spot_exchange_rpc/13_StreamOrderbooks.py +++ b/examples/exchange_client/spot_exchange_rpc/13_StreamOrderbooks.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_ids = [ "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0" diff --git a/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py b/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py index b8b0840f..82f59a69 100644 --- a/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py +++ b/examples/exchange_client/spot_exchange_rpc/14_Orderbooks.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_ids = [ "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0" diff --git a/examples/exchange_client/spot_exchange_rpc/15_HistoricalOrders.py b/examples/exchange_client/spot_exchange_rpc/15_HistoricalOrders.py index d116a8a7..a2ff4cec 100644 --- a/examples/exchange_client/spot_exchange_rpc/15_HistoricalOrders.py +++ b/examples/exchange_client/spot_exchange_rpc/15_HistoricalOrders.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" subaccount_id = "0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000" skip = 10 diff --git a/examples/exchange_client/spot_exchange_rpc/1_Market.py b/examples/exchange_client/spot_exchange_rpc/1_Market.py index e1c99b6e..e96f8d57 100644 --- a/examples/exchange_client/spot_exchange_rpc/1_Market.py +++ b/examples/exchange_client/spot_exchange_rpc/1_Market.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" market = await client.get_spot_market(market_id=market_id) print(market) diff --git a/examples/exchange_client/spot_exchange_rpc/2_Markets.py b/examples/exchange_client/spot_exchange_rpc/2_Markets.py index ff7e3211..36f90f86 100644 --- a/examples/exchange_client/spot_exchange_rpc/2_Markets.py +++ b/examples/exchange_client/spot_exchange_rpc/2_Markets.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_status = "active" base_denom = "inj" quote_denom = "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5" diff --git a/examples/exchange_client/spot_exchange_rpc/3_StreamMarkets.py b/examples/exchange_client/spot_exchange_rpc/3_StreamMarkets.py index d697eeea..d5e37a55 100644 --- a/examples/exchange_client/spot_exchange_rpc/3_StreamMarkets.py +++ b/examples/exchange_client/spot_exchange_rpc/3_StreamMarkets.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) markets = await client.stream_spot_markets() async for market in markets: print(market) diff --git a/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py b/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py index b1a107e2..60822926 100644 --- a/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py +++ b/examples/exchange_client/spot_exchange_rpc/4_Orderbook.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" orderbook = await client.get_spot_orderbookV2(market_id=market_id) print(orderbook) diff --git a/examples/exchange_client/spot_exchange_rpc/6_Trades.py b/examples/exchange_client/spot_exchange_rpc/6_Trades.py index aab46ba2..4745296f 100644 --- a/examples/exchange_client/spot_exchange_rpc/6_Trades.py +++ b/examples/exchange_client/spot_exchange_rpc/6_Trades.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_ids = ["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"] execution_side = "taker" direction = "buy" diff --git a/examples/exchange_client/spot_exchange_rpc/7_StreamOrderbookSnapshot.py b/examples/exchange_client/spot_exchange_rpc/7_StreamOrderbookSnapshot.py index 9094d4ba..e46a8ca8 100644 --- a/examples/exchange_client/spot_exchange_rpc/7_StreamOrderbookSnapshot.py +++ b/examples/exchange_client/spot_exchange_rpc/7_StreamOrderbookSnapshot.py @@ -8,7 +8,7 @@ async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_ids = ["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"] orderbooks = await client.stream_spot_orderbook_snapshot(market_ids=market_ids) async for orderbook in orderbooks: diff --git a/examples/exchange_client/spot_exchange_rpc/8_StreamOrderbookUpdate.py b/examples/exchange_client/spot_exchange_rpc/8_StreamOrderbookUpdate.py index ea0a0a95..bd5fc5fc 100644 --- a/examples/exchange_client/spot_exchange_rpc/8_StreamOrderbookUpdate.py +++ b/examples/exchange_client/spot_exchange_rpc/8_StreamOrderbookUpdate.py @@ -50,7 +50,7 @@ async def load_orderbook_snapshot(async_client: AsyncClient, orderbook: Orderboo async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() - async_client = AsyncClient(network, insecure=False) + async_client = AsyncClient(network) market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" orderbook = Orderbook(market_id=market_id) diff --git a/examples/exchange_client/spot_exchange_rpc/9_StreamHistoricalOrders.py b/examples/exchange_client/spot_exchange_rpc/9_StreamHistoricalOrders.py index 48453eed..96d0898c 100644 --- a/examples/exchange_client/spot_exchange_rpc/9_StreamHistoricalOrders.py +++ b/examples/exchange_client/spot_exchange_rpc/9_StreamHistoricalOrders.py @@ -7,7 +7,7 @@ async def main() -> None: network = Network.testnet() - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" order_side = "buy" subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000" diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index f1ecb8f6..3374f6c1 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -78,6 +78,7 @@ def __init__( insecure: bool = False, credentials=grpc.ssl_channel_credentials(), ): + # the `insecure` parameter is ignored and will be deprecated soon. The value is taken directly from `network` self.addr = "" self.number = 0 @@ -87,11 +88,11 @@ def __init__( # chain stubs self.chain_channel = ( - grpc.aio.insecure_channel(network.grpc_endpoint) - if (insecure or credentials is None) - else grpc.aio.secure_channel(network.grpc_endpoint, credentials) + grpc.aio.secure_channel(network.grpc_endpoint, credentials) + if (network.use_secure_connection and credentials is not None) + else grpc.aio.insecure_channel(network.grpc_endpoint) ) - self.insecure = insecure + self.stubCosmosTendermint = tendermint_query_grpc.ServiceStub( self.chain_channel ) @@ -105,9 +106,9 @@ def __init__( # exchange stubs self.exchange_channel = ( - grpc.aio.insecure_channel(network.grpc_exchange_endpoint) - if (insecure or credentials is None) - else grpc.aio.secure_channel(network.grpc_exchange_endpoint, credentials) + grpc.aio.secure_channel(network.grpc_exchange_endpoint, credentials) + if (network.use_secure_connection and credentials is not None) + else grpc.aio.insecure_channel(network.grpc_exchange_endpoint) ) self.stubMeta = exchange_meta_rpc_grpc.InjectiveMetaRPCStub( self.exchange_channel @@ -136,9 +137,9 @@ def __init__( # explorer stubs self.explorer_channel = ( - grpc.aio.insecure_channel(network.grpc_explorer_endpoint) - if (insecure or credentials is None) - else grpc.aio.secure_channel(network.grpc_explorer_endpoint, credentials) + grpc.aio.secure_channel(network.grpc_explorer_endpoint, credentials) + if (network.use_secure_connection and credentials is not None) + else grpc.aio.insecure_channel(network.grpc_explorer_endpoint) ) self.stubExplorer = explorer_rpc_grpc.InjectiveExplorerRPCStub( self.explorer_channel diff --git a/pyinjective/core/broadcaster.py b/pyinjective/core/broadcaster.py index 68a5baf1..7fb54278 100644 --- a/pyinjective/core/broadcaster.py +++ b/pyinjective/core/broadcaster.py @@ -67,11 +67,10 @@ def new_using_simulation( cls, network: Network, private_key: str, - use_secure_connection: bool = True, client: Optional[AsyncClient] = None, composer: Optional[Composer] = None, ): - client = client or AsyncClient(network=network, insecure=not(use_secure_connection)) + client = client or AsyncClient(network=network) composer = composer or Composer(network=client.network.string()) account_config = StandardAccountBroadcasterConfig(private_key=private_key) fee_calculator = SimulatedTransactionFeeCalculator( @@ -92,11 +91,10 @@ def new_without_simulation( cls, network: Network, private_key: str, - use_secure_connection: bool = True, client: Optional[AsyncClient] = None, composer: Optional[Composer] = None, ): - client = client or AsyncClient(network=network, insecure=not (use_secure_connection)) + client = client or AsyncClient(network=network) composer = composer or Composer(network=client.network.string()) account_config = StandardAccountBroadcasterConfig(private_key=private_key) fee_calculator = MessageBasedTransactionFeeCalculator( @@ -117,11 +115,10 @@ def new_for_grantee_account_using_simulation( cls, network: Network, grantee_private_key: str, - use_secure_connection: bool = True, client: Optional[AsyncClient] = None, composer: Optional[Composer] = None, ): - client = client or AsyncClient(network=network, insecure=not (use_secure_connection)) + client = client or AsyncClient(network=network) composer = composer or Composer(network=client.network.string()) account_config = GranteeAccountBroadcasterConfig(grantee_private_key=grantee_private_key, composer=composer) fee_calculator = SimulatedTransactionFeeCalculator( @@ -142,11 +139,10 @@ def new_for_grantee_account_without_simulation( cls, network: Network, grantee_private_key: str, - use_secure_connection: bool = True, client: Optional[AsyncClient] = None, composer: Optional[Composer] = None, ): - client = client or AsyncClient(network=network, insecure=not (use_secure_connection)) + client = client or AsyncClient(network=network) composer = composer or Composer(network=client.network.string()) account_config = GranteeAccountBroadcasterConfig(grantee_private_key=grantee_private_key, composer=composer) fee_calculator = MessageBasedTransactionFeeCalculator( diff --git a/pyinjective/core/network.py b/pyinjective/core/network.py index ea638920..420d0152 100644 --- a/pyinjective/core/network.py +++ b/pyinjective/core/network.py @@ -150,71 +150,6 @@ def _is_cookie_expired(self, cookie_data: str) -> bool: return False -class TestnetLegacyCookieAssistant(CookieAssistant): - - def __init__(self): - self._chain_cookie: Optional[str] = None - self._exchange_cookie: Optional[str] = None - self._chain_cookie_initialization_lock = asyncio.Lock() - self._exchange_cookie_initialization_lock = asyncio.Lock() - - async def chain_cookie(self, metadata_query_provider: Callable) -> str: - if self._chain_cookie == None: - async with self._chain_cookie_initialization_lock: - if self._chain_cookie == None: - await self._fetch_chain_cookie(metadata_query_provider=metadata_query_provider) - cookie = self._chain_cookie - self._check_chain_cookie_expiration() - - return cookie - - async def exchange_cookie(self, metadata_query_provider: Callable) -> str: - if self._exchange_cookie == None: - async with self._exchange_cookie_initialization_lock: - if self._exchange_cookie == None: - await self._fetch_exchange_cookie(metadata_query_provider=metadata_query_provider) - cookie = self._exchange_cookie - self._check_exchange_cookie_expiration() - - return cookie - - async def _fetch_chain_cookie(self, metadata_query_provider: Callable): - metadata = await metadata_query_provider() - cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) - - if cookie_info is None: - raise RuntimeError(f"Error fetching chain cookie ({metadata})") - - self._chain_cookie = cookie_info - - async def _fetch_exchange_cookie(self, metadata_query_provider: Callable): - metadata = await metadata_query_provider() - cookie_info = next((value for key, value in metadata if key == "set-cookie"), None) - - if cookie_info is None: - raise RuntimeError(f"Error fetching exchange cookie ({metadata})") - - self._exchange_cookie = cookie_info - - def _check_chain_cookie_expiration(self): - if self._is_cookie_expired(cookie_data=self._chain_cookie): - self._chain_cookie = None - - def _check_exchange_cookie_expiration(self): - if self._is_cookie_expired(cookie_data=self._exchange_cookie): - self._exchange_cookie = None - - def _is_cookie_expired(self, cookie_data: str) -> bool: - cookie = SimpleCookie() - cookie.load(cookie_data) - - expiration_time = datetime.datetime.strptime(cookie["grpc-cookie"]["expires"], - "%a, %d-%b-%y %H:%M:%S %Z").timestamp() - - timestamp_diff = expiration_time - time.time() - return timestamp_diff < self.SESSION_RENEWAL_OFFSET - - class DisabledCookieAssistant(CookieAssistant): async def chain_cookie(self, metadata_query_provider: Callable) -> str: pass @@ -241,6 +176,7 @@ def __init__( fee_denom: str, env: str, cookie_assistant: CookieAssistant, + use_secure_connection: bool = False, ): self.lcd_endpoint = lcd_endpoint self.tm_websocket_endpoint = tm_websocket_endpoint @@ -251,6 +187,7 @@ def __init__( self.fee_denom = fee_denom self.env = env self.cookie_assistant = cookie_assistant + self.use_secure_connection = use_secure_connection @classmethod def devnet(cls): @@ -282,13 +219,15 @@ def testnet(cls, node="lb"): grpc_exchange_endpoint = "testnet.sentry.exchange.grpc.injective.network:443" grpc_explorer_endpoint = "testnet.sentry.explorer.grpc.injective.network:443" cookie_assistant = BareMetalLoadBalancedCookieAssistant() + use_secure_connection = True else: lcd_endpoint = "https://testnet.lcd.injective.network" tm_websocket_endpoint = "wss://testnet.tm.injective.network/websocket" grpc_endpoint = "testnet.chain.grpc.injective.network" grpc_exchange_endpoint = "testnet.exchange.grpc.injective.network" grpc_explorer_endpoint = "testnet.explorer.grpc.injective.network" - cookie_assistant = TestnetLegacyCookieAssistant() + cookie_assistant = DisabledCookieAssistant() + use_secure_connection = True return cls( lcd_endpoint=lcd_endpoint, @@ -299,14 +238,15 @@ def testnet(cls, node="lb"): chain_id="injective-888", fee_denom="inj", env="testnet", - cookie_assistant=cookie_assistant + cookie_assistant=cookie_assistant, + use_secure_connection=use_secure_connection ) @classmethod def mainnet(cls, node="lb"): nodes = [ "lb", # us, asia, prod - "lb_bare_metal", + "lb_k8s", "sentry0", # ca, prod "sentry1", # ca, prod "sentry3", # us, prod @@ -315,19 +255,21 @@ def mainnet(cls, node="lb"): raise ValueError("Must be one of {}".format(nodes)) if node == "lb": - lcd_endpoint = "https://k8s.global.mainnet.lcd.injective.network:443" - tm_websocket_endpoint = "wss://k8s.global.mainnet.tm.injective.network:443/websocket" - grpc_endpoint = "k8s.global.mainnet.chain.grpc.injective.network:443" - grpc_exchange_endpoint = "k8s.global.mainnet.exchange.grpc.injective.network:443" - grpc_explorer_endpoint = "k8s.global.mainnet.explorer.grpc.injective.network:443" - cookie_assistant = KubernetesLoadBalancedCookieAssistant() - elif node == "lb_bare_metal": lcd_endpoint = "https://sentry.lcd.injective.network:443" tm_websocket_endpoint = "wss://sentry.tm.injective.network:443/websocket" grpc_endpoint = "sentry.chain.grpc.injective.network:443" grpc_exchange_endpoint = "sentry.exchange.grpc.injective.network:443" grpc_explorer_endpoint = "sentry.explorer.grpc.injective.network:443" cookie_assistant = BareMetalLoadBalancedCookieAssistant() + use_secure_connection = True + elif node == "lb_k8s": + lcd_endpoint = "https://k8s.global.mainnet.lcd.injective.network:443" + tm_websocket_endpoint = "wss://k8s.global.mainnet.tm.injective.network:443/websocket" + grpc_endpoint = "k8s.global.mainnet.chain.grpc.injective.network:443" + grpc_exchange_endpoint = "k8s.global.mainnet.exchange.grpc.injective.network:443" + grpc_explorer_endpoint = "k8s.global.mainnet.explorer.grpc.injective.network:443" + cookie_assistant = KubernetesLoadBalancedCookieAssistant() + use_secure_connection = True else: lcd_endpoint = f"http://{node}.injective.network:10337" tm_websocket_endpoint = f"ws://{node}.injective.network:26657/websocket" @@ -335,6 +277,7 @@ def mainnet(cls, node="lb"): grpc_exchange_endpoint = f"{node}.injective.network:9910" grpc_explorer_endpoint = f"{node}.injective.network:9911" cookie_assistant = DisabledCookieAssistant() + use_secure_connection = False return cls( lcd_endpoint=lcd_endpoint, @@ -346,6 +289,7 @@ def mainnet(cls, node="lb"): fee_denom="inj", env="mainnet", cookie_assistant=cookie_assistant, + use_secure_connection=use_secure_connection, ) @classmethod @@ -360,6 +304,7 @@ def local(cls): fee_denom="inj", env="local", cookie_assistant=DisabledCookieAssistant(), + use_secure_connection=False, ) @classmethod @@ -373,6 +318,7 @@ def custom( chain_id, env, cookie_assistant: Optional[CookieAssistant] = None, + use_secure_connection: bool = False, ): assistant = cookie_assistant or DisabledCookieAssistant() return cls( @@ -384,7 +330,8 @@ def custom( chain_id=chain_id, fee_denom="inj", env=env, - cookie_assistant=assistant + cookie_assistant=assistant, + use_secure_connection=use_secure_connection ) def string(self): diff --git a/pyinjective/utils/fetch_metadata.py b/pyinjective/utils/fetch_metadata.py index ef81cef0..68269b74 100644 --- a/pyinjective/utils/fetch_metadata.py +++ b/pyinjective/utils/fetch_metadata.py @@ -28,7 +28,7 @@ async def fetch_denom(network) -> str: symbols = {} # fetch meta data for spot markets - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) status = 'active' mresp = await client.get_spot_markets(market_status=status) for market in mresp.markets: @@ -55,7 +55,7 @@ async def fetch_denom(network) -> str: denom_output += config # fetch meta data for derivative markets - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) status = 'active' mresp = await client.get_derivative_markets(market_status=status) for market in mresp.markets: diff --git a/pyinjective/utils/metadata_validation.py b/pyinjective/utils/metadata_validation.py index 3ef03209..366aa0aa 100644 --- a/pyinjective/utils/metadata_validation.py +++ b/pyinjective/utils/metadata_validation.py @@ -4,12 +4,12 @@ import pyinjective.constant as constant from pyinjective.async_client import AsyncClient -from pyinjective.constant import Network +from pyinjective.core.network import Network from pyinjective.core.market import SpotMarket, DerivativeMarket, BinaryOptionMarket def find_metadata_inconsistencies(network: Network) -> Tuple[List[Any]]: - client = AsyncClient(network, insecure=False) + client = AsyncClient(network) ini_config = constant.CONFIGS[network.string()] spot_markets = asyncio.get_event_loop().run_until_complete(client.all_spot_markets()) diff --git a/setup.py b/setup.py index 69b8a244..ec5c78ae 100755 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ EMAIL = "achilleas@injectivelabs.com" AUTHOR = "Injective Labs" REQUIRES_PYTHON = ">=3.9" -VERSION = "0.8" +VERSION = "0.8.1" REQUIRED = [ "aiohttp", diff --git a/tests/core/test_message_based_transaction_fee_calculator.py b/tests/core/test_message_based_transaction_fee_calculator.py index 7525fe00..2c3c4441 100644 --- a/tests/core/test_message_based_transaction_fee_calculator.py +++ b/tests/core/test_message_based_transaction_fee_calculator.py @@ -18,7 +18,7 @@ class TestMessageBasedTransactionFeeCalculator: @pytest.mark.asyncio async def test_gas_fee_for_privileged_execute_contract_message(self): network = Network.testnet(node="sentry") - client = AsyncClient(network=network, insecure=False) + client = AsyncClient(network=network) composer = Composer(network=network.string()) calculator = MessageBasedTransactionFeeCalculator( client=client, @@ -40,7 +40,7 @@ async def test_gas_fee_for_privileged_execute_contract_message(self): @pytest.mark.asyncio async def test_gas_fee_for_execute_contract_message(self): network = Network.testnet(node="sentry") - client = AsyncClient(network=network, insecure=False) + client = AsyncClient(network=network) composer = Composer(network=network.string()) calculator = MessageBasedTransactionFeeCalculator( client=client, @@ -66,7 +66,7 @@ async def test_gas_fee_for_execute_contract_message(self): @pytest.mark.asyncio async def test_gas_fee_for_wasm_message(self): network = Network.testnet(node="sentry") - client = AsyncClient(network=network, insecure=False) + client = AsyncClient(network=network) composer = Composer(network=network.string()) calculator = MessageBasedTransactionFeeCalculator( client=client, @@ -88,7 +88,7 @@ async def test_gas_fee_for_wasm_message(self): @pytest.mark.asyncio async def test_gas_fee_for_governance_message(self): network = Network.testnet(node="sentry") - client = AsyncClient(network=network, insecure=False) + client = AsyncClient(network=network) composer = Composer(network=network.string()) calculator = MessageBasedTransactionFeeCalculator( client=client, @@ -110,7 +110,7 @@ async def test_gas_fee_for_governance_message(self): @pytest.mark.asyncio async def test_gas_fee_for_exchange_message(self): network = Network.testnet(node="sentry") - client = AsyncClient(network=network, insecure=False) + client = AsyncClient(network=network) composer = Composer(network=network.string()) calculator = MessageBasedTransactionFeeCalculator( client=client, @@ -141,7 +141,7 @@ async def test_gas_fee_for_exchange_message(self): @pytest.mark.asyncio async def test_gas_fee_for_msg_exec_message(self): network = Network.testnet(node="sentry") - client = AsyncClient(network=network, insecure=False) + client = AsyncClient(network=network) composer = Composer(network=network.string()) calculator = MessageBasedTransactionFeeCalculator( client=client, @@ -180,7 +180,7 @@ async def test_gas_fee_for_msg_exec_message(self): @pytest.mark.asyncio async def test_gas_fee_for_two_messages_in_one_transaction(self): network = Network.testnet(node="sentry") - client = AsyncClient(network=network, insecure=False) + client = AsyncClient(network=network) composer = Composer(network=network.string()) calculator = MessageBasedTransactionFeeCalculator( client=client, From c8d68eb6ed39759ec89d4f0a18991e995227e3a2 Mon Sep 17 00:00:00 2001 From: abel Date: Wed, 6 Sep 2023 00:37:05 -0300 Subject: [PATCH 40/40] (fix) Fixed error in the changelog inside the README file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 278b5f7b..381d3401 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ make tests * Moved the configuration to use a secure or insecure connection inside the Network class. The AsyncClient's `insecure` parameter is no longer used for anything and will be removed in the future. * Made the new load balanced bare-metal node the default one for mainnet (it is called `lb`). The legacy one (load balanced k8s node) is called `lb_k8s` -**0.8**(change before release) +**0.8** * Refactor Composer to be created with all the markets and tokens. The Composer now uses the real markets and tokens to convert human-readable values to chain format * The Composer can still be instantiated without markets and tokens. When markets and tokens are not provided the Composer loads the required information from the Denoms used in previous versions * Change in AsyncClient to be able to create Composer instances for the client network, markets and tokens