From 8abeb382d8378e54ac6ec4e715702159703911d8 Mon Sep 17 00:00:00 2001 From: abel Date: Fri, 18 Aug 2023 00:55:26 -0300 Subject: [PATCH 1/8] (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 2/8] (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 3/8] (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 4/8] (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 5/8] (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 6/8] (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 7/8] (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 8/8] (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 (