From d5666388af96f870b189ed030524814420bb5632 Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 20 Feb 2024 12:52:10 -0300 Subject: [PATCH 1/7] (feat) Added support for all chain exchange module queries. Included new example scripts for all the queries and unit tests. --- ...drawAddress.py => 1_SetWithdrawAddress.py} | 0 ...Reward.py => 2_WithdrawDelegatorReward.py} | 0 ...on.py => 3_WithdrawValidatorCommission.py} | 0 ...ommunityPool.py => 4_FundCommunityPool.py} | 0 .../1_ValidatorDistributionInfo.py | 0 .../2_ValidatorOutstandingRewards.py | 0 .../{ => query}/3_ValidatorCommission.py | 0 .../{ => query}/4_ValidatorSlashes.py | 0 .../{ => query}/5_DelegationRewards.py | 0 .../{ => query}/6_DelegationTotalRewards.py | 0 .../{ => query}/7_DelegatorValidators.py | 0 .../{ => query}/8_DelegatorWithdrawAddress.py | 0 .../{ => query}/9_CommunityPool.py | 0 .../10_MsgSubaccountTransfer.py} | 0 .../11_MsgBatchUpdateOrders.py} | 0 .../12_MsgRewardsOptOut.py} | 0 .../15_ExternalTransfer.py} | 0 .../16_MsgCreateBinaryOptionsLimitOrder.py} | 0 .../17_MsgCreateBinaryOptionsMarketOrder.py} | 0 .../18_MsgCancelBinaryOptionsOrder.py} | 0 .../19_MsgLiquidatePosition.py} | 0 .../1_MsgDeposit.py} | 0 .../3_MsgCreateSpotLimitOrder.py | 0 .../4_MsgCreateSpotMarketOrder.py | 0 .../{ => exchange}/5_MsgCancelSpotOrder.py | 0 .../6_MsgCreateDerivativeLimitOrder.py | 0 .../7_MsgCreateDerivativeMarketOrder.py | 0 .../8_MsgCancelDerivativeOrder.py | 0 .../9_MsgWithdraw.py} | 0 .../exchange/query/10_SpotMarkets.py | 22 + .../exchange/query/11_SpotMarket.py | 21 + .../exchange/query/12_FullSpotMarkets.py | 23 + .../exchange/query/13_FullSpotMarket.py | 22 + .../exchange/query/14_SpotOrderbook.py | 26 + .../exchange/query/15_TraderSpotOrders.py | 37 + .../query/16_AccountAddressSpotOrders.py | 35 + .../exchange/query/17_SpotOrdersByHashes.py | 38 + .../exchange/query/18_SubaccountOrders.py | 37 + .../query/19_TraderSpotTransientOrders.py | 37 + .../exchange/query/1_SubaccountDeposits.py | 34 + .../exchange/query/20_SpotMidPriceAndTOB.py | 21 + .../query/21_DerivativeMidPriceAndTOB.py | 21 + .../exchange/query/22_DerivativeOrderbook.py | 25 + .../query/23_TraderDerivativeOrders.py | 37 + .../24_AccountAddressDerivativeOrders.py | 35 + .../query/25_DerivativeOrdersByHashes.py | 38 + .../26_TraderDerivativeTransientOrders.py | 37 + .../exchange/query/27_DerivativeMarkets.py | 22 + .../exchange/query/28_DerivativeMarket.py | 21 + .../query/29_DerivativeMarketAddress.py | 21 + .../exchange/query/2_SubaccountDeposit.py | 34 + .../exchange/query/30_SubaccountTradeNonce.py | 36 + .../exchange/query/31_Positions.py | 19 + .../exchange/query/32_SubaccountPositions.py | 36 + .../query/33_SubaccountPossitionInMarket.py | 37 + ...34_SubaccountEffectivePossitionInMarket.py | 37 + .../exchange/query/35_PerpetualMarketInfo.py | 21 + .../query/36_ExpiryFuturesMarketInfo.py | 21 + .../query/37_PerpetualMarketFunding.py | 21 + .../query/38_SubaccountOrderMetadata.py | 36 + .../exchange/query/39_TradeRewardPoints.py | 34 + .../exchange/query/3_ExchangeBalances.py | 18 + .../query/40_PendingTradeRewardPoints.py | 34 + .../query/41_FeeDiscountAccountInfo.py | 34 + .../exchange/query/42_FeeDiscountSchedule.py | 19 + .../exchange/query/43_BalanceMismatches.py | 19 + .../query/44_BalanceWithBalanceHolds.py | 19 + .../query/45_FeeDiscountTierStatistics.py | 19 + .../exchange/query/46_MitoVaultInfos.py | 19 + .../query/47_QueryMarketIDFromVault.py | 19 + .../query/48_HistoricalTradeRecords.py | 21 + .../exchange/query/49_IsOptedOutOfRewards.py | 34 + .../exchange/query/4_AggregateVolume.py | 36 + .../query/50_OptedOutOfRewardsAccounts.py | 19 + .../exchange/query/51_MarketVolatility.py | 30 + .../exchange/query/52_BinaryOptionsMarkets.py | 19 + .../53_TraderDerivativeConditionalOrders.py | 37 + .../54_MarketAtomicExecutionFeeMultiplier.py | 21 + .../exchange/query/5_AggregateVolumes.py | 34 + .../exchange/query/6_AggregateMarketVolume.py | 21 + .../query/7_AggregateMarketVolumes.py | 21 + .../exchange/query/8_DenomDecimal.py | 19 + .../exchange/query/9_DenomDecimals.py | 19 + pyinjective/async_client.py | 393 +++ .../chain/grpc/chain_grpc_exchange_api.py | 572 ++++ .../configurable_exchange_query_servicer.py | 325 +++ .../grpc/test_chain_grpc_exchange_api.py | 2466 +++++++++++++++++ 87 files changed, 5229 insertions(+) rename examples/chain_client/distribution/{10_SetWithdrawAddress.py => 1_SetWithdrawAddress.py} (100%) rename examples/chain_client/distribution/{11_WithdrawDelegatorReward.py => 2_WithdrawDelegatorReward.py} (100%) rename examples/chain_client/distribution/{12_WithdrawValidatorCommission.py => 3_WithdrawValidatorCommission.py} (100%) rename examples/chain_client/distribution/{13_FundCommunityPool.py => 4_FundCommunityPool.py} (100%) rename examples/chain_client/distribution/{ => query}/1_ValidatorDistributionInfo.py (100%) rename examples/chain_client/distribution/{ => query}/2_ValidatorOutstandingRewards.py (100%) rename examples/chain_client/distribution/{ => query}/3_ValidatorCommission.py (100%) rename examples/chain_client/distribution/{ => query}/4_ValidatorSlashes.py (100%) rename examples/chain_client/distribution/{ => query}/5_DelegationRewards.py (100%) rename examples/chain_client/distribution/{ => query}/6_DelegationTotalRewards.py (100%) rename examples/chain_client/distribution/{ => query}/7_DelegatorValidators.py (100%) rename examples/chain_client/distribution/{ => query}/8_DelegatorWithdrawAddress.py (100%) rename examples/chain_client/distribution/{ => query}/9_CommunityPool.py (100%) rename examples/chain_client/{16_MsgSubaccountTransfer.py => exchange/10_MsgSubaccountTransfer.py} (100%) rename examples/chain_client/{17_MsgBatchUpdateOrders.py => exchange/11_MsgBatchUpdateOrders.py} (100%) rename examples/chain_client/{24_MsgRewardsOptOut.py => exchange/12_MsgRewardsOptOut.py} (100%) rename examples/chain_client/{30_ExternalTransfer.py => exchange/15_ExternalTransfer.py} (100%) rename examples/chain_client/{31_MsgCreateBinaryOptionsLimitOrder.py => exchange/16_MsgCreateBinaryOptionsLimitOrder.py} (100%) rename examples/chain_client/{32_MsgCreateBinaryOptionsMarketOrder.py => exchange/17_MsgCreateBinaryOptionsMarketOrder.py} (100%) rename examples/chain_client/{33_MsgCancelBinaryOptionsOrder.py => exchange/18_MsgCancelBinaryOptionsOrder.py} (100%) rename examples/chain_client/{77_MsgLiquidatePosition.py => exchange/19_MsgLiquidatePosition.py} (100%) rename examples/chain_client/{2_MsgDeposit.py => exchange/1_MsgDeposit.py} (100%) rename examples/chain_client/{ => exchange}/3_MsgCreateSpotLimitOrder.py (100%) rename examples/chain_client/{ => exchange}/4_MsgCreateSpotMarketOrder.py (100%) rename examples/chain_client/{ => exchange}/5_MsgCancelSpotOrder.py (100%) rename examples/chain_client/{ => exchange}/6_MsgCreateDerivativeLimitOrder.py (100%) rename examples/chain_client/{ => exchange}/7_MsgCreateDerivativeMarketOrder.py (100%) rename examples/chain_client/{ => exchange}/8_MsgCancelDerivativeOrder.py (100%) rename examples/chain_client/{15_MsgWithdraw.py => exchange/9_MsgWithdraw.py} (100%) create mode 100644 examples/chain_client/exchange/query/10_SpotMarkets.py create mode 100644 examples/chain_client/exchange/query/11_SpotMarket.py create mode 100644 examples/chain_client/exchange/query/12_FullSpotMarkets.py create mode 100644 examples/chain_client/exchange/query/13_FullSpotMarket.py create mode 100644 examples/chain_client/exchange/query/14_SpotOrderbook.py create mode 100644 examples/chain_client/exchange/query/15_TraderSpotOrders.py create mode 100644 examples/chain_client/exchange/query/16_AccountAddressSpotOrders.py create mode 100644 examples/chain_client/exchange/query/17_SpotOrdersByHashes.py create mode 100644 examples/chain_client/exchange/query/18_SubaccountOrders.py create mode 100644 examples/chain_client/exchange/query/19_TraderSpotTransientOrders.py create mode 100644 examples/chain_client/exchange/query/1_SubaccountDeposits.py create mode 100644 examples/chain_client/exchange/query/20_SpotMidPriceAndTOB.py create mode 100644 examples/chain_client/exchange/query/21_DerivativeMidPriceAndTOB.py create mode 100644 examples/chain_client/exchange/query/22_DerivativeOrderbook.py create mode 100644 examples/chain_client/exchange/query/23_TraderDerivativeOrders.py create mode 100644 examples/chain_client/exchange/query/24_AccountAddressDerivativeOrders.py create mode 100644 examples/chain_client/exchange/query/25_DerivativeOrdersByHashes.py create mode 100644 examples/chain_client/exchange/query/26_TraderDerivativeTransientOrders.py create mode 100644 examples/chain_client/exchange/query/27_DerivativeMarkets.py create mode 100644 examples/chain_client/exchange/query/28_DerivativeMarket.py create mode 100644 examples/chain_client/exchange/query/29_DerivativeMarketAddress.py create mode 100644 examples/chain_client/exchange/query/2_SubaccountDeposit.py create mode 100644 examples/chain_client/exchange/query/30_SubaccountTradeNonce.py create mode 100644 examples/chain_client/exchange/query/31_Positions.py create mode 100644 examples/chain_client/exchange/query/32_SubaccountPositions.py create mode 100644 examples/chain_client/exchange/query/33_SubaccountPossitionInMarket.py create mode 100644 examples/chain_client/exchange/query/34_SubaccountEffectivePossitionInMarket.py create mode 100644 examples/chain_client/exchange/query/35_PerpetualMarketInfo.py create mode 100644 examples/chain_client/exchange/query/36_ExpiryFuturesMarketInfo.py create mode 100644 examples/chain_client/exchange/query/37_PerpetualMarketFunding.py create mode 100644 examples/chain_client/exchange/query/38_SubaccountOrderMetadata.py create mode 100644 examples/chain_client/exchange/query/39_TradeRewardPoints.py create mode 100644 examples/chain_client/exchange/query/3_ExchangeBalances.py create mode 100644 examples/chain_client/exchange/query/40_PendingTradeRewardPoints.py create mode 100644 examples/chain_client/exchange/query/41_FeeDiscountAccountInfo.py create mode 100644 examples/chain_client/exchange/query/42_FeeDiscountSchedule.py create mode 100644 examples/chain_client/exchange/query/43_BalanceMismatches.py create mode 100644 examples/chain_client/exchange/query/44_BalanceWithBalanceHolds.py create mode 100644 examples/chain_client/exchange/query/45_FeeDiscountTierStatistics.py create mode 100644 examples/chain_client/exchange/query/46_MitoVaultInfos.py create mode 100644 examples/chain_client/exchange/query/47_QueryMarketIDFromVault.py create mode 100644 examples/chain_client/exchange/query/48_HistoricalTradeRecords.py create mode 100644 examples/chain_client/exchange/query/49_IsOptedOutOfRewards.py create mode 100644 examples/chain_client/exchange/query/4_AggregateVolume.py create mode 100644 examples/chain_client/exchange/query/50_OptedOutOfRewardsAccounts.py create mode 100644 examples/chain_client/exchange/query/51_MarketVolatility.py create mode 100644 examples/chain_client/exchange/query/52_BinaryOptionsMarkets.py create mode 100644 examples/chain_client/exchange/query/53_TraderDerivativeConditionalOrders.py create mode 100644 examples/chain_client/exchange/query/54_MarketAtomicExecutionFeeMultiplier.py create mode 100644 examples/chain_client/exchange/query/5_AggregateVolumes.py create mode 100644 examples/chain_client/exchange/query/6_AggregateMarketVolume.py create mode 100644 examples/chain_client/exchange/query/7_AggregateMarketVolumes.py create mode 100644 examples/chain_client/exchange/query/8_DenomDecimal.py create mode 100644 examples/chain_client/exchange/query/9_DenomDecimals.py create mode 100644 pyinjective/client/chain/grpc/chain_grpc_exchange_api.py create mode 100644 tests/client/chain/grpc/configurable_exchange_query_servicer.py create mode 100644 tests/client/chain/grpc/test_chain_grpc_exchange_api.py diff --git a/examples/chain_client/distribution/10_SetWithdrawAddress.py b/examples/chain_client/distribution/1_SetWithdrawAddress.py similarity index 100% rename from examples/chain_client/distribution/10_SetWithdrawAddress.py rename to examples/chain_client/distribution/1_SetWithdrawAddress.py diff --git a/examples/chain_client/distribution/11_WithdrawDelegatorReward.py b/examples/chain_client/distribution/2_WithdrawDelegatorReward.py similarity index 100% rename from examples/chain_client/distribution/11_WithdrawDelegatorReward.py rename to examples/chain_client/distribution/2_WithdrawDelegatorReward.py diff --git a/examples/chain_client/distribution/12_WithdrawValidatorCommission.py b/examples/chain_client/distribution/3_WithdrawValidatorCommission.py similarity index 100% rename from examples/chain_client/distribution/12_WithdrawValidatorCommission.py rename to examples/chain_client/distribution/3_WithdrawValidatorCommission.py diff --git a/examples/chain_client/distribution/13_FundCommunityPool.py b/examples/chain_client/distribution/4_FundCommunityPool.py similarity index 100% rename from examples/chain_client/distribution/13_FundCommunityPool.py rename to examples/chain_client/distribution/4_FundCommunityPool.py diff --git a/examples/chain_client/distribution/1_ValidatorDistributionInfo.py b/examples/chain_client/distribution/query/1_ValidatorDistributionInfo.py similarity index 100% rename from examples/chain_client/distribution/1_ValidatorDistributionInfo.py rename to examples/chain_client/distribution/query/1_ValidatorDistributionInfo.py diff --git a/examples/chain_client/distribution/2_ValidatorOutstandingRewards.py b/examples/chain_client/distribution/query/2_ValidatorOutstandingRewards.py similarity index 100% rename from examples/chain_client/distribution/2_ValidatorOutstandingRewards.py rename to examples/chain_client/distribution/query/2_ValidatorOutstandingRewards.py diff --git a/examples/chain_client/distribution/3_ValidatorCommission.py b/examples/chain_client/distribution/query/3_ValidatorCommission.py similarity index 100% rename from examples/chain_client/distribution/3_ValidatorCommission.py rename to examples/chain_client/distribution/query/3_ValidatorCommission.py diff --git a/examples/chain_client/distribution/4_ValidatorSlashes.py b/examples/chain_client/distribution/query/4_ValidatorSlashes.py similarity index 100% rename from examples/chain_client/distribution/4_ValidatorSlashes.py rename to examples/chain_client/distribution/query/4_ValidatorSlashes.py diff --git a/examples/chain_client/distribution/5_DelegationRewards.py b/examples/chain_client/distribution/query/5_DelegationRewards.py similarity index 100% rename from examples/chain_client/distribution/5_DelegationRewards.py rename to examples/chain_client/distribution/query/5_DelegationRewards.py diff --git a/examples/chain_client/distribution/6_DelegationTotalRewards.py b/examples/chain_client/distribution/query/6_DelegationTotalRewards.py similarity index 100% rename from examples/chain_client/distribution/6_DelegationTotalRewards.py rename to examples/chain_client/distribution/query/6_DelegationTotalRewards.py diff --git a/examples/chain_client/distribution/7_DelegatorValidators.py b/examples/chain_client/distribution/query/7_DelegatorValidators.py similarity index 100% rename from examples/chain_client/distribution/7_DelegatorValidators.py rename to examples/chain_client/distribution/query/7_DelegatorValidators.py diff --git a/examples/chain_client/distribution/8_DelegatorWithdrawAddress.py b/examples/chain_client/distribution/query/8_DelegatorWithdrawAddress.py similarity index 100% rename from examples/chain_client/distribution/8_DelegatorWithdrawAddress.py rename to examples/chain_client/distribution/query/8_DelegatorWithdrawAddress.py diff --git a/examples/chain_client/distribution/9_CommunityPool.py b/examples/chain_client/distribution/query/9_CommunityPool.py similarity index 100% rename from examples/chain_client/distribution/9_CommunityPool.py rename to examples/chain_client/distribution/query/9_CommunityPool.py diff --git a/examples/chain_client/16_MsgSubaccountTransfer.py b/examples/chain_client/exchange/10_MsgSubaccountTransfer.py similarity index 100% rename from examples/chain_client/16_MsgSubaccountTransfer.py rename to examples/chain_client/exchange/10_MsgSubaccountTransfer.py diff --git a/examples/chain_client/17_MsgBatchUpdateOrders.py b/examples/chain_client/exchange/11_MsgBatchUpdateOrders.py similarity index 100% rename from examples/chain_client/17_MsgBatchUpdateOrders.py rename to examples/chain_client/exchange/11_MsgBatchUpdateOrders.py diff --git a/examples/chain_client/24_MsgRewardsOptOut.py b/examples/chain_client/exchange/12_MsgRewardsOptOut.py similarity index 100% rename from examples/chain_client/24_MsgRewardsOptOut.py rename to examples/chain_client/exchange/12_MsgRewardsOptOut.py diff --git a/examples/chain_client/30_ExternalTransfer.py b/examples/chain_client/exchange/15_ExternalTransfer.py similarity index 100% rename from examples/chain_client/30_ExternalTransfer.py rename to examples/chain_client/exchange/15_ExternalTransfer.py diff --git a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py b/examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py similarity index 100% rename from examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py rename to examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py diff --git a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py b/examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py similarity index 100% rename from examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py rename to examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py diff --git a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py b/examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py similarity index 100% rename from examples/chain_client/33_MsgCancelBinaryOptionsOrder.py rename to examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py diff --git a/examples/chain_client/77_MsgLiquidatePosition.py b/examples/chain_client/exchange/19_MsgLiquidatePosition.py similarity index 100% rename from examples/chain_client/77_MsgLiquidatePosition.py rename to examples/chain_client/exchange/19_MsgLiquidatePosition.py diff --git a/examples/chain_client/2_MsgDeposit.py b/examples/chain_client/exchange/1_MsgDeposit.py similarity index 100% rename from examples/chain_client/2_MsgDeposit.py rename to examples/chain_client/exchange/1_MsgDeposit.py diff --git a/examples/chain_client/3_MsgCreateSpotLimitOrder.py b/examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py similarity index 100% rename from examples/chain_client/3_MsgCreateSpotLimitOrder.py rename to examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py diff --git a/examples/chain_client/4_MsgCreateSpotMarketOrder.py b/examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py similarity index 100% rename from examples/chain_client/4_MsgCreateSpotMarketOrder.py rename to examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py diff --git a/examples/chain_client/5_MsgCancelSpotOrder.py b/examples/chain_client/exchange/5_MsgCancelSpotOrder.py similarity index 100% rename from examples/chain_client/5_MsgCancelSpotOrder.py rename to examples/chain_client/exchange/5_MsgCancelSpotOrder.py diff --git a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py similarity index 100% rename from examples/chain_client/6_MsgCreateDerivativeLimitOrder.py rename to examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py diff --git a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py b/examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py similarity index 100% rename from examples/chain_client/7_MsgCreateDerivativeMarketOrder.py rename to examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py diff --git a/examples/chain_client/8_MsgCancelDerivativeOrder.py b/examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py similarity index 100% rename from examples/chain_client/8_MsgCancelDerivativeOrder.py rename to examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py diff --git a/examples/chain_client/15_MsgWithdraw.py b/examples/chain_client/exchange/9_MsgWithdraw.py similarity index 100% rename from examples/chain_client/15_MsgWithdraw.py rename to examples/chain_client/exchange/9_MsgWithdraw.py diff --git a/examples/chain_client/exchange/query/10_SpotMarkets.py b/examples/chain_client/exchange/query/10_SpotMarkets.py new file mode 100644 index 00000000..4cedc9d7 --- /dev/null +++ b/examples/chain_client/exchange/query/10_SpotMarkets.py @@ -0,0 +1,22 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + spot_markets = await client.fetch_chain_spot_markets( + status="Active", + market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"], + ) + print(spot_markets) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/11_SpotMarket.py b/examples/chain_client/exchange/query/11_SpotMarket.py new file mode 100644 index 00000000..0e774edf --- /dev/null +++ b/examples/chain_client/exchange/query/11_SpotMarket.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + spot_market = await client.fetch_chain_spot_market( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + print(spot_market) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/12_FullSpotMarkets.py b/examples/chain_client/exchange/query/12_FullSpotMarkets.py new file mode 100644 index 00000000..cfefee28 --- /dev/null +++ b/examples/chain_client/exchange/query/12_FullSpotMarkets.py @@ -0,0 +1,23 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + spot_markets = await client.fetch_chain_full_spot_markets( + status="Active", + market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"], + with_mid_price_and_tob=True, + ) + print(spot_markets) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/13_FullSpotMarket.py b/examples/chain_client/exchange/query/13_FullSpotMarket.py new file mode 100644 index 00000000..6a39269d --- /dev/null +++ b/examples/chain_client/exchange/query/13_FullSpotMarket.py @@ -0,0 +1,22 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + spot_market = await client.fetch_chain_full_spot_market( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + with_mid_price_and_tob=True, + ) + print(spot_market) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/14_SpotOrderbook.py b/examples/chain_client/exchange/query/14_SpotOrderbook.py new file mode 100644 index 00000000..7b5a9aa1 --- /dev/null +++ b/examples/chain_client/exchange/query/14_SpotOrderbook.py @@ -0,0 +1,26 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + pagination = PaginationOption(limit=2) + + orderbook = await client.fetch_chain_spot_orderbook( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + order_side="Buy", + pagination=pagination, + ) + print(orderbook) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/15_TraderSpotOrders.py b/examples/chain_client/exchange/query/15_TraderSpotOrders.py new file mode 100644 index 00000000..0cc96b6f --- /dev/null +++ b/examples/chain_client/exchange/query/15_TraderSpotOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_trader_spot_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id=subaccount_id, + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/16_AccountAddressSpotOrders.py b/examples/chain_client/exchange/query/16_AccountAddressSpotOrders.py new file mode 100644 index 00000000..8e50fa95 --- /dev/null +++ b/examples/chain_client/exchange/query/16_AccountAddressSpotOrders.py @@ -0,0 +1,35 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + orders = await client.fetch_chain_account_address_spot_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + account_address=address.to_acc_bech32(), + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/17_SpotOrdersByHashes.py b/examples/chain_client/exchange/query/17_SpotOrdersByHashes.py new file mode 100644 index 00000000..641eb6f5 --- /dev/null +++ b/examples/chain_client/exchange/query/17_SpotOrdersByHashes.py @@ -0,0 +1,38 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_spot_orders_by_hashes( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id=subaccount_id, + order_hashes=["0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"], + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/18_SubaccountOrders.py b/examples/chain_client/exchange/query/18_SubaccountOrders.py new file mode 100644 index 00000000..4983f827 --- /dev/null +++ b/examples/chain_client/exchange/query/18_SubaccountOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_subaccount_orders( + subaccount_id=subaccount_id, + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/19_TraderSpotTransientOrders.py b/examples/chain_client/exchange/query/19_TraderSpotTransientOrders.py new file mode 100644 index 00000000..2b29c2c0 --- /dev/null +++ b/examples/chain_client/exchange/query/19_TraderSpotTransientOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_trader_spot_transient_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id=subaccount_id, + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/1_SubaccountDeposits.py b/examples/chain_client/exchange/query/1_SubaccountDeposits.py new file mode 100644 index 00000000..f9afb8ae --- /dev/null +++ b/examples/chain_client/exchange/query/1_SubaccountDeposits.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + deposits = await client.fetch_subaccount_deposits(subaccount_id=subaccount_id) + print(deposits) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/20_SpotMidPriceAndTOB.py b/examples/chain_client/exchange/query/20_SpotMidPriceAndTOB.py new file mode 100644 index 00000000..35493ffd --- /dev/null +++ b/examples/chain_client/exchange/query/20_SpotMidPriceAndTOB.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + prices = await client.fetch_spot_mid_price_and_tob( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + print(prices) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/21_DerivativeMidPriceAndTOB.py b/examples/chain_client/exchange/query/21_DerivativeMidPriceAndTOB.py new file mode 100644 index 00000000..5b5c5fff --- /dev/null +++ b/examples/chain_client/exchange/query/21_DerivativeMidPriceAndTOB.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + prices = await client.fetch_derivative_mid_price_and_tob( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(prices) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/22_DerivativeOrderbook.py b/examples/chain_client/exchange/query/22_DerivativeOrderbook.py new file mode 100644 index 00000000..465a62b6 --- /dev/null +++ b/examples/chain_client/exchange/query/22_DerivativeOrderbook.py @@ -0,0 +1,25 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + pagination = PaginationOption(limit=2) + + orderbook = await client.fetch_chain_derivative_orderbook( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + pagination=pagination, + ) + print(orderbook) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/23_TraderDerivativeOrders.py b/examples/chain_client/exchange/query/23_TraderDerivativeOrders.py new file mode 100644 index 00000000..61e98ba1 --- /dev/null +++ b/examples/chain_client/exchange/query/23_TraderDerivativeOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_trader_spot_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id=subaccount_id, + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/24_AccountAddressDerivativeOrders.py b/examples/chain_client/exchange/query/24_AccountAddressDerivativeOrders.py new file mode 100644 index 00000000..469c99fb --- /dev/null +++ b/examples/chain_client/exchange/query/24_AccountAddressDerivativeOrders.py @@ -0,0 +1,35 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + orders = await client.fetch_chain_account_address_spot_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + account_address=address.to_acc_bech32(), + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/25_DerivativeOrdersByHashes.py b/examples/chain_client/exchange/query/25_DerivativeOrdersByHashes.py new file mode 100644 index 00000000..ea700e6d --- /dev/null +++ b/examples/chain_client/exchange/query/25_DerivativeOrdersByHashes.py @@ -0,0 +1,38 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_spot_orders_by_hashes( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id=subaccount_id, + order_hashes=["0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"], + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/26_TraderDerivativeTransientOrders.py b/examples/chain_client/exchange/query/26_TraderDerivativeTransientOrders.py new file mode 100644 index 00000000..c5548d59 --- /dev/null +++ b/examples/chain_client/exchange/query/26_TraderDerivativeTransientOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_trader_derivative_transient_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id=subaccount_id, + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/27_DerivativeMarkets.py b/examples/chain_client/exchange/query/27_DerivativeMarkets.py new file mode 100644 index 00000000..2f4bbc5a --- /dev/null +++ b/examples/chain_client/exchange/query/27_DerivativeMarkets.py @@ -0,0 +1,22 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + derivative_markets = await client.fetch_chain_derivative_markets( + status="Active", + market_ids=["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"], + ) + print(derivative_markets) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/28_DerivativeMarket.py b/examples/chain_client/exchange/query/28_DerivativeMarket.py new file mode 100644 index 00000000..152381f5 --- /dev/null +++ b/examples/chain_client/exchange/query/28_DerivativeMarket.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + derivative_market = await client.fetch_chain_derivative_market( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(derivative_market) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/29_DerivativeMarketAddress.py b/examples/chain_client/exchange/query/29_DerivativeMarketAddress.py new file mode 100644 index 00000000..c2d88805 --- /dev/null +++ b/examples/chain_client/exchange/query/29_DerivativeMarketAddress.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + address = await client.fetch_derivative_market_address( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(address) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/2_SubaccountDeposit.py b/examples/chain_client/exchange/query/2_SubaccountDeposit.py new file mode 100644 index 00000000..5002397d --- /dev/null +++ b/examples/chain_client/exchange/query/2_SubaccountDeposit.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + deposit = await client.fetch_subaccount_deposit(subaccount_id=subaccount_id, denom="inj") + print(deposit) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/30_SubaccountTradeNonce.py b/examples/chain_client/exchange/query/30_SubaccountTradeNonce.py new file mode 100644 index 00000000..ad81aca3 --- /dev/null +++ b/examples/chain_client/exchange/query/30_SubaccountTradeNonce.py @@ -0,0 +1,36 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + nonce = await client.fetch_subaccount_trade_nonce( + subaccount_id=subaccount_id, + ) + print(nonce) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/31_Positions.py b/examples/chain_client/exchange/query/31_Positions.py new file mode 100644 index 00000000..ae494b6a --- /dev/null +++ b/examples/chain_client/exchange/query/31_Positions.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + positions = await client.fetch_chain_positions() + print(positions) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/32_SubaccountPositions.py b/examples/chain_client/exchange/query/32_SubaccountPositions.py new file mode 100644 index 00000000..000d95b6 --- /dev/null +++ b/examples/chain_client/exchange/query/32_SubaccountPositions.py @@ -0,0 +1,36 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + positions = await client.fetch_chain_subaccount_positions( + subaccount_id=subaccount_id, + ) + print(positions) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/33_SubaccountPossitionInMarket.py b/examples/chain_client/exchange/query/33_SubaccountPossitionInMarket.py new file mode 100644 index 00000000..4e0f1ddb --- /dev/null +++ b/examples/chain_client/exchange/query/33_SubaccountPossitionInMarket.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + position = await client.fetch_chain_subaccount_position_in_market( + subaccount_id=subaccount_id, + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(position) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/34_SubaccountEffectivePossitionInMarket.py b/examples/chain_client/exchange/query/34_SubaccountEffectivePossitionInMarket.py new file mode 100644 index 00000000..e729e77c --- /dev/null +++ b/examples/chain_client/exchange/query/34_SubaccountEffectivePossitionInMarket.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + position = await client.fetch_chain_subaccount_effective_position_in_market( + subaccount_id=subaccount_id, + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(position) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/35_PerpetualMarketInfo.py b/examples/chain_client/exchange/query/35_PerpetualMarketInfo.py new file mode 100644 index 00000000..ca27f552 --- /dev/null +++ b/examples/chain_client/exchange/query/35_PerpetualMarketInfo.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_info = await client.fetch_chain_perpetual_market_info( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(market_info) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/36_ExpiryFuturesMarketInfo.py b/examples/chain_client/exchange/query/36_ExpiryFuturesMarketInfo.py new file mode 100644 index 00000000..4053013c --- /dev/null +++ b/examples/chain_client/exchange/query/36_ExpiryFuturesMarketInfo.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_info = await client.fetch_chain_expiry_futures_market_info( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(market_info) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/37_PerpetualMarketFunding.py b/examples/chain_client/exchange/query/37_PerpetualMarketFunding.py new file mode 100644 index 00000000..099c2a0f --- /dev/null +++ b/examples/chain_client/exchange/query/37_PerpetualMarketFunding.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + funding = await client.fetch_chain_perpetual_market_funding( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(funding) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/38_SubaccountOrderMetadata.py b/examples/chain_client/exchange/query/38_SubaccountOrderMetadata.py new file mode 100644 index 00000000..f4af9d38 --- /dev/null +++ b/examples/chain_client/exchange/query/38_SubaccountOrderMetadata.py @@ -0,0 +1,36 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + metadata = await client.fetch_subaccount_order_metadata( + subaccount_id=subaccount_id, + ) + print(metadata) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/39_TradeRewardPoints.py b/examples/chain_client/exchange/query/39_TradeRewardPoints.py new file mode 100644 index 00000000..13f08730 --- /dev/null +++ b/examples/chain_client/exchange/query/39_TradeRewardPoints.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + points = await client.fetch_trade_reward_points( + accounts=[address.to_acc_bech32()], + ) + print(points) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/3_ExchangeBalances.py b/examples/chain_client/exchange/query/3_ExchangeBalances.py new file mode 100644 index 00000000..091bf10c --- /dev/null +++ b/examples/chain_client/exchange/query/3_ExchangeBalances.py @@ -0,0 +1,18 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + # initialize grpc client + client = AsyncClient(network) + + balances = await client.fetch_exchange_balances() + print(balances) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/40_PendingTradeRewardPoints.py b/examples/chain_client/exchange/query/40_PendingTradeRewardPoints.py new file mode 100644 index 00000000..fa3e8aa2 --- /dev/null +++ b/examples/chain_client/exchange/query/40_PendingTradeRewardPoints.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + points = await client.fetch_pending_trade_reward_points( + accounts=[address.to_acc_bech32()], + ) + print(points) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/41_FeeDiscountAccountInfo.py b/examples/chain_client/exchange/query/41_FeeDiscountAccountInfo.py new file mode 100644 index 00000000..15fbb7ce --- /dev/null +++ b/examples/chain_client/exchange/query/41_FeeDiscountAccountInfo.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + fee_discount = await client.fetch_fee_discount_account_info( + account=address.to_acc_bech32(), + ) + print(fee_discount) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/42_FeeDiscountSchedule.py b/examples/chain_client/exchange/query/42_FeeDiscountSchedule.py new file mode 100644 index 00000000..a0ae96cb --- /dev/null +++ b/examples/chain_client/exchange/query/42_FeeDiscountSchedule.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + schedule = await client.fetch_fee_discount_schedule() + print(schedule) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/43_BalanceMismatches.py b/examples/chain_client/exchange/query/43_BalanceMismatches.py new file mode 100644 index 00000000..c7f7ca5e --- /dev/null +++ b/examples/chain_client/exchange/query/43_BalanceMismatches.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + mismatches = await client.fetch_balance_mismatches(dust_factor=1) + print(mismatches) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/44_BalanceWithBalanceHolds.py b/examples/chain_client/exchange/query/44_BalanceWithBalanceHolds.py new file mode 100644 index 00000000..6587c59a --- /dev/null +++ b/examples/chain_client/exchange/query/44_BalanceWithBalanceHolds.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + balance = await client.fetch_balance_with_balance_holds() + print(balance) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/45_FeeDiscountTierStatistics.py b/examples/chain_client/exchange/query/45_FeeDiscountTierStatistics.py new file mode 100644 index 00000000..5671e4ce --- /dev/null +++ b/examples/chain_client/exchange/query/45_FeeDiscountTierStatistics.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + statistics = await client.fetch_fee_discount_tier_statistics() + print(statistics) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/46_MitoVaultInfos.py b/examples/chain_client/exchange/query/46_MitoVaultInfos.py new file mode 100644 index 00000000..3faa5cb9 --- /dev/null +++ b/examples/chain_client/exchange/query/46_MitoVaultInfos.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + infos = await client.fetch_mito_vault_infos() + print(infos) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/47_QueryMarketIDFromVault.py b/examples/chain_client/exchange/query/47_QueryMarketIDFromVault.py new file mode 100644 index 00000000..e699dbaa --- /dev/null +++ b/examples/chain_client/exchange/query/47_QueryMarketIDFromVault.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_id = await client.fetch_market_id_from_vault(vault_address="inj1qg5ega6dykkxc307y25pecuufrjkxkag6xhp6y") + print(market_id) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/48_HistoricalTradeRecords.py b/examples/chain_client/exchange/query/48_HistoricalTradeRecords.py new file mode 100644 index 00000000..6b93200f --- /dev/null +++ b/examples/chain_client/exchange/query/48_HistoricalTradeRecords.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + records = await client.fetch_historical_trade_records( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + ) + print(records) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/49_IsOptedOutOfRewards.py b/examples/chain_client/exchange/query/49_IsOptedOutOfRewards.py new file mode 100644 index 00000000..28c0925c --- /dev/null +++ b/examples/chain_client/exchange/query/49_IsOptedOutOfRewards.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + is_opted_out = await client.fetch_is_opted_out_of_rewards( + account=address.to_acc_bech32(), + ) + print(is_opted_out) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/4_AggregateVolume.py b/examples/chain_client/exchange/query/4_AggregateVolume.py new file mode 100644 index 00000000..35c334a5 --- /dev/null +++ b/examples/chain_client/exchange/query/4_AggregateVolume.py @@ -0,0 +1,36 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + + subaccount_id = address.get_subaccount_id(index=0) + + volume = await client.fetch_aggregate_volume(account=address.to_acc_bech32()) + print(volume) + + volume = await client.fetch_aggregate_volume(account=subaccount_id) + print(volume) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/50_OptedOutOfRewardsAccounts.py b/examples/chain_client/exchange/query/50_OptedOutOfRewardsAccounts.py new file mode 100644 index 00000000..9940f799 --- /dev/null +++ b/examples/chain_client/exchange/query/50_OptedOutOfRewardsAccounts.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + opted_out = await client.fetch_opted_out_of_rewards_accounts() + print(opted_out) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/51_MarketVolatility.py b/examples/chain_client/exchange/query/51_MarketVolatility.py new file mode 100644 index 00000000..3173ca39 --- /dev/null +++ b/examples/chain_client/exchange/query/51_MarketVolatility.py @@ -0,0 +1,30 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + trade_grouping_sec = 10 + max_age = 0 + include_raw_history = True + include_metadata = True + volatility = await client.fetch_market_volatility( + market_id=market_id, + trade_grouping_sec=trade_grouping_sec, + max_age=max_age, + include_raw_history=include_raw_history, + include_metadata=include_metadata, + ) + print(volatility) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/52_BinaryOptionsMarkets.py b/examples/chain_client/exchange/query/52_BinaryOptionsMarkets.py new file mode 100644 index 00000000..4448a4ec --- /dev/null +++ b/examples/chain_client/exchange/query/52_BinaryOptionsMarkets.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + markets = await client.fetch_chain_binary_options_markets(status="Active") + print(markets) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/53_TraderDerivativeConditionalOrders.py b/examples/chain_client/exchange/query/53_TraderDerivativeConditionalOrders.py new file mode 100644 index 00000000..fd65e68f --- /dev/null +++ b/examples/chain_client/exchange/query/53_TraderDerivativeConditionalOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_trader_derivative_conditional_orders( + subaccount_id=subaccount_id, + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/54_MarketAtomicExecutionFeeMultiplier.py b/examples/chain_client/exchange/query/54_MarketAtomicExecutionFeeMultiplier.py new file mode 100644 index 00000000..328028d3 --- /dev/null +++ b/examples/chain_client/exchange/query/54_MarketAtomicExecutionFeeMultiplier.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + multiplier = await client.fetch_market_atomic_execution_fee_multiplier( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(multiplier) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/5_AggregateVolumes.py b/examples/chain_client/exchange/query/5_AggregateVolumes.py new file mode 100644 index 00000000..6effe4be --- /dev/null +++ b/examples/chain_client/exchange/query/5_AggregateVolumes.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + + volume = await client.fetch_aggregate_volumes( + accounts=[address.to_acc_bech32()], + market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"], + ) + print(volume) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/6_AggregateMarketVolume.py b/examples/chain_client/exchange/query/6_AggregateMarketVolume.py new file mode 100644 index 00000000..b3262d82 --- /dev/null +++ b/examples/chain_client/exchange/query/6_AggregateMarketVolume.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + + volume = await client.fetch_aggregate_market_volume(market_id=market_id) + print(volume) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/7_AggregateMarketVolumes.py b/examples/chain_client/exchange/query/7_AggregateMarketVolumes.py new file mode 100644 index 00000000..23dfa0ec --- /dev/null +++ b/examples/chain_client/exchange/query/7_AggregateMarketVolumes.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + volume = await client.fetch_aggregate_market_volumes( + market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"], + ) + print(volume) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/8_DenomDecimal.py b/examples/chain_client/exchange/query/8_DenomDecimal.py new file mode 100644 index 00000000..2079f5e8 --- /dev/null +++ b/examples/chain_client/exchange/query/8_DenomDecimal.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + deposits = await client.fetch_denom_decimal(denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5") + print(deposits) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/9_DenomDecimals.py b/examples/chain_client/exchange/query/9_DenomDecimals.py new file mode 100644 index 00000000..d96df30b --- /dev/null +++ b/examples/chain_client/exchange/query/9_DenomDecimals.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + deposits = await client.fetch_denom_decimals(denoms=["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"]) + print(deposits) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index dea12f12..0af37da0 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -13,6 +13,7 @@ from pyinjective.client.chain.grpc.chain_grpc_authz_api import ChainGrpcAuthZApi from pyinjective.client.chain.grpc.chain_grpc_bank_api import ChainGrpcBankApi from pyinjective.client.chain.grpc.chain_grpc_distribution_api import ChainGrpcDistributionApi +from pyinjective.client.chain.grpc.chain_grpc_exchange_api import ChainGrpcExchangeApi from pyinjective.client.chain.grpc.chain_grpc_token_factory_api import ChainGrpcTokenFactoryApi from pyinjective.client.chain.grpc.chain_grpc_wasm_api import ChainGrpcWasmApi from pyinjective.client.chain.grpc_stream.chain_grpc_chain_stream import ChainGrpcChainStream @@ -185,6 +186,12 @@ def __init__( metadata_query_provider=self._chain_cookie_metadata_requestor ), ) + self.chain_exchange_api = ChainGrpcExchangeApi( + channel=self.chain_channel, + metadata_provider=lambda: self.network.chain_metadata( + metadata_query_provider=self._chain_cookie_metadata_requestor + ), + ) self.token_factory_api = ChainGrpcTokenFactoryApi( channel=self.chain_channel, metadata_provider=lambda: self.network.chain_metadata( @@ -639,6 +646,392 @@ async def fetch_delegator_withdraw_address( async def fetch_community_pool(self) -> Dict[str, Any]: return await self.distribution_api.fetch_community_pool() + # Exchange module + + async def fetch_subaccount_deposits( + self, + subaccount_id: Optional[str] = None, + subaccount_trader: Optional[str] = None, + subaccount_nonce: Optional[int] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_deposits( + subaccount_id=subaccount_id, + subaccount_trader=subaccount_trader, + subaccount_nonce=subaccount_nonce, + ) + + async def fetch_subaccount_deposit( + self, + subaccount_id: str, + denom: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_deposit( + subaccount_id=subaccount_id, + denom=denom, + ) + + async def fetch_exchange_balances(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_exchange_balances() + + async def fetch_aggregate_volume(self, account: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_aggregate_volume(account=account) + + async def fetch_aggregate_volumes( + self, + accounts: Optional[List[str]] = None, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_aggregate_volumes( + accounts=accounts, + market_ids=market_ids, + ) + + async def fetch_aggregate_market_volume( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_aggregate_market_volume( + market_id=market_id, + ) + + async def fetch_aggregate_market_volumes( + self, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_aggregate_market_volumes( + market_ids=market_ids, + ) + + async def fetch_denom_decimal(self, denom: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_denom_decimal(denom=denom) + + async def fetch_denom_decimals(self, denoms: Optional[List[str]] = None) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_denom_decimals(denoms=denoms) + + async def fetch_chain_spot_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_spot_markets( + status=status, + market_ids=market_ids, + ) + + async def fetch_chain_spot_market( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_spot_market( + market_id=market_id, + ) + + async def fetch_chain_full_spot_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_full_spot_markets( + status=status, + market_ids=market_ids, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + + async def fetch_chain_full_spot_market( + self, + market_id: str, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_full_spot_market( + market_id=market_id, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + + async def fetch_chain_spot_orderbook( + self, + market_id: str, + order_side: Optional[str] = None, + limit_cumulative_notional: Optional[str] = None, + limit_cumulative_quantity: Optional[str] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + # Order side could be "Side_Unspecified", "Buy", "Sell" + return await self.chain_exchange_api.fetch_spot_orderbook( + market_id=market_id, + order_side=order_side, + limit_cumulative_notional=limit_cumulative_notional, + limit_cumulative_quantity=limit_cumulative_quantity, + pagination=pagination, + ) + + async def fetch_chain_trader_spot_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_spot_orders( + market_id=market_id, + subaccount_id=subaccount_id, + ) + + async def fetch_chain_account_address_spot_orders( + self, + market_id: str, + account_address: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_account_address_spot_orders( + market_id=market_id, + account_address=account_address, + ) + + async def fetch_chain_spot_orders_by_hashes( + self, + market_id: str, + subaccount_id: str, + order_hashes: List[str], + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_spot_orders_by_hashes( + market_id=market_id, + subaccount_id=subaccount_id, + order_hashes=order_hashes, + ) + + async def fetch_chain_subaccount_orders( + self, + subaccount_id: str, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_orders( + subaccount_id=subaccount_id, + market_id=market_id, + ) + + async def fetch_chain_trader_spot_transient_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_spot_transient_orders( + market_id=market_id, + subaccount_id=subaccount_id, + ) + + async def fetch_spot_mid_price_and_tob( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_spot_mid_price_and_tob( + market_id=market_id, + ) + + async def fetch_derivative_mid_price_and_tob( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_mid_price_and_tob( + market_id=market_id, + ) + + async def fetch_chain_derivative_orderbook( + self, + market_id: str, + limit_cumulative_notional: Optional[str] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_orderbook( + market_id=market_id, + limit_cumulative_notional=limit_cumulative_notional, + pagination=pagination, + ) + + async def fetch_chain_trader_derivative_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_derivative_orders( + market_id=market_id, + subaccount_id=subaccount_id, + ) + + async def fetch_chain_account_address_derivative_orders( + self, + market_id: str, + account_address: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_account_address_derivative_orders( + market_id=market_id, + account_address=account_address, + ) + + async def fetch_chain_derivative_orders_by_hashes( + self, + market_id: str, + subaccount_id: str, + order_hashes: List[str], + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_orders_by_hashes( + market_id=market_id, + subaccount_id=subaccount_id, + order_hashes=order_hashes, + ) + + async def fetch_chain_trader_derivative_transient_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_derivative_transient_orders( + market_id=market_id, + subaccount_id=subaccount_id, + ) + + async def fetch_chain_derivative_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_markets( + status=status, + market_ids=market_ids, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + + async def fetch_chain_derivative_market( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_market( + market_id=market_id, + ) + + async def fetch_derivative_market_address(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_market_address(market_id=market_id) + + async def fetch_subaccount_trade_nonce(self, subaccount_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_trade_nonce(subaccount_id=subaccount_id) + + async def fetch_chain_positions(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_positions() + + async def fetch_chain_subaccount_positions(self, subaccount_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_positions(subaccount_id=subaccount_id) + + async def fetch_chain_subaccount_position_in_market(self, subaccount_id: str, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_position_in_market( + subaccount_id=subaccount_id, + market_id=market_id, + ) + + async def fetch_chain_subaccount_effective_position_in_market( + self, subaccount_id: str, market_id: str + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_effective_position_in_market( + subaccount_id=subaccount_id, + market_id=market_id, + ) + + async def fetch_chain_perpetual_market_info(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_perpetual_market_info(market_id=market_id) + + async def fetch_chain_expiry_futures_market_info(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_expiry_futures_market_info(market_id=market_id) + + async def fetch_chain_perpetual_market_funding(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_perpetual_market_funding(market_id=market_id) + + async def fetch_subaccount_order_metadata(self, subaccount_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_order_metadata(subaccount_id=subaccount_id) + + async def fetch_trade_reward_points( + self, + accounts: Optional[List[str]] = None, + pending_pool_timestamp: Optional[int] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trade_reward_points( + accounts=accounts, + pending_pool_timestamp=pending_pool_timestamp, + ) + + async def fetch_pending_trade_reward_points( + self, + accounts: Optional[List[str]] = None, + pending_pool_timestamp: Optional[int] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_pending_trade_reward_points( + accounts=accounts, + pending_pool_timestamp=pending_pool_timestamp, + ) + + async def fetch_fee_discount_account_info(self, account: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_fee_discount_account_info(account=account) + + async def fetch_fee_discount_schedule(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_fee_discount_schedule() + + async def fetch_balance_mismatches(self, dust_factor: int) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_balance_mismatches(dust_factor=dust_factor) + + async def fetch_balance_with_balance_holds(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_balance_with_balance_holds() + + async def fetch_fee_discount_tier_statistics(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_fee_discount_tier_statistics() + + async def fetch_mito_vault_infos(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_mito_vault_infos() + + async def fetch_market_id_from_vault(self, vault_address: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_market_id_from_vault(vault_address=vault_address) + + async def fetch_historical_trade_records(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_historical_trade_records(market_id=market_id) + + async def fetch_is_opted_out_of_rewards(self, account: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_is_opted_out_of_rewards(account=account) + + async def fetch_opted_out_of_rewards_accounts(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_opted_out_of_rewards_accounts() + + async def fetch_market_volatility( + self, + market_id: str, + trade_grouping_sec: Optional[int] = None, + max_age: Optional[int] = None, + include_raw_history: Optional[bool] = None, + include_metadata: Optional[bool] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_market_volatility( + market_id=market_id, + trade_grouping_sec=trade_grouping_sec, + max_age=max_age, + include_raw_history=include_raw_history, + include_metadata=include_metadata, + ) + + async def fetch_chain_binary_options_markets(self, status: Optional[str] = None) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_binary_options_markets(status=status) + + async def fetch_trader_derivative_conditional_orders( + self, + subaccount_id: Optional[str] = None, + market_id: Optional[str] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_derivative_conditional_orders( + subaccount_id=subaccount_id, + market_id=market_id, + ) + + async def fetch_market_atomic_execution_fee_multiplier( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_market_atomic_execution_fee_multiplier( + market_id=market_id, + ) + # Injective Exchange client methods # Auction RPC diff --git a/pyinjective/client/chain/grpc/chain_grpc_exchange_api.py b/pyinjective/client/chain/grpc/chain_grpc_exchange_api.py new file mode 100644 index 00000000..217c0d34 --- /dev/null +++ b/pyinjective/client/chain/grpc/chain_grpc_exchange_api.py @@ -0,0 +1,572 @@ +from typing import Any, Callable, Dict, List, Optional + +from grpc.aio import Channel + +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.proto.injective.exchange.v1beta1 import ( + query_pb2 as exchange_query_pb, + query_pb2_grpc as exchange_query_grpc, +) +from pyinjective.utils.grpc_api_request_assistant import GrpcApiRequestAssistant + + +class ChainGrpcExchangeApi: + def __init__(self, channel: Channel, metadata_provider: Callable): + self._stub = exchange_query_grpc.QueryStub(channel) + self._assistant = GrpcApiRequestAssistant(metadata_provider=metadata_provider) + + async def fetch_exchange_params(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryExchangeParamsRequest() + response = await self._execute_call(call=self._stub.QueryExchangeParams, request=request) + + return response + + async def fetch_subaccount_deposits( + self, + subaccount_id: Optional[str] = None, + subaccount_trader: Optional[str] = None, + subaccount_nonce: Optional[int] = None, + ) -> Dict[str, Any]: + subaccount = None + if subaccount_trader is not None or subaccount_nonce is not None: + subaccount = exchange_query_pb.Subaccount( + trader=subaccount_trader, + subaccount_nonce=subaccount_nonce, + ) + + request = exchange_query_pb.QuerySubaccountDepositsRequest(subaccount_id=subaccount_id, subaccount=subaccount) + response = await self._execute_call(call=self._stub.SubaccountDeposits, request=request) + + return response + + async def fetch_subaccount_deposit( + self, + subaccount_id: str, + denom: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountDepositRequest( + subaccount_id=subaccount_id, + denom=denom, + ) + response = await self._execute_call(call=self._stub.SubaccountDeposit, request=request) + + return response + + async def fetch_exchange_balances(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryExchangeBalancesRequest() + response = await self._execute_call(call=self._stub.ExchangeBalances, request=request) + + return response + + async def fetch_aggregate_volume(self, account: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryAggregateVolumeRequest(account=account) + response = await self._execute_call(call=self._stub.AggregateVolume, request=request) + + return response + + async def fetch_aggregate_volumes( + self, + accounts: Optional[List[str]] = None, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryAggregateVolumesRequest(accounts=accounts, market_ids=market_ids) + response = await self._execute_call(call=self._stub.AggregateVolumes, request=request) + + return response + + async def fetch_aggregate_market_volume(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryAggregateMarketVolumeRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.AggregateMarketVolume, request=request) + + return response + + async def fetch_aggregate_market_volumes(self, market_ids: Optional[List[str]] = None) -> Dict[str, Any]: + request = exchange_query_pb.QueryAggregateMarketVolumesRequest(market_ids=market_ids) + response = await self._execute_call(call=self._stub.AggregateMarketVolumes, request=request) + + return response + + async def fetch_denom_decimal(self, denom: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryDenomDecimalRequest(denom=denom) + response = await self._execute_call(call=self._stub.DenomDecimal, request=request) + + return response + + async def fetch_denom_decimals(self, denoms: Optional[List[str]] = None) -> Dict[str, Any]: + request = exchange_query_pb.QueryDenomDecimalsRequest(denoms=denoms) + response = await self._execute_call(call=self._stub.DenomDecimals, request=request) + + return response + + async def fetch_spot_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySpotMarketsRequest( + status=status, + market_ids=market_ids, + ) + response = await self._execute_call(call=self._stub.SpotMarkets, request=request) + + return response + + async def fetch_spot_market(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySpotMarketRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.SpotMarket, request=request) + + return response + + async def fetch_full_spot_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryFullSpotMarketsRequest( + status=status, + market_ids=market_ids, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + response = await self._execute_call(call=self._stub.FullSpotMarkets, request=request) + + return response + + async def fetch_full_spot_market( + self, + market_id: str, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryFullSpotMarketRequest( + market_id=market_id, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + response = await self._execute_call(call=self._stub.FullSpotMarket, request=request) + + return response + + async def fetch_spot_orderbook( + self, + market_id: str, + order_side: Optional[str] = None, + limit_cumulative_notional: Optional[str] = None, + limit_cumulative_quantity: Optional[str] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + limit = None + if pagination is not None: + limit = pagination.limit + request = exchange_query_pb.QuerySpotOrderbookRequest( + market_id=market_id, + order_side=order_side, + limit=limit, + limit_cumulative_notional=limit_cumulative_notional, + limit_cumulative_quantity=limit_cumulative_quantity, + ) + response = await self._execute_call(call=self._stub.SpotOrderbook, request=request) + + return response + + async def fetch_trader_spot_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderSpotOrdersRequest( + market_id=market_id, + subaccount_id=subaccount_id, + ) + response = await self._execute_call(call=self._stub.TraderSpotOrders, request=request) + + return response + + async def fetch_account_address_spot_orders( + self, + market_id: str, + account_address: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryAccountAddressSpotOrdersRequest( + market_id=market_id, + account_address=account_address, + ) + response = await self._execute_call(call=self._stub.AccountAddressSpotOrders, request=request) + + return response + + async def fetch_spot_orders_by_hashes( + self, + market_id: str, + subaccount_id: str, + order_hashes: List[str], + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySpotOrdersByHashesRequest( + market_id=market_id, + subaccount_id=subaccount_id, + order_hashes=order_hashes, + ) + response = await self._execute_call(call=self._stub.SpotOrdersByHashes, request=request) + + return response + + async def fetch_subaccount_orders( + self, + subaccount_id: str, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountOrdersRequest( + subaccount_id=subaccount_id, + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.SubaccountOrders, request=request) + + return response + + async def fetch_trader_spot_transient_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderSpotOrdersRequest( + market_id=market_id, + subaccount_id=subaccount_id, + ) + response = await self._execute_call(call=self._stub.TraderSpotTransientOrders, request=request) + + return response + + async def fetch_spot_mid_price_and_tob( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySpotMidPriceAndTOBRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.SpotMidPriceAndTOB, request=request) + + return response + + async def fetch_derivative_mid_price_and_tob( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeMidPriceAndTOBRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.DerivativeMidPriceAndTOB, request=request) + + return response + + async def fetch_derivative_orderbook( + self, + market_id: str, + limit_cumulative_notional: Optional[str] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + limit = None + if pagination is not None: + limit = pagination.limit + request = exchange_query_pb.QueryDerivativeOrderbookRequest( + market_id=market_id, + limit=limit, + limit_cumulative_notional=limit_cumulative_notional, + ) + response = await self._execute_call(call=self._stub.DerivativeOrderbook, request=request) + + return response + + async def fetch_trader_derivative_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderDerivativeOrdersRequest( + market_id=market_id, + subaccount_id=subaccount_id, + ) + response = await self._execute_call(call=self._stub.TraderDerivativeOrders, request=request) + + return response + + async def fetch_account_address_derivative_orders( + self, + market_id: str, + account_address: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryAccountAddressDerivativeOrdersRequest( + market_id=market_id, + account_address=account_address, + ) + response = await self._execute_call(call=self._stub.AccountAddressDerivativeOrders, request=request) + + return response + + async def fetch_derivative_orders_by_hashes( + self, + market_id: str, + subaccount_id: str, + order_hashes: List[str], + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeOrdersByHashesRequest( + market_id=market_id, + subaccount_id=subaccount_id, + order_hashes=order_hashes, + ) + response = await self._execute_call(call=self._stub.DerivativeOrdersByHashes, request=request) + + return response + + async def fetch_trader_derivative_transient_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderDerivativeOrdersRequest( + market_id=market_id, + subaccount_id=subaccount_id, + ) + response = await self._execute_call(call=self._stub.TraderDerivativeTransientOrders, request=request) + + return response + + async def fetch_derivative_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeMarketsRequest( + status=status, + market_ids=market_ids, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + response = await self._execute_call(call=self._stub.DerivativeMarkets, request=request) + + return response + + async def fetch_derivative_market( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeMarketRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.DerivativeMarket, request=request) + + return response + + async def fetch_derivative_market_address( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeMarketAddressRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.DerivativeMarketAddress, request=request) + + return response + + async def fetch_subaccount_trade_nonce(self, subaccount_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountTradeNonceRequest(subaccount_id=subaccount_id) + response = await self._execute_call(call=self._stub.SubaccountTradeNonce, request=request) + + return response + + async def fetch_positions(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryPositionsRequest() + response = await self._execute_call(call=self._stub.Positions, request=request) + + return response + + async def fetch_subaccount_positions(self, subaccount_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountPositionsRequest(subaccount_id=subaccount_id) + response = await self._execute_call(call=self._stub.SubaccountPositions, request=request) + + return response + + async def fetch_subaccount_position_in_market(self, subaccount_id: str, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountPositionInMarketRequest( + subaccount_id=subaccount_id, + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.SubaccountPositionInMarket, request=request) + + return response + + async def fetch_subaccount_effective_position_in_market(self, subaccount_id: str, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountEffectivePositionInMarketRequest( + subaccount_id=subaccount_id, + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.SubaccountEffectivePositionInMarket, request=request) + + return response + + async def fetch_perpetual_market_info(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryPerpetualMarketInfoRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.PerpetualMarketInfo, request=request) + + return response + + async def fetch_expiry_futures_market_info(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryExpiryFuturesMarketInfoRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.ExpiryFuturesMarketInfo, request=request) + + return response + + async def fetch_perpetual_market_funding(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryPerpetualMarketFundingRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.PerpetualMarketFunding, request=request) + + return response + + async def fetch_subaccount_order_metadata(self, subaccount_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountOrderMetadataRequest(subaccount_id=subaccount_id) + response = await self._execute_call(call=self._stub.SubaccountOrderMetadata, request=request) + + return response + + async def fetch_trade_reward_points( + self, + accounts: Optional[List[str]] = None, + pending_pool_timestamp: Optional[int] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTradeRewardPointsRequest( + accounts=accounts, + pending_pool_timestamp=pending_pool_timestamp, + ) + response = await self._execute_call(call=self._stub.TradeRewardPoints, request=request) + + return response + + async def fetch_pending_trade_reward_points( + self, + accounts: Optional[List[str]] = None, + pending_pool_timestamp: Optional[int] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTradeRewardPointsRequest( + accounts=accounts, + pending_pool_timestamp=pending_pool_timestamp, + ) + response = await self._execute_call(call=self._stub.PendingTradeRewardPoints, request=request) + + return response + + async def fetch_fee_discount_account_info( + self, + account: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryFeeDiscountAccountInfoRequest(account=account) + response = await self._execute_call(call=self._stub.FeeDiscountAccountInfo, request=request) + + return response + + async def fetch_fee_discount_schedule(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryFeeDiscountScheduleRequest() + response = await self._execute_call(call=self._stub.FeeDiscountSchedule, request=request) + + return response + + async def fetch_balance_mismatches(self, dust_factor: int) -> Dict[str, Any]: + request = exchange_query_pb.QueryBalanceMismatchesRequest(dust_factor=dust_factor) + response = await self._execute_call(call=self._stub.BalanceMismatches, request=request) + + return response + + async def fetch_balance_with_balance_holds(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryBalanceWithBalanceHoldsRequest() + response = await self._execute_call(call=self._stub.BalanceWithBalanceHolds, request=request) + + return response + + async def fetch_fee_discount_tier_statistics(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryFeeDiscountTierStatisticsRequest() + response = await self._execute_call(call=self._stub.FeeDiscountTierStatistics, request=request) + + return response + + async def fetch_mito_vault_infos(self) -> Dict[str, Any]: + request = exchange_query_pb.MitoVaultInfosRequest() + response = await self._execute_call(call=self._stub.MitoVaultInfos, request=request) + + return response + + async def fetch_market_id_from_vault(self, vault_address: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryMarketIDFromVaultRequest(vault_address=vault_address) + response = await self._execute_call(call=self._stub.QueryMarketIDFromVault, request=request) + + return response + + async def fetch_historical_trade_records(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryHistoricalTradeRecordsRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.HistoricalTradeRecords, request=request) + + return response + + async def fetch_is_opted_out_of_rewards(self, account: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryIsOptedOutOfRewardsRequest(account=account) + response = await self._execute_call(call=self._stub.IsOptedOutOfRewards, request=request) + + return response + + async def fetch_opted_out_of_rewards_accounts(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryOptedOutOfRewardsAccountsRequest() + response = await self._execute_call(call=self._stub.OptedOutOfRewardsAccounts, request=request) + + return response + + async def fetch_market_volatility( + self, + market_id: str, + trade_grouping_sec: Optional[int] = None, + max_age: Optional[int] = None, + include_raw_history: Optional[bool] = None, + include_metadata: Optional[bool] = None, + ) -> Dict[str, Any]: + trade_history_options = exchange_query_pb.TradeHistoryOptions() + if trade_grouping_sec is not None: + trade_history_options.trade_grouping_sec = trade_grouping_sec + if max_age is not None: + trade_history_options.max_age = max_age + if include_raw_history is not None: + trade_history_options.include_raw_history = include_raw_history + if include_metadata is not None: + trade_history_options.include_metadata = include_metadata + request = exchange_query_pb.QueryMarketVolatilityRequest( + market_id=market_id, trade_history_options=trade_history_options + ) + response = await self._execute_call(call=self._stub.MarketVolatility, request=request) + + return response + + async def fetch_binary_options_markets(self, status: Optional[str] = None) -> Dict[str, Any]: + request = exchange_query_pb.QueryBinaryMarketsRequest(status=status) + response = await self._execute_call(call=self._stub.BinaryOptionsMarkets, request=request) + + return response + + async def fetch_trader_derivative_conditional_orders( + self, + subaccount_id: Optional[str] = None, + market_id: Optional[str] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderDerivativeConditionalOrdersRequest( + subaccount_id=subaccount_id, + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.TraderDerivativeConditionalOrders, request=request) + + return response + + async def fetch_market_atomic_execution_fee_multiplier( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryMarketAtomicExecutionFeeMultiplierRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.MarketAtomicExecutionFeeMultiplier, request=request) + + return response + + async def _execute_call(self, call: Callable, request) -> Dict[str, Any]: + return await self._assistant.execute_call(call=call, request=request) diff --git a/tests/client/chain/grpc/configurable_exchange_query_servicer.py b/tests/client/chain/grpc/configurable_exchange_query_servicer.py new file mode 100644 index 00000000..267b08ce --- /dev/null +++ b/tests/client/chain/grpc/configurable_exchange_query_servicer.py @@ -0,0 +1,325 @@ +from collections import deque + +from pyinjective.proto.injective.exchange.v1beta1 import ( + query_pb2 as exchange_query_pb, + query_pb2_grpc as exchange_query_grpc, +) + + +class ConfigurableExchangeQueryServicer(exchange_query_grpc.QueryServicer): + def __init__(self): + super().__init__() + self.exchange_params = deque() + self.subaccount_deposits_responses = deque() + self.subaccount_deposit_responses = deque() + self.exchange_balances_responses = deque() + self.aggregate_volume_responses = deque() + self.aggregate_volumes_responses = deque() + self.aggregate_market_volume_responses = deque() + self.aggregate_market_volumes_responses = deque() + self.denom_decimal_responses = deque() + self.denom_decimals_responses = deque() + self.spot_markets_responses = deque() + self.spot_market_responses = deque() + self.full_spot_markets_responses = deque() + self.full_spot_market_responses = deque() + self.spot_orderbook_responses = deque() + self.trader_spot_orders_responses = deque() + self.account_address_spot_orders_responses = deque() + self.spot_orders_by_hashes_responses = deque() + self.subaccount_orders_responses = deque() + self.trader_spot_transient_orders_responses = deque() + self.spot_mid_price_and_tob_responses = deque() + self.derivative_mid_price_and_tob_responses = deque() + self.derivative_orderbook_responses = deque() + self.trader_derivative_orders_responses = deque() + self.account_address_derivative_orders_responses = deque() + self.derivative_orders_by_hashes_responses = deque() + self.trader_derivative_transient_orders_responses = deque() + self.derivative_markets_responses = deque() + self.derivative_market_responses = deque() + self.derivative_market_address_responses = deque() + self.subaccount_trade_nonce_responses = deque() + self.positions_responses = deque() + self.subaccount_positions_responses = deque() + self.subaccount_position_in_market_responses = deque() + self.subaccount_effective_position_in_market_responses = deque() + self.perpetual_market_info_responses = deque() + self.expiry_futures_market_info_responses = deque() + self.perpetual_market_funding_responses = deque() + self.subaccount_order_metadata_responses = deque() + self.trade_reward_points_responses = deque() + self.pending_trade_reward_points_responses = deque() + self.fee_discount_account_info_responses = deque() + self.fee_discount_schedule_responses = deque() + self.balance_mismatches_responses = deque() + self.balance_with_balance_holds_responses = deque() + self.fee_discount_tier_statistics_responses = deque() + self.mito_vault_infos_responses = deque() + self.market_id_from_vault_responses = deque() + self.historical_trade_records_responses = deque() + self.is_opted_out_of_rewards_responses = deque() + self.opted_out_of_rewards_accounts_responses = deque() + self.market_volatility_responses = deque() + self.binary_options_markets_responses = deque() + self.trader_derivative_conditional_orders_responses = deque() + self.market_atomic_execution_fee_multiplier_responses = deque() + + async def QueryExchangeParams( + self, request: exchange_query_pb.QueryExchangeParamsRequest, context=None, metadata=None + ): + return self.exchange_params.pop() + + async def SubaccountDeposits( + self, request: exchange_query_pb.QuerySubaccountDepositsRequest, context=None, metadata=None + ): + return self.subaccount_deposits_responses.pop() + + async def SubaccountDeposit( + self, request: exchange_query_pb.QuerySubaccountDepositRequest, context=None, metadata=None + ): + return self.subaccount_deposit_responses.pop() + + async def ExchangeBalances( + self, request: exchange_query_pb.QueryExchangeBalancesRequest, context=None, metadata=None + ): + return self.exchange_balances_responses.pop() + + async def AggregateVolume( + self, request: exchange_query_pb.QueryAggregateVolumeRequest, context=None, metadata=None + ): + return self.aggregate_volume_responses.pop() + + async def AggregateVolumes( + self, request: exchange_query_pb.QueryAggregateVolumesRequest, context=None, metadata=None + ): + return self.aggregate_volumes_responses.pop() + + async def AggregateMarketVolume( + self, request: exchange_query_pb.QueryAggregateMarketVolumeRequest, context=None, metadata=None + ): + return self.aggregate_market_volume_responses.pop() + + async def AggregateMarketVolumes( + self, request: exchange_query_pb.QueryAggregateMarketVolumesRequest, context=None, metadata=None + ): + return self.aggregate_market_volumes_responses.pop() + + async def DenomDecimal(self, request: exchange_query_pb.QueryDenomDecimalRequest, context=None, metadata=None): + return self.denom_decimal_responses.pop() + + async def DenomDecimals(self, request: exchange_query_pb.QueryDenomDecimalsRequest, context=None, metadata=None): + return self.denom_decimals_responses.pop() + + async def SpotMarkets(self, request: exchange_query_pb.QuerySpotMarketsRequest, context=None, metadata=None): + return self.spot_markets_responses.pop() + + async def SpotMarket(self, request: exchange_query_pb.QuerySpotMarketRequest, context=None, metadata=None): + return self.spot_market_responses.pop() + + async def FullSpotMarkets( + self, request: exchange_query_pb.QueryFullSpotMarketsRequest, context=None, metadata=None + ): + return self.full_spot_markets_responses.pop() + + async def FullSpotMarket(self, request: exchange_query_pb.QueryFullSpotMarketRequest, context=None, metadata=None): + return self.full_spot_market_responses.pop() + + async def SpotOrderbook(self, request: exchange_query_pb.QuerySpotOrderbookRequest, context=None, metadata=None): + return self.spot_orderbook_responses.pop() + + async def TraderSpotOrders( + self, request: exchange_query_pb.QueryTraderSpotOrdersRequest, context=None, metadata=None + ): + return self.trader_spot_orders_responses.pop() + + async def AccountAddressSpotOrders( + self, request: exchange_query_pb.QueryAccountAddressSpotOrdersRequest, context=None, metadata=None + ): + return self.account_address_spot_orders_responses.pop() + + async def SpotOrdersByHashes( + self, request: exchange_query_pb.QuerySpotOrdersByHashesRequest, context=None, metadata=None + ): + return self.spot_orders_by_hashes_responses.pop() + + async def SubaccountOrders( + self, request: exchange_query_pb.QuerySubaccountOrdersRequest, context=None, metadata=None + ): + return self.subaccount_orders_responses.pop() + + async def TraderSpotTransientOrders( + self, request: exchange_query_pb.QueryTraderSpotOrdersRequest, context=None, metadata=None + ): + return self.trader_spot_transient_orders_responses.pop() + + async def SpotMidPriceAndTOB( + self, request: exchange_query_pb.QuerySpotMidPriceAndTOBRequest, context=None, metadata=None + ): + return self.spot_mid_price_and_tob_responses.pop() + + async def DerivativeMidPriceAndTOB( + self, request: exchange_query_pb.QueryDerivativeMidPriceAndTOBRequest, context=None, metadata=None + ): + return self.derivative_mid_price_and_tob_responses.pop() + + async def DerivativeOrderbook( + self, request: exchange_query_pb.QueryDerivativeOrderbookRequest, context=None, metadata=None + ): + return self.derivative_orderbook_responses.pop() + + async def TraderDerivativeOrders( + self, request: exchange_query_pb.QueryTraderDerivativeOrdersRequest, context=None, metadata=None + ): + return self.trader_derivative_orders_responses.pop() + + async def AccountAddressDerivativeOrders( + self, request: exchange_query_pb.QueryAccountAddressDerivativeOrdersRequest, context=None, metadata=None + ): + return self.account_address_derivative_orders_responses.pop() + + async def DerivativeOrdersByHashes( + self, request: exchange_query_pb.QueryDerivativeOrdersByHashesRequest, context=None, metadata=None + ): + return self.derivative_orders_by_hashes_responses.pop() + + async def TraderDerivativeTransientOrders( + self, request: exchange_query_pb.QueryTraderDerivativeOrdersRequest, context=None, metadata=None + ): + return self.trader_derivative_transient_orders_responses.pop() + + async def DerivativeMarkets( + self, request: exchange_query_pb.QueryDerivativeMarketsRequest, context=None, metadata=None + ): + return self.derivative_markets_responses.pop() + + async def DerivativeMarket( + self, request: exchange_query_pb.QueryDerivativeMarketRequest, context=None, metadata=None + ): + return self.derivative_market_responses.pop() + + async def DerivativeMarketAddress( + self, request: exchange_query_pb.QueryDerivativeMarketAddressRequest, context=None, metadata=None + ): + return self.derivative_market_address_responses.pop() + + async def SubaccountTradeNonce( + self, request: exchange_query_pb.QuerySubaccountTradeNonceRequest, context=None, metadata=None + ): + return self.subaccount_trade_nonce_responses.pop() + + async def Positions(self, request: exchange_query_pb.QueryPositionsRequest, context=None, metadata=None): + return self.positions_responses.pop() + + async def SubaccountPositions( + self, request: exchange_query_pb.QuerySubaccountPositionsRequest, context=None, metadata=None + ): + return self.subaccount_positions_responses.pop() + + async def SubaccountPositionInMarket( + self, request: exchange_query_pb.QuerySubaccountPositionInMarketRequest, context=None, metadata=None + ): + return self.subaccount_position_in_market_responses.pop() + + async def SubaccountEffectivePositionInMarket( + self, request: exchange_query_pb.QuerySubaccountEffectivePositionInMarketRequest, context=None, metadata=None + ): + return self.subaccount_effective_position_in_market_responses.pop() + + async def PerpetualMarketInfo( + self, request: exchange_query_pb.QueryPerpetualMarketInfoRequest, context=None, metadata=None + ): + return self.perpetual_market_info_responses.pop() + + async def ExpiryFuturesMarketInfo( + self, request: exchange_query_pb.QueryExpiryFuturesMarketInfoRequest, context=None, metadata=None + ): + return self.expiry_futures_market_info_responses.pop() + + async def PerpetualMarketFunding( + self, request: exchange_query_pb.QueryPerpetualMarketFundingRequest, context=None, metadata=None + ): + return self.perpetual_market_funding_responses.pop() + + async def SubaccountOrderMetadata( + self, request: exchange_query_pb.QuerySubaccountOrderMetadataRequest, context=None, metadata=None + ): + return self.subaccount_order_metadata_responses.pop() + + async def TradeRewardPoints( + self, request: exchange_query_pb.QueryTradeRewardPointsRequest, context=None, metadata=None + ): + return self.trade_reward_points_responses.pop() + + async def PendingTradeRewardPoints( + self, request: exchange_query_pb.QueryTradeRewardPointsRequest, context=None, metadata=None + ): + return self.pending_trade_reward_points_responses.pop() + + async def FeeDiscountAccountInfo( + self, request: exchange_query_pb.QueryFeeDiscountAccountInfoRequest, context=None, metadata=None + ): + return self.fee_discount_account_info_responses.pop() + + async def FeeDiscountSchedule( + self, request: exchange_query_pb.QueryFeeDiscountScheduleRequest, context=None, metadata=None + ): + return self.fee_discount_schedule_responses.pop() + + async def BalanceMismatches( + self, request: exchange_query_pb.QueryBalanceMismatchesRequest, context=None, metadata=None + ): + return self.balance_mismatches_responses.pop() + + async def BalanceWithBalanceHolds( + self, request: exchange_query_pb.QueryBalanceWithBalanceHoldsRequest, context=None, metadata=None + ): + return self.balance_with_balance_holds_responses.pop() + + async def FeeDiscountTierStatistics( + self, request: exchange_query_pb.QueryFeeDiscountTierStatisticsRequest, context=None, metadata=None + ): + return self.fee_discount_tier_statistics_responses.pop() + + async def MitoVaultInfos(self, request: exchange_query_pb.MitoVaultInfosRequest, context=None, metadata=None): + return self.mito_vault_infos_responses.pop() + + async def QueryMarketIDFromVault( + self, request: exchange_query_pb.QueryMarketIDFromVaultRequest, context=None, metadata=None + ): + return self.market_id_from_vault_responses.pop() + + async def HistoricalTradeRecords( + self, request: exchange_query_pb.QueryHistoricalTradeRecordsRequest, context=None, metadata=None + ): + return self.historical_trade_records_responses.pop() + + async def IsOptedOutOfRewards( + self, request: exchange_query_pb.QueryIsOptedOutOfRewardsRequest, context=None, metadata=None + ): + return self.is_opted_out_of_rewards_responses.pop() + + async def OptedOutOfRewardsAccounts( + self, request: exchange_query_pb.QueryOptedOutOfRewardsAccountsRequest, context=None, metadata=None + ): + return self.opted_out_of_rewards_accounts_responses.pop() + + async def MarketVolatility( + self, request: exchange_query_pb.QueryMarketVolatilityRequest, context=None, metadata=None + ): + return self.market_volatility_responses.pop() + + async def BinaryOptionsMarkets( + self, request: exchange_query_pb.QueryBinaryMarketsRequest, context=None, metadata=None + ): + return self.binary_options_markets_responses.pop() + + async def TraderDerivativeConditionalOrders( + self, request: exchange_query_pb.QueryTraderDerivativeConditionalOrdersRequest, context=None, metadata=None + ): + return self.trader_derivative_conditional_orders_responses.pop() + + async def MarketAtomicExecutionFeeMultiplier( + self, request: exchange_query_pb.QueryMarketAtomicExecutionFeeMultiplierRequest, context=None, metadata=None + ): + return self.market_atomic_execution_fee_multiplier_responses.pop() diff --git a/tests/client/chain/grpc/test_chain_grpc_exchange_api.py b/tests/client/chain/grpc/test_chain_grpc_exchange_api.py new file mode 100644 index 00000000..54393a94 --- /dev/null +++ b/tests/client/chain/grpc/test_chain_grpc_exchange_api.py @@ -0,0 +1,2466 @@ +import base64 + +import grpc +import pytest + +from pyinjective.client.chain.grpc.chain_grpc_exchange_api import ChainGrpcExchangeApi +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.core.network import Network +from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as coin_pb +from pyinjective.proto.injective.exchange.v1beta1 import ( + exchange_pb2 as exchange_pb, + genesis_pb2 as genesis_pb, + query_pb2 as exchange_query_pb, +) +from pyinjective.proto.injective.oracle.v1beta1 import oracle_pb2 as oracle_pb +from tests.client.chain.grpc.configurable_exchange_query_servicer import ConfigurableExchangeQueryServicer + + +@pytest.fixture +def exchange_servicer(): + return ConfigurableExchangeQueryServicer() + + +class TestChainGrpcBankApi: + @pytest.mark.asyncio + async def test_fetch_exchange_params( + self, + exchange_servicer, + ): + spot_market_instant_listing_fee = coin_pb.Coin(denom="inj", amount="10000000000000000000") + derivative_market_instant_listing_fee = coin_pb.Coin(denom="inj", amount="2000000000000000000000") + binary_options_market_instant_listing_fee = coin_pb.Coin(denom="inj", amount="30000000000000000000") + params = exchange_pb.Params( + spot_market_instant_listing_fee=spot_market_instant_listing_fee, + derivative_market_instant_listing_fee=derivative_market_instant_listing_fee, + default_spot_maker_fee_rate="-0.000100000000000000", + default_spot_taker_fee_rate="0.001000000000000000", + default_derivative_maker_fee_rate="-0.000100000000000000", + default_derivative_taker_fee_rate="0.001000000000000000", + default_initial_margin_ratio="0.050000000000000000", + default_maintenance_margin_ratio="0.020000000000000000", + default_funding_interval=3600, + funding_multiple=4600, + relayer_fee_share_rate="0.400000000000000000", + default_hourly_funding_rate_cap="0.000625000000000000", + default_hourly_interest_rate="0.000004166660000000", + max_derivative_order_side_count=20, + inj_reward_staked_requirement_threshold="25000000000000000000", + trading_rewards_vesting_duration=1209600, + liquidator_reward_share_rate="0.050000000000000000", + binary_options_market_instant_listing_fee=binary_options_market_instant_listing_fee, + atomic_market_order_access_level=2, + spot_atomic_market_order_fee_multiplier="2.000000000000000000", + derivative_atomic_market_order_fee_multiplier="2.000000000000000000", + binary_options_atomic_market_order_fee_multiplier="2.000000000000000000", + minimal_protocol_fee_rate="0.000010000000000000", + is_instant_derivative_market_launch_enabled=False, + post_only_mode_height_threshold=57078000, + ) + exchange_servicer.exchange_params.append(exchange_query_pb.QueryExchangeParamsResponse(params=params)) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + module_params = await api.fetch_exchange_params() + expected_params = { + "params": { + "spotMarketInstantListingFee": { + "amount": spot_market_instant_listing_fee.amount, + "denom": spot_market_instant_listing_fee.denom, + }, + "derivativeMarketInstantListingFee": { + "amount": derivative_market_instant_listing_fee.amount, + "denom": derivative_market_instant_listing_fee.denom, + }, + "defaultSpotMakerFeeRate": params.default_spot_maker_fee_rate, + "defaultSpotTakerFeeRate": params.default_spot_taker_fee_rate, + "defaultDerivativeMakerFeeRate": params.default_derivative_maker_fee_rate, + "defaultDerivativeTakerFeeRate": params.default_derivative_taker_fee_rate, + "defaultInitialMarginRatio": params.default_initial_margin_ratio, + "defaultMaintenanceMarginRatio": params.default_maintenance_margin_ratio, + "defaultFundingInterval": str(params.default_funding_interval), + "fundingMultiple": str(params.funding_multiple), + "relayerFeeShareRate": params.relayer_fee_share_rate, + "defaultHourlyFundingRateCap": params.default_hourly_funding_rate_cap, + "defaultHourlyInterestRate": params.default_hourly_interest_rate, + "maxDerivativeOrderSideCount": params.max_derivative_order_side_count, + "injRewardStakedRequirementThreshold": params.inj_reward_staked_requirement_threshold, + "tradingRewardsVestingDuration": str(params.trading_rewards_vesting_duration), + "liquidatorRewardShareRate": "0.050000000000000000", + "binaryOptionsMarketInstantListingFee": { + "amount": binary_options_market_instant_listing_fee.amount, + "denom": binary_options_market_instant_listing_fee.denom, + }, + "atomicMarketOrderAccessLevel": exchange_pb.AtomicMarketOrderAccessLevel.Name( + params.atomic_market_order_access_level + ), + "spotAtomicMarketOrderFeeMultiplier": params.spot_atomic_market_order_fee_multiplier, + "derivativeAtomicMarketOrderFeeMultiplier": params.derivative_atomic_market_order_fee_multiplier, + "binaryOptionsAtomicMarketOrderFeeMultiplier": params.binary_options_atomic_market_order_fee_multiplier, + "minimalProtocolFeeRate": params.minimal_protocol_fee_rate, + "isInstantDerivativeMarketLaunchEnabled": params.is_instant_derivative_market_launch_enabled, + "postOnlyModeHeightThreshold": str(params.post_only_mode_height_threshold), + } + } + + assert module_params == expected_params + + @pytest.mark.asyncio + async def test_fetch_subaccount_deposits( + self, + exchange_servicer, + ): + deposit_denom = "inj" + deposit = exchange_pb.Deposit( + available_balance="1000000000000000000", + total_balance="2000000000000000000", + ) + exchange_servicer.subaccount_deposits_responses.append( + exchange_query_pb.QuerySubaccountDepositsResponse(deposits={deposit_denom: deposit}) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + deposits = await api.fetch_subaccount_deposits( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + subaccount_trader="inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7", + subaccount_nonce=1, + ) + expected_deposits = { + "deposits": { + deposit_denom: { + "availableBalance": deposit.available_balance, + "totalBalance": deposit.total_balance, + }, + } + } + + assert deposits == expected_deposits + + @pytest.mark.asyncio + async def test_fetch_subaccount_deposit( + self, + exchange_servicer, + ): + deposit = exchange_pb.Deposit( + available_balance="1000000000000000000", + total_balance="2000000000000000000", + ) + exchange_servicer.subaccount_deposit_responses.append( + exchange_query_pb.QuerySubaccountDepositResponse(deposits=deposit) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + deposit_response = await api.fetch_subaccount_deposit( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + denom="inj", + ) + expected_deposit = { + "deposits": { + "availableBalance": deposit.available_balance, + "totalBalance": deposit.total_balance, + } + } + + assert deposit_response == expected_deposit + + @pytest.mark.asyncio + async def test_fetch_exchange_balances( + self, + exchange_servicer, + ): + deposit = exchange_pb.Deposit( + available_balance="1000000000000000000", + total_balance="2000000000000000000", + ) + balance = genesis_pb.Balance( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + denom="inj", + deposits=deposit, + ) + exchange_servicer.exchange_balances_responses.append( + exchange_query_pb.QueryExchangeBalancesResponse(balances=[balance]) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + balances_response = await api.fetch_exchange_balances() + expected_balances = { + "balances": [ + { + "subaccountId": balance.subaccount_id, + "denom": balance.denom, + "deposits": { + "availableBalance": deposit.available_balance, + "totalBalance": deposit.total_balance, + }, + }, + ] + } + + assert balances_response == expected_balances + + @pytest.mark.asyncio + async def test_fetch_aggregate_volume( + self, + exchange_servicer, + ): + volume = exchange_pb.VolumeRecord( + maker_volume="1000000000000000000", + taker_volume="2000000000000000000", + ) + market_volume = exchange_pb.MarketVolume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + volume=volume, + ) + exchange_servicer.aggregate_volume_responses.append( + exchange_query_pb.QueryAggregateVolumeResponse( + aggregate_volumes=[market_volume], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volume_response = await api.fetch_aggregate_volume(account="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r") + expected_volume = { + "aggregateVolumes": [ + { + "marketId": market_volume.market_id, + "volume": { + "makerVolume": volume.maker_volume, + "takerVolume": volume.taker_volume, + }, + }, + ] + } + + assert volume_response == expected_volume + + @pytest.mark.asyncio + async def test_fetch_aggregate_volumes( + self, + exchange_servicer, + ): + acc_volume = exchange_pb.VolumeRecord( + maker_volume="1000000000000000000", + taker_volume="2000000000000000000", + ) + account_market_volume = exchange_pb.MarketVolume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + volume=acc_volume, + ) + account_volume = exchange_pb.AggregateAccountVolumeRecord( + account="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + market_volumes=[account_market_volume], + ) + volume = exchange_pb.VolumeRecord( + maker_volume="3000000000000000000", + taker_volume="4000000000000000000", + ) + market_volume = exchange_pb.MarketVolume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + volume=volume, + ) + exchange_servicer.aggregate_volumes_responses.append( + exchange_query_pb.QueryAggregateVolumesResponse( + aggregate_account_volumes=[account_volume], + aggregate_market_volumes=[market_volume], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volume_response = await api.fetch_aggregate_volumes( + accounts=[account_volume.account], + market_ids=[account_market_volume.market_id], + ) + expected_volume = { + "aggregateAccountVolumes": [ + { + "account": account_volume.account, + "marketVolumes": [ + { + "marketId": account_market_volume.market_id, + "volume": { + "makerVolume": acc_volume.maker_volume, + "takerVolume": acc_volume.taker_volume, + }, + }, + ], + }, + ], + "aggregateMarketVolumes": [ + { + "marketId": market_volume.market_id, + "volume": { + "makerVolume": volume.maker_volume, + "takerVolume": volume.taker_volume, + }, + }, + ], + } + + assert volume_response == expected_volume + + @pytest.mark.asyncio + async def test_fetch_aggregate_market_volume( + self, + exchange_servicer, + ): + volume = exchange_pb.VolumeRecord( + maker_volume="1000000000000000000", + taker_volume="2000000000000000000", + ) + exchange_servicer.aggregate_market_volume_responses.append( + exchange_query_pb.QueryAggregateMarketVolumeResponse( + volume=volume, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volume_response = await api.fetch_aggregate_market_volume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + ) + expected_volume = { + "volume": { + "makerVolume": volume.maker_volume, + "takerVolume": volume.taker_volume, + } + } + + assert volume_response == expected_volume + + @pytest.mark.asyncio + async def test_fetch_aggregate_market_volumes( + self, + exchange_servicer, + ): + volume = exchange_pb.VolumeRecord( + maker_volume="3000000000000000000", + taker_volume="4000000000000000000", + ) + market_volume = exchange_pb.MarketVolume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + volume=volume, + ) + exchange_servicer.aggregate_market_volumes_responses.append( + exchange_query_pb.QueryAggregateMarketVolumesResponse( + volumes=[market_volume], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volume_response = await api.fetch_aggregate_market_volumes( + market_ids=[market_volume.market_id], + ) + expected_volume = { + "volumes": [ + { + "marketId": market_volume.market_id, + "volume": { + "makerVolume": volume.maker_volume, + "takerVolume": volume.taker_volume, + }, + }, + ], + } + + assert volume_response == expected_volume + + @pytest.mark.asyncio + async def test_fetch_denom_decimal( + self, + exchange_servicer, + ): + decimal = 18 + exchange_servicer.denom_decimal_responses.append( + exchange_query_pb.QueryDenomDecimalResponse( + decimal=decimal, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + denom_decimal = await api.fetch_denom_decimal(denom="inj") + expected_decimal = {"decimal": str(decimal)} + + assert denom_decimal == expected_decimal + + @pytest.mark.asyncio + async def test_fetch_denom_decimals( + self, + exchange_servicer, + ): + denom_decimal = exchange_pb.DenomDecimals( + denom="inj", + decimals=18, + ) + exchange_servicer.denom_decimals_responses.append( + exchange_query_pb.QueryDenomDecimalsResponse( + denom_decimals=[denom_decimal], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + denom_decimals = await api.fetch_denom_decimals(denoms=[denom_decimal.denom]) + expected_decimals = { + "denomDecimals": [ + { + "denom": denom_decimal.denom, + "decimals": str(denom_decimal.decimals), + } + ] + } + + assert denom_decimals == expected_decimals + + @pytest.mark.asyncio + async def test_fetch_spot_markets( + self, + exchange_servicer, + ): + market = exchange_pb.SpotMarket( + ticker="INJ/USDT", + base_denom="inj", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="0.4", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + status=1, + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + exchange_servicer.spot_markets_responses.append( + exchange_query_pb.QuerySpotMarketsResponse( + markets=[market], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + markets = await api.fetch_spot_markets( + status=status_string, + market_ids=[market.market_id], + ) + expected_markets = { + "markets": [ + { + "ticker": market.ticker, + "baseDenom": market.base_denom, + "quoteDenom": market.quote_denom, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "marketId": market.market_id, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + } + ] + } + + assert markets == expected_markets + + @pytest.mark.asyncio + async def test_fetch_spot_market( + self, + exchange_servicer, + ): + market = exchange_pb.SpotMarket( + ticker="INJ/USDT", + base_denom="inj", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="0.4", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + status=1, + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + exchange_servicer.spot_market_responses.append( + exchange_query_pb.QuerySpotMarketResponse( + market=market, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + response_market = await api.fetch_spot_market( + market_id=market.market_id, + ) + expected_market = { + "market": { + "ticker": market.ticker, + "baseDenom": market.base_denom, + "quoteDenom": market.quote_denom, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "marketId": market.market_id, + "status": exchange_pb.MarketStatus.Name(market.status), + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + } + } + + assert response_market == expected_market + + @pytest.mark.asyncio + async def test_fetch_full_spot_markets( + self, + exchange_servicer, + ): + market = exchange_pb.SpotMarket( + ticker="INJ/USDT", + base_denom="inj", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="0.4", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + status=1, + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + mid_price_and_tob = exchange_pb.MidPriceAndTOB( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + full_market = exchange_query_pb.FullSpotMarket( + market=market, + mid_price_and_tob=mid_price_and_tob, + ) + exchange_servicer.full_spot_markets_responses.append( + exchange_query_pb.QueryFullSpotMarketsResponse( + markets=[full_market], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + markets = await api.fetch_full_spot_markets( + status=status_string, + market_ids=[market.market_id], + with_mid_price_and_tob=True, + ) + expected_markets = { + "markets": [ + { + "market": { + "ticker": market.ticker, + "baseDenom": market.base_denom, + "quoteDenom": market.quote_denom, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "marketId": market.market_id, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + }, + "midPriceAndTob": { + "midPrice": mid_price_and_tob.mid_price, + "bestBuyPrice": mid_price_and_tob.best_buy_price, + "bestSellPrice": mid_price_and_tob.best_sell_price, + }, + } + ] + } + + assert markets == expected_markets + + @pytest.mark.asyncio + async def test_fetch_full_spot_market( + self, + exchange_servicer, + ): + market = exchange_pb.SpotMarket( + ticker="INJ/USDT", + base_denom="inj", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="0.4", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + status=1, + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + mid_price_and_tob = exchange_pb.MidPriceAndTOB( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + full_market = exchange_query_pb.FullSpotMarket( + market=market, + mid_price_and_tob=mid_price_and_tob, + ) + exchange_servicer.full_spot_market_responses.append( + exchange_query_pb.QueryFullSpotMarketResponse( + market=full_market, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + market_response = await api.fetch_full_spot_market( + market_id=market.market_id, + with_mid_price_and_tob=True, + ) + expected_market = { + "market": { + "market": { + "ticker": market.ticker, + "baseDenom": market.base_denom, + "quoteDenom": market.quote_denom, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "marketId": market.market_id, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + }, + "midPriceAndTob": { + "midPrice": mid_price_and_tob.mid_price, + "bestBuyPrice": mid_price_and_tob.best_buy_price, + "bestSellPrice": mid_price_and_tob.best_sell_price, + }, + } + } + + assert market_response == expected_market + + @pytest.mark.asyncio + async def test_fetch_spot_orderbook( + self, + exchange_servicer, + ): + buy_price_level = exchange_pb.Level( + p="1000000000000000000", + q="1000000000000000", + ) + sell_price_level = exchange_pb.Level( + p="2000000000000000000", + q="2000000000000000", + ) + exchange_servicer.spot_orderbook_responses.append( + exchange_query_pb.QuerySpotOrderbookResponse( + buys_price_level=[buy_price_level], + sells_price_level=[sell_price_level], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orderbook = await api.fetch_spot_orderbook( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + order_side="Side_Unspecified", + limit_cumulative_notional="1000000000000000000", + limit_cumulative_quantity="1000000000000000", + pagination=PaginationOption(limit=100), + ) + expected_orderbook = { + "buysPriceLevel": [ + { + "p": buy_price_level.p, + "q": buy_price_level.q, + } + ], + "sellsPriceLevel": [ + { + "p": sell_price_level.p, + "q": sell_price_level.q, + } + ], + } + + assert orderbook == expected_orderbook + + @pytest.mark.asyncio + async def test_fetch_trader_spot_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedSpotLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.trader_spot_orders_responses.append( + exchange_query_pb.QueryTraderSpotOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_spot_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_account_address_spot_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedSpotLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.account_address_spot_orders_responses.append( + exchange_query_pb.QueryAccountAddressSpotOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_account_address_spot_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + account_address="inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_spot_orders_by_hashes( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedSpotLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.spot_orders_by_hashes_responses.append( + exchange_query_pb.QuerySpotOrdersByHashesResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_spot_orders_by_hashes( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + order_hashes=[order.order_hash], + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_subaccount_orders( + self, + exchange_servicer, + ): + buy_subaccount_order = exchange_pb.SubaccountOrder( + price="1000000000000000000", + quantity="1000000000000000", + isReduceOnly=False, + ) + buy_order = exchange_pb.SubaccountOrderData( + order=buy_subaccount_order, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849".encode(), + ) + sell_subaccount_order = exchange_pb.SubaccountOrder( + price="2000000000000000000", + quantity="2000000000000000", + isReduceOnly=False, + ) + sell_order = exchange_pb.SubaccountOrderData( + order=sell_subaccount_order, + order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2".encode(), + ) + exchange_servicer.subaccount_orders_responses.append( + exchange_query_pb.QuerySubaccountOrdersResponse( + buy_orders=[buy_order], + sell_orders=[sell_order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_subaccount_orders( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + expected_orders = { + "buyOrders": [ + { + "order": { + "price": buy_subaccount_order.price, + "quantity": buy_subaccount_order.quantity, + "isReduceOnly": buy_subaccount_order.isReduceOnly, + }, + "orderHash": base64.b64encode(buy_order.order_hash).decode(), + } + ], + "sellOrders": [ + { + "order": { + "price": sell_subaccount_order.price, + "quantity": sell_subaccount_order.quantity, + "isReduceOnly": sell_subaccount_order.isReduceOnly, + }, + "orderHash": base64.b64encode(sell_order.order_hash).decode(), + } + ], + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_trader_spot_transient_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedSpotLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.trader_spot_transient_orders_responses.append( + exchange_query_pb.QueryTraderSpotOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_spot_transient_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_spot_mid_price_and_tob( + self, + exchange_servicer, + ): + response = exchange_query_pb.QuerySpotMidPriceAndTOBResponse( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + exchange_servicer.spot_mid_price_and_tob_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + prices = await api.fetch_spot_mid_price_and_tob( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + expected_prices = { + "midPrice": response.mid_price, + "bestBuyPrice": response.best_buy_price, + "bestSellPrice": response.best_sell_price, + } + + assert prices == expected_prices + + @pytest.mark.asyncio + async def test_fetch_derivative_mid_price_and_tob( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryDerivativeMidPriceAndTOBResponse( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + exchange_servicer.derivative_mid_price_and_tob_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + prices = await api.fetch_derivative_mid_price_and_tob( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + expected_prices = { + "midPrice": response.mid_price, + "bestBuyPrice": response.best_buy_price, + "bestSellPrice": response.best_sell_price, + } + + assert prices == expected_prices + + @pytest.mark.asyncio + async def test_fetch_derivative_orderbook( + self, + exchange_servicer, + ): + buy_price_level = exchange_pb.Level( + p="1000000000000000000", + q="1000000000000000", + ) + sell_price_level = exchange_pb.Level( + p="2000000000000000000", + q="2000000000000000", + ) + exchange_servicer.derivative_orderbook_responses.append( + exchange_query_pb.QueryDerivativeOrderbookResponse( + buys_price_level=[buy_price_level], + sells_price_level=[sell_price_level], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orderbook = await api.fetch_derivative_orderbook( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + limit_cumulative_notional="1000000000000000000", + pagination=PaginationOption(limit=100), + ) + expected_orderbook = { + "buysPriceLevel": [ + { + "p": buy_price_level.p, + "q": buy_price_level.q, + } + ], + "sellsPriceLevel": [ + { + "p": sell_price_level.p, + "q": sell_price_level.q, + } + ], + } + + assert orderbook == expected_orderbook + + @pytest.mark.asyncio + async def test_fetch_trader_derivative_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + margin="1000000000000000000000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.trader_derivative_orders_responses.append( + exchange_query_pb.QueryTraderDerivativeOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_derivative_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_account_address_derivative_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + margin="1000000000000000000000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.account_address_derivative_orders_responses.append( + exchange_query_pb.QueryAccountAddressDerivativeOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_account_address_derivative_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + account_address="inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_derivative_orders_by_hashes( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + margin="1000000000000000000000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.derivative_orders_by_hashes_responses.append( + exchange_query_pb.QueryDerivativeOrdersByHashesResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_derivative_orders_by_hashes( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + order_hashes=[order.order_hash], + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_trader_derivative_transient_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + margin="1000000000000000000000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.trader_derivative_transient_orders_responses.append( + exchange_query_pb.QueryTraderDerivativeOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_derivative_transient_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_derivative_markets( + self, + exchange_servicer, + ): + market = exchange_pb.DerivativeMarket( + ticker="20250608/USDT", + oracle_base="0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3", + oracle_quote="0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588", + oracle_type=9, + oracle_scale_factor=6, + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + initial_margin_ratio="50000000000000000", + maintenance_margin_ratio="20000000000000000", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="400000000000000000", + isPerpetual=True, + status=1, + min_price_tick_size="100000000000000000000", + min_quantity_tick_size="1000000000000000", + ) + market_info = exchange_pb.PerpetualMarketInfo( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + hourly_funding_rate_cap="625000000000000", + hourly_interest_rate="4166660000000", + next_funding_timestamp=1708099200, + funding_interval=3600, + ) + funding_info = exchange_pb.PerpetualMarketFunding( + cumulative_funding="-107853477278881692857461", + cumulative_price="0", + last_timestamp=1708099200, + ) + perpetual_info = exchange_query_pb.PerpetualMarketState( + market_info=market_info, + funding_info=funding_info, + ) + mid_price_and_tob = exchange_pb.MidPriceAndTOB( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + full_market = exchange_query_pb.FullDerivativeMarket( + market=market, + perpetual_info=perpetual_info, + mark_price="33803835513327368963000000", + mid_price_and_tob=mid_price_and_tob, + ) + exchange_servicer.derivative_markets_responses.append( + exchange_query_pb.QueryDerivativeMarketsResponse( + markets=[full_market], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + markets = await api.fetch_derivative_markets( + status=status_string, + market_ids=[market.market_id], + ) + expected_markets = { + "markets": [ + { + "market": { + "ticker": market.ticker, + "oracleBase": market.oracle_base, + "oracleQuote": market.oracle_quote, + "oracleType": oracle_pb.OracleType.Name(market.oracle_type), + "oracleScaleFactor": market.oracle_scale_factor, + "quoteDenom": market.quote_denom, + "marketId": market.market_id, + "initialMarginRatio": market.initial_margin_ratio, + "maintenanceMarginRatio": market.maintenance_margin_ratio, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "isPerpetual": market.isPerpetual, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + }, + "perpetualInfo": { + "marketInfo": { + "marketId": market_info.market_id, + "hourlyFundingRateCap": market_info.hourly_funding_rate_cap, + "hourlyInterestRate": market_info.hourly_interest_rate, + "nextFundingTimestamp": str(market_info.next_funding_timestamp), + "fundingInterval": str(market_info.funding_interval), + }, + "fundingInfo": { + "cumulativeFunding": funding_info.cumulative_funding, + "cumulativePrice": funding_info.cumulative_price, + "lastTimestamp": str(funding_info.last_timestamp), + }, + }, + "markPrice": full_market.mark_price, + "midPriceAndTob": { + "midPrice": mid_price_and_tob.mid_price, + "bestBuyPrice": mid_price_and_tob.best_buy_price, + "bestSellPrice": mid_price_and_tob.best_sell_price, + }, + } + ] + } + + assert markets == expected_markets + + @pytest.mark.asyncio + async def test_fetch_derivative_market( + self, + exchange_servicer, + ): + market = exchange_pb.DerivativeMarket( + ticker="INJ/USDT PERP", + oracle_base="0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3", + oracle_quote="0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588", + oracle_type=9, + oracle_scale_factor=6, + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + initial_margin_ratio="50000000000000000", + maintenance_margin_ratio="20000000000000000", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="400000000000000000", + isPerpetual=True, + status=1, + min_price_tick_size="100000000000000000000", + min_quantity_tick_size="1000000000000000", + ) + market_info = exchange_pb.PerpetualMarketInfo( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + hourly_funding_rate_cap="625000000000000", + hourly_interest_rate="4166660000000", + next_funding_timestamp=1708099200, + funding_interval=3600, + ) + funding_info = exchange_pb.PerpetualMarketFunding( + cumulative_funding="-107853477278881692857461", + cumulative_price="0", + last_timestamp=1708099200, + ) + perpetual_info = exchange_query_pb.PerpetualMarketState( + market_info=market_info, + funding_info=funding_info, + ) + mid_price_and_tob = exchange_pb.MidPriceAndTOB( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + full_market = exchange_query_pb.FullDerivativeMarket( + market=market, + perpetual_info=perpetual_info, + mark_price="33803835513327368963000000", + mid_price_and_tob=mid_price_and_tob, + ) + exchange_servicer.derivative_market_responses.append( + exchange_query_pb.QueryDerivativeMarketResponse( + market=full_market, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + market_response = await api.fetch_derivative_market( + market_id=market.market_id, + ) + expected_market = { + "market": { + "market": { + "ticker": market.ticker, + "oracleBase": market.oracle_base, + "oracleQuote": market.oracle_quote, + "oracleType": oracle_pb.OracleType.Name(market.oracle_type), + "oracleScaleFactor": market.oracle_scale_factor, + "quoteDenom": market.quote_denom, + "marketId": market.market_id, + "initialMarginRatio": market.initial_margin_ratio, + "maintenanceMarginRatio": market.maintenance_margin_ratio, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "isPerpetual": market.isPerpetual, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + }, + "perpetualInfo": { + "marketInfo": { + "marketId": market_info.market_id, + "hourlyFundingRateCap": market_info.hourly_funding_rate_cap, + "hourlyInterestRate": market_info.hourly_interest_rate, + "nextFundingTimestamp": str(market_info.next_funding_timestamp), + "fundingInterval": str(market_info.funding_interval), + }, + "fundingInfo": { + "cumulativeFunding": funding_info.cumulative_funding, + "cumulativePrice": funding_info.cumulative_price, + "lastTimestamp": str(funding_info.last_timestamp), + }, + }, + "markPrice": full_market.mark_price, + "midPriceAndTob": { + "midPrice": mid_price_and_tob.mid_price, + "bestBuyPrice": mid_price_and_tob.best_buy_price, + "bestSellPrice": mid_price_and_tob.best_sell_price, + }, + } + } + + assert market_response == expected_market + + @pytest.mark.asyncio + async def test_fetch_derivative_market_address( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryDerivativeMarketAddressResponse( + address="inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9", + subaccount_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000", + ) + exchange_servicer.derivative_market_address_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + address = await api.fetch_derivative_market_address( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + expected_address = { + "address": response.address, + "subaccountId": response.subaccount_id, + } + + assert address == expected_address + + @pytest.mark.asyncio + async def test_fetch_subaccount_trade_nonce( + self, + exchange_servicer, + ): + response = exchange_query_pb.QuerySubaccountTradeNonceResponse(nonce=1234567879) + exchange_servicer.subaccount_trade_nonce_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + nonce = await api.fetch_subaccount_trade_nonce( + subaccount_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000", + ) + expected_nonce = { + "nonce": response.nonce, + } + + assert nonce == expected_nonce + + @pytest.mark.asyncio + async def test_fetch_positions( + self, + exchange_servicer, + ): + position = exchange_pb.Position( + isLong=True, + quantity="1000000000000000", + entry_price="2000000000000000000", + margin="2000000000000000000000000000000000", + cumulative_funding_entry="4000000", + ) + derivative_position = genesis_pb.DerivativePosition( + subaccount_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + position=position, + ) + exchange_servicer.positions_responses.append( + exchange_query_pb.QueryPositionsResponse(state=[derivative_position]) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + positions = await api.fetch_positions() + expected_positions = { + "state": [ + { + "subaccountId": derivative_position.subaccount_id, + "marketId": derivative_position.market_id, + "position": { + "isLong": position.isLong, + "quantity": position.quantity, + "entryPrice": position.entry_price, + "margin": position.margin, + "cumulativeFundingEntry": position.cumulative_funding_entry, + }, + }, + ], + } + + assert positions == expected_positions + + @pytest.mark.asyncio + async def test_fetch_subaccount_positions( + self, + exchange_servicer, + ): + position = exchange_pb.Position( + isLong=True, + quantity="1000000000000000", + entry_price="2000000000000000000", + margin="2000000000000000000000000000000000", + cumulative_funding_entry="4000000", + ) + derivative_position = genesis_pb.DerivativePosition( + subaccount_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + position=position, + ) + exchange_servicer.subaccount_positions_responses.append( + exchange_query_pb.QuerySubaccountPositionsResponse(state=[derivative_position]) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + positions = await api.fetch_subaccount_positions(subaccount_id=derivative_position.subaccount_id) + expected_positions = { + "state": [ + { + "subaccountId": derivative_position.subaccount_id, + "marketId": derivative_position.market_id, + "position": { + "isLong": position.isLong, + "quantity": position.quantity, + "entryPrice": position.entry_price, + "margin": position.margin, + "cumulativeFundingEntry": position.cumulative_funding_entry, + }, + }, + ], + } + + assert positions == expected_positions + + @pytest.mark.asyncio + async def test_fetch_subaccount_position_in_market( + self, + exchange_servicer, + ): + subaccount_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000" + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + position = exchange_pb.Position( + isLong=True, + quantity="1000000000000000", + entry_price="2000000000000000000", + margin="2000000000000000000000000000000000", + cumulative_funding_entry="4000000", + ) + exchange_servicer.subaccount_position_in_market_responses.append( + exchange_query_pb.QuerySubaccountPositionInMarketResponse(state=position) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + position_response = await api.fetch_subaccount_position_in_market( + subaccount_id=subaccount_id, + market_id=market_id, + ) + expected_position = { + "state": { + "isLong": position.isLong, + "quantity": position.quantity, + "entryPrice": position.entry_price, + "margin": position.margin, + "cumulativeFundingEntry": position.cumulative_funding_entry, + }, + } + + assert position_response == expected_position + + @pytest.mark.asyncio + async def test_fetch_subaccount_effective_position_in_market( + self, + exchange_servicer, + ): + subaccount_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000" + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + + effective_position = exchange_query_pb.EffectivePosition( + is_long=True, + quantity="1000000000000000", + entry_price="2000000000000000000", + effective_margin="2000000000000000000000000000000000", + ) + exchange_servicer.subaccount_effective_position_in_market_responses.append( + exchange_query_pb.QuerySubaccountEffectivePositionInMarketResponse(state=effective_position) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + position_response = await api.fetch_subaccount_effective_position_in_market( + subaccount_id=subaccount_id, + market_id=market_id, + ) + expected_position = { + "state": { + "isLong": effective_position.is_long, + "quantity": effective_position.quantity, + "entryPrice": effective_position.entry_price, + "effectiveMargin": effective_position.effective_margin, + }, + } + + assert position_response == expected_position + + @pytest.mark.asyncio + async def test_fetch_perpetual_market_info( + self, + exchange_servicer, + ): + perpetual_market_info = exchange_pb.PerpetualMarketInfo( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + hourly_funding_rate_cap="625000000000000", + hourly_interest_rate="4166660000000", + next_funding_timestamp=1708099200, + funding_interval=3600, + ) + exchange_servicer.perpetual_market_info_responses.append( + exchange_query_pb.QueryPerpetualMarketInfoResponse(info=perpetual_market_info) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + market_info = await api.fetch_perpetual_market_info(market_id=perpetual_market_info.market_id) + expected_market_info = { + "info": { + "marketId": perpetual_market_info.market_id, + "hourlyFundingRateCap": perpetual_market_info.hourly_funding_rate_cap, + "hourlyInterestRate": perpetual_market_info.hourly_interest_rate, + "nextFundingTimestamp": str(perpetual_market_info.next_funding_timestamp), + "fundingInterval": str(perpetual_market_info.funding_interval), + } + } + + assert market_info == expected_market_info + + @pytest.mark.asyncio + async def test_fetch_expiry_futures_market_info( + self, + exchange_servicer, + ): + expiry_futures_market_info = exchange_pb.ExpiryFuturesMarketInfo( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + expiration_timestamp=1708099200, + twap_start_timestamp=1705566200, + expiration_twap_start_price_cumulative="1000000000000000000", + settlement_price="2000000000000000000", + ) + exchange_servicer.expiry_futures_market_info_responses.append( + exchange_query_pb.QueryExpiryFuturesMarketInfoResponse(info=expiry_futures_market_info) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + market_info = await api.fetch_expiry_futures_market_info(market_id=expiry_futures_market_info.market_id) + expected_market_info = { + "info": { + "marketId": expiry_futures_market_info.market_id, + "expirationTimestamp": str(expiry_futures_market_info.expiration_timestamp), + "twapStartTimestamp": str(expiry_futures_market_info.twap_start_timestamp), + "expirationTwapStartPriceCumulative": expiry_futures_market_info.expiration_twap_start_price_cumulative, + "settlementPrice": expiry_futures_market_info.settlement_price, + } + } + + assert market_info == expected_market_info + + @pytest.mark.asyncio + async def test_fetch_perpetual_market_funding( + self, + exchange_servicer, + ): + perpetual_market_funding = exchange_pb.PerpetualMarketFunding( + cumulative_funding="-107853477278881692857461", + cumulative_price="0", + last_timestamp=1708099200, + ) + exchange_servicer.perpetual_market_funding_responses.append( + exchange_query_pb.QueryPerpetualMarketFundingResponse(state=perpetual_market_funding) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + funding = await api.fetch_perpetual_market_funding( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + ) + expected_funding = { + "state": { + "cumulativeFunding": perpetual_market_funding.cumulative_funding, + "cumulativePrice": perpetual_market_funding.cumulative_price, + "lastTimestamp": str(perpetual_market_funding.last_timestamp), + } + } + + assert funding == expected_funding + + @pytest.mark.asyncio + async def test_fetch_subaccount_order_metadata( + self, + exchange_servicer, + ): + metadata = exchange_pb.SubaccountOrderbookMetadata( + vanilla_limit_order_count=1, + reduce_only_limit_order_count=2, + aggregate_reduce_only_quantity="1000000000000000", + aggregate_vanilla_quantity="2000000000000000", + vanilla_conditional_order_count=3, + reduce_only_conditional_order_count=4, + ) + subaccount_order_metadata = exchange_query_pb.SubaccountOrderbookMetadataWithMarket( + metadata=metadata, + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + isBuy=True, + ) + exchange_servicer.subaccount_order_metadata_responses.append( + exchange_query_pb.QuerySubaccountOrderMetadataResponse(metadata=[subaccount_order_metadata]) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + metadata_response = await api.fetch_subaccount_order_metadata( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001" + ) + expected_metadata = { + "metadata": [ + { + "metadata": { + "vanillaLimitOrderCount": metadata.vanilla_limit_order_count, + "reduceOnlyLimitOrderCount": metadata.reduce_only_limit_order_count, + "aggregateReduceOnlyQuantity": metadata.aggregate_reduce_only_quantity, + "aggregateVanillaQuantity": metadata.aggregate_vanilla_quantity, + "vanillaConditionalOrderCount": metadata.vanilla_conditional_order_count, + "reduceOnlyConditionalOrderCount": metadata.reduce_only_conditional_order_count, + }, + "marketId": subaccount_order_metadata.market_id, + "isBuy": subaccount_order_metadata.isBuy, + }, + ] + } + + assert metadata_response == expected_metadata + + @pytest.mark.asyncio + async def test_fetch_trade_reward_points( + self, + exchange_servicer, + ): + points = "40" + response = exchange_query_pb.QueryTradeRewardPointsResponse(account_trade_reward_points=[points]) + exchange_servicer.trade_reward_points_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + trade_reward_points = await api.fetch_trade_reward_points( + accounts=["inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"], + pending_pool_timestamp=1708099200, + ) + expected_trade_reward_points = {"accountTradeRewardPoints": [points]} + + assert trade_reward_points == expected_trade_reward_points + + @pytest.mark.asyncio + async def test_fetch_pending_trade_reward_points( + self, + exchange_servicer, + ): + points = "40" + response = exchange_query_pb.QueryTradeRewardPointsResponse(account_trade_reward_points=[points]) + exchange_servicer.pending_trade_reward_points_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + trade_reward_points = await api.fetch_pending_trade_reward_points( + accounts=["inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"], + pending_pool_timestamp=1708099200, + ) + expected_trade_reward_points = {"accountTradeRewardPoints": [points]} + + assert trade_reward_points == expected_trade_reward_points + + @pytest.mark.asyncio + async def test_fetch_fee_discount_account_info( + self, + exchange_servicer, + ): + account_info = exchange_pb.FeeDiscountTierInfo( + maker_discount_rate="0.0001", + taker_discount_rate="0.0002", + staked_amount="1000000000", + volume="1000000000000000000", + ) + account_ttl = exchange_pb.FeeDiscountTierTTL( + tier=3, + ttl_timestamp=1708099200, + ) + response = exchange_query_pb.QueryFeeDiscountAccountInfoResponse( + tier_level=3, + account_info=account_info, + account_ttl=account_ttl, + ) + exchange_servicer.fee_discount_account_info_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + fee_discount = await api.fetch_fee_discount_account_info(account="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r") + expected_fee_discount = { + "tierLevel": str(response.tier_level), + "accountInfo": { + "makerDiscountRate": account_info.maker_discount_rate, + "takerDiscountRate": account_info.taker_discount_rate, + "stakedAmount": account_info.staked_amount, + "volume": account_info.volume, + }, + "accountTtl": { + "tier": str(account_ttl.tier), + "ttlTimestamp": str(account_ttl.ttl_timestamp), + }, + } + + assert fee_discount == expected_fee_discount + + @pytest.mark.asyncio + async def test_fetch_fee_discount_schedule( + self, + exchange_servicer, + ): + fee_discount_tier_info = exchange_pb.FeeDiscountTierInfo( + maker_discount_rate="0.0001", + taker_discount_rate="0.0002", + staked_amount="1000000000", + volume="1000000000000000000", + ) + fee_discount_schedule = exchange_pb.FeeDiscountSchedule( + bucket_count=3, + bucket_duration=3600, + quote_denoms=["peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"], + tier_infos=[fee_discount_tier_info], + disqualified_market_ids=["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"], + ) + exchange_servicer.fee_discount_schedule_responses.append( + exchange_query_pb.QueryFeeDiscountScheduleResponse( + fee_discount_schedule=fee_discount_schedule, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + schedule = await api.fetch_fee_discount_schedule() + expected_schedule = { + "feeDiscountSchedule": { + "bucketCount": str(fee_discount_schedule.bucket_count), + "bucketDuration": str(fee_discount_schedule.bucket_duration), + "quoteDenoms": fee_discount_schedule.quote_denoms, + "tierInfos": [ + { + "makerDiscountRate": fee_discount_tier_info.maker_discount_rate, + "takerDiscountRate": fee_discount_tier_info.taker_discount_rate, + "stakedAmount": fee_discount_tier_info.staked_amount, + "volume": fee_discount_tier_info.volume, + } + ], + "disqualifiedMarketIds": fee_discount_schedule.disqualified_market_ids, + }, + } + + assert schedule == expected_schedule + + @pytest.mark.asyncio + async def test_fetch_balance_mismatches( + self, + exchange_servicer, + ): + balance_mismatch = exchange_query_pb.BalanceMismatch( + subaccountId="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + available="1000000000000000", + total="2000000000000000", + balance_hold="3000000000000000", + expected_total="4000000000000000", + difference="500000000000000", + ) + exchange_servicer.balance_mismatches_responses.append( + exchange_query_pb.QueryBalanceMismatchesResponse( + balance_mismatches=[balance_mismatch], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + mismatches = await api.fetch_balance_mismatches(dust_factor=20) + expected_mismatches = { + "balanceMismatches": [ + { + "subaccountId": balance_mismatch.subaccountId, + "denom": balance_mismatch.denom, + "available": balance_mismatch.available, + "total": balance_mismatch.total, + "balanceHold": balance_mismatch.balance_hold, + "expectedTotal": balance_mismatch.expected_total, + "difference": balance_mismatch.difference, + } + ], + } + + assert mismatches == expected_mismatches + + @pytest.mark.asyncio + async def test_fetch_balance_with_balance_holds( + self, + exchange_servicer, + ): + balance_with_balance_hold = exchange_query_pb.BalanceWithMarginHold( + subaccountId="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + available="1000000000000000", + total="2000000000000000", + balance_hold="3000000000000000", + ) + exchange_servicer.balance_with_balance_holds_responses.append( + exchange_query_pb.QueryBalanceWithBalanceHoldsResponse( + balance_with_balance_holds=[balance_with_balance_hold], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + balance = await api.fetch_balance_with_balance_holds() + expected_balance = { + "balanceWithBalanceHolds": [ + { + "subaccountId": balance_with_balance_hold.subaccountId, + "denom": balance_with_balance_hold.denom, + "available": balance_with_balance_hold.available, + "total": balance_with_balance_hold.total, + "balanceHold": balance_with_balance_hold.balance_hold, + } + ], + } + + assert balance == expected_balance + + @pytest.mark.asyncio + async def test_fetch_fee_discount_tier_statistics( + self, + exchange_servicer, + ): + tier_statistics = exchange_query_pb.TierStatistic( + tier=3, + count=30, + ) + exchange_servicer.fee_discount_tier_statistics_responses.append( + exchange_query_pb.QueryFeeDiscountTierStatisticsResponse( + statistics=[tier_statistics], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + statistics = await api.fetch_fee_discount_tier_statistics() + expected_statistics = { + "statistics": [ + { + "tier": str(tier_statistics.tier), + "count": str(tier_statistics.count), + } + ], + } + + assert statistics == expected_statistics + + @pytest.mark.asyncio + async def test_fetch_mito_vault_infos( + self, + exchange_servicer, + ): + master_address = "inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9" + derivative_address = "inj1zlh5" + spot_address = "inj1zlh6" + cw20_address = "inj1zlh7" + response = exchange_query_pb.MitoVaultInfosResponse( + master_addresses=[master_address], + derivative_addresses=[derivative_address], + spot_addresses=[spot_address], + cw20_addresses=[cw20_address], + ) + exchange_servicer.mito_vault_infos_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + mito_vaults = await api.fetch_mito_vault_infos() + expected_mito_vaults = { + "masterAddresses": [master_address], + "derivativeAddresses": [derivative_address], + "spotAddresses": [spot_address], + "cw20Addresses": [cw20_address], + } + + assert mito_vaults == expected_mito_vaults + + @pytest.mark.asyncio + async def test_fetch_market_id_from_vault( + self, + exchange_servicer, + ): + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + exchange_servicer.market_id_from_vault_responses.append( + exchange_query_pb.QueryMarketIDFromVaultResponse( + market_id=market_id, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + market_id_response = await api.fetch_market_id_from_vault( + vault_address="inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9" + ) + expected_market_id = { + "marketId": market_id, + } + + assert market_id_response == expected_market_id + + @pytest.mark.asyncio + async def test_fetch_historical_trade_records( + self, + exchange_servicer, + ): + latest_trade_record = exchange_pb.TradeRecord( + timestamp=1708099200, + price="2000000000000000000", + quantity="1000000000000000", + ) + trade_record = exchange_pb.TradeRecords( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + latest_trade_records=[latest_trade_record], + ) + exchange_servicer.historical_trade_records_responses.append( + exchange_query_pb.QueryHistoricalTradeRecordsResponse( + trade_records=[trade_record], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + records = await api.fetch_historical_trade_records(market_id=trade_record.market_id) + expected_records = { + "tradeRecords": [ + { + "marketId": trade_record.market_id, + "latestTradeRecords": [ + { + "timestamp": str(latest_trade_record.timestamp), + "price": latest_trade_record.price, + "quantity": latest_trade_record.quantity, + } + ], + }, + ], + } + + assert records == expected_records + + @pytest.mark.asyncio + async def test_fetch_is_opted_out_of_rewards( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryIsOptedOutOfRewardsResponse( + is_opted_out=False, + ) + exchange_servicer.is_opted_out_of_rewards_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + is_opted_out = await api.fetch_is_opted_out_of_rewards(account="inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9") + expected_is_opted_out = { + "isOptedOut": response.is_opted_out, + } + + assert is_opted_out == expected_is_opted_out + + @pytest.mark.asyncio + async def test_fetch_opted_out_of_rewards_accounts( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryOptedOutOfRewardsAccountsResponse( + accounts=["inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9"], + ) + exchange_servicer.opted_out_of_rewards_accounts_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + opted_out = await api.fetch_opted_out_of_rewards_accounts() + expected_opted_out = { + "accounts": response.accounts, + } + + assert opted_out == expected_opted_out + + @pytest.mark.asyncio + async def test_fetch_market_volatility( + self, + exchange_servicer, + ): + history_metadata = oracle_pb.MetadataStatistics( + group_count=2, + records_sample_size=10, + mean="0.0001", + twap="0.0005", + first_timestamp=1702399200, + last_timestamp=1708099200, + min_price="1000000000000", + max_price="3000000000000", + median_price="2000000000000", + ) + trade_record = exchange_pb.TradeRecord( + timestamp=1708099200, + price="2000000000000000000", + quantity="1000000000000000", + ) + response = exchange_query_pb.QueryMarketVolatilityResponse( + volatility="0.0001", history_metadata=history_metadata, raw_history=[trade_record] + ) + exchange_servicer.market_volatility_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volatility = await api.fetch_market_volatility( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + trade_grouping_sec=0, + max_age=28000000, + include_raw_history=True, + include_metadata=True, + ) + expected_volatility = { + "volatility": response.volatility, + "historyMetadata": { + "groupCount": history_metadata.group_count, + "recordsSampleSize": history_metadata.records_sample_size, + "mean": history_metadata.mean, + "twap": history_metadata.twap, + "firstTimestamp": str(history_metadata.first_timestamp), + "lastTimestamp": str(history_metadata.last_timestamp), + "minPrice": history_metadata.min_price, + "maxPrice": history_metadata.max_price, + "medianPrice": history_metadata.median_price, + }, + "rawHistory": [ + { + "timestamp": str(trade_record.timestamp), + "price": trade_record.price, + "quantity": trade_record.quantity, + } + ], + } + + assert volatility == expected_volatility + + @pytest.mark.asyncio + async def test_fetch_binary_options_markets( + self, + exchange_servicer, + ): + market = exchange_pb.BinaryOptionsMarket( + ticker="20250608/USDT", + oracle_symbol="0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3", + oracle_provider="Pyth", + oracle_type=9, + oracle_scale_factor=6, + expiration_timestamp=1708099200, + settlement_timestamp=1707099200, + admin="inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="400000000000000000", + status=1, + min_price_tick_size="100000000000000000000", + min_quantity_tick_size="1000000000000000", + settlement_price="2000000000000000000", + ) + response = exchange_query_pb.QueryBinaryMarketsResponse( + markets=[market], + ) + exchange_servicer.binary_options_markets_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + markets = await api.fetch_binary_options_markets(status="Active") + expected_markets = { + "markets": [ + { + "ticker": market.ticker, + "oracleSymbol": market.oracle_symbol, + "oracleProvider": market.oracle_provider, + "oracleType": oracle_pb.OracleType.Name(market.oracle_type), + "oracleScaleFactor": market.oracle_scale_factor, + "expirationTimestamp": str(market.expiration_timestamp), + "settlementTimestamp": str(market.settlement_timestamp), + "admin": market.admin, + "quoteDenom": market.quote_denom, + "marketId": market.market_id, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "status": exchange_pb.MarketStatus.Name(market.status), + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + "settlementPrice": market.settlement_price, + }, + ] + } + + assert markets == expected_markets + + @pytest.mark.asyncio + async def test_fetch_trader_derivative_conditional_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeConditionalOrder( + price="2000000000000000000", + quantity="1000000000000000", + margin="2000000000000000000000000000000000", + triggerPrice="3000000000000000000", + isBuy=True, + isLimit=True, + order_hash="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + response = exchange_query_pb.QueryTraderDerivativeConditionalOrdersResponse(orders=[order]) + exchange_servicer.trader_derivative_conditional_orders_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_derivative_conditional_orders( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "triggerPrice": order.triggerPrice, + "isBuy": order.isBuy, + "isLimit": order.isLimit, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_market_atomic_execution_fee_multiplier( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryMarketAtomicExecutionFeeMultiplierResponse( + multiplier="100", + ) + exchange_servicer.market_atomic_execution_fee_multiplier_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + multiplier = await api.fetch_market_atomic_execution_fee_multiplier( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + expected_multiplier = { + "multiplier": response.multiplier, + } + + assert multiplier == expected_multiplier + + async def _dummy_metadata_provider(self): + return None From 96c79c023225db49ed8a07131385640b5f526f87 Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 27 Feb 2024 10:03:11 -0300 Subject: [PATCH 2/7] (feat) Added support for all chain exchange module messages in Composer. Added unit tests for new messages. Refactored example scripts to move them into separated subfolders for each module. --- ..._LocalOrderHash.py => 1_LocalOrderHash.py} | 101 +- ...OrderFail.py => 2_StreamEventOrderFail.py} | 0 .../35_MsgInstantBinaryOptionsMarketLaunch.py | 98 - ...Broadcaster.py => 3_MessageBroadcaster.py} | 21 +- ...4_MessageBroadcasterWithGranteeAccount.py} | 12 +- ... 5_MessageBroadcasterWithoutSimulation.py} | 19 +- ...terWithGranteeAccountWithoutSimulation.py} | 12 +- .../{49_ChainStream.py => 7_ChainStream.py} | 0 .../{18_MsgBid.py => auction/1_MsgBid.py} | 0 .../query/1_Account.py} | 0 .../{19_MsgGrant.py => authz/1_MsgGrant.py} | 0 .../{20_MsgExec.py => authz/2_MsgExec.py} | 10 +- .../{21_MsgRevoke.py => authz/3_MsgRevoke.py} | 0 .../4_MsgExecuteContractCompat.py} | 0 .../{27_Grants.py => authz/query/1_Grants.py} | 0 examples/chain_client/{ => bank}/1_MsgSend.py | 0 .../query/10_SendEnabled.py} | 0 .../query/1_BankBalance.py} | 0 .../query/2_BankBalances.py} | 0 .../query/3_SpendableBalances.py} | 0 .../query/4_SpendableBalancesByDenom.py} | 0 .../query/5_TotalSupply.py} | 0 .../query/6_SupplyOf.py} | 0 .../query/7_DenomMetadata.py} | 0 .../query/8_DenomsMetadata.py} | 0 .../query/9_DenomOwners.py} | 0 ...py => 10_MsgCreateDerivativeLimitOrder.py} | 14 +- ...y => 11_MsgCreateDerivativeMarketOrder.py} | 12 +- ...rder.py => 12_MsgCancelDerivativeOrder.py} | 2 +- .../13_MsgInstantBinaryOptionsMarketLaunch.py | 61 + ...=> 14_MsgCreateBinaryOptionsLimitOrder.py} | 13 +- ...> 15_MsgCreateBinaryOptionsMarketOrder.py} | 12 +- ...r.py => 16_MsgCancelBinaryOptionsOrder.py} | 2 +- ...ransfer.py => 17_MsgSubaccountTransfer.py} | 5 +- ...lTransfer.py => 18_MsgExternalTransfer.py} | 5 +- .../exchange/19_MsgLiquidatePosition.py | 15 +- .../chain_client/exchange/1_MsgDeposit.py | 4 +- .../20_MsgIncreasePositionMargin.py} | 5 +- ...ewardsOptOut.py => 21_MsgRewardsOptOut.py} | 2 +- .../22_MsgAdminUpdateBinaryOptionsMarket.py} | 5 +- .../{9_MsgWithdraw.py => 2_MsgWithdraw.py} | 2 +- .../exchange/3_MsgInstantSpotMarketLaunch.py | 54 + .../4_MsgInstantPerpetualMarketLaunch.py | 61 + .../5_MsgInstantExpiryFuturesMarketLaunch.py | 62 + ...tOrder.py => 6_MsgCreateSpotLimitOrder.py} | 10 +- ...Order.py => 7_MsgCreateSpotMarketOrder.py} | 11 +- ...elSpotOrder.py => 8_MsgCancelSpotOrder.py} | 0 ...ateOrders.py => 9_MsgBatchUpdateOrders.py} | 53 +- .../1_MsgCreateInsuranceFund.py} | 0 .../2_MsgUnderwrite.py} | 0 .../3_MsgRequestRedemption.py} | 0 .../1_MsgRelayPriceFeedPrice.py} | 0 .../2_MsgRelayProviderPrices.py} | 0 .../1_MsgSendToEth.py} | 0 .../1_MsgDelegate.py} | 0 .../1_CreateDenom.py} | 0 .../2_MsgMint.py} | 0 .../3_MsgBurn.py} | 0 .../4_MsgChangeAdmin.py} | 0 .../5_MsgSetDenomMetadata.py} | 0 .../query/1_DenomAuthorityMetadata.py} | 0 .../query/2_DenomsFromCreator.py} | 0 .../query/3_TokenfactoryModuleState.py} | 0 .../{37_GetTx.py => tx/query/1_GetTx.py} | 0 .../1_MsgExecuteContract.py} | 0 .../query/10_ContractsByCreator.py} | 0 .../query/1_ContractInfo.py} | 0 .../query/2_ContractHistory.py} | 0 .../query/3_ContractsByCode.py} | 0 .../query/4_AllContractsState.py} | 0 .../query/5_RawContractState.py} | 0 .../query/6_SmartContractState.py} | 0 .../query/7_SmartContractCode.py} | 0 .../query/8_SmartContractCodes.py} | 0 .../query/9_SmartContractPinnedCodes.py} | 0 pyinjective/composer.py | 1751 +++++++++++++---- pyinjective/core/market.py | 11 + tests/core/test_gas_limit_estimator.py | 158 +- tests/core/test_market.py | 36 + ...essage_based_transaction_fee_calculator.py | 27 +- tests/test_composer.py | 1466 ++++++++++++-- tests/test_composer_deprecation_warnings.py | 522 +++++ tests/test_orderhash.py | 20 +- 83 files changed, 3740 insertions(+), 934 deletions(-) rename examples/chain_client/{0_LocalOrderHash.py => 1_LocalOrderHash.py} (75%) rename examples/chain_client/{38_StreamEventOrderFail.py => 2_StreamEventOrderFail.py} (100%) delete mode 100644 examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py rename examples/chain_client/{44_MessageBroadcaster.py => 3_MessageBroadcaster.py} (84%) rename examples/chain_client/{45_MessageBroadcasterWithGranteeAccount.py => 4_MessageBroadcasterWithGranteeAccount.py} (91%) rename examples/chain_client/{46_MessageBroadcasterWithoutSimulation.py => 5_MessageBroadcasterWithoutSimulation.py} (86%) rename examples/chain_client/{47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py => 6_MessageBroadcasterWithGranteeAccountWithoutSimulation.py} (91%) rename examples/chain_client/{49_ChainStream.py => 7_ChainStream.py} (100%) rename examples/chain_client/{18_MsgBid.py => auction/1_MsgBid.py} (100%) rename examples/chain_client/{39_Account.py => auth/query/1_Account.py} (100%) rename examples/chain_client/{19_MsgGrant.py => authz/1_MsgGrant.py} (100%) rename examples/chain_client/{20_MsgExec.py => authz/2_MsgExec.py} (95%) rename examples/chain_client/{21_MsgRevoke.py => authz/3_MsgRevoke.py} (100%) rename examples/chain_client/{76_MsgExecuteContractCompat.py => authz/4_MsgExecuteContractCompat.py} (100%) rename examples/chain_client/{27_Grants.py => authz/query/1_Grants.py} (100%) rename examples/chain_client/{ => bank}/1_MsgSend.py (100%) rename examples/chain_client/{57_SendEnabled.py => bank/query/10_SendEnabled.py} (100%) rename examples/chain_client/{29_BankBalance.py => bank/query/1_BankBalance.py} (100%) rename examples/chain_client/{28_BankBalances.py => bank/query/2_BankBalances.py} (100%) rename examples/chain_client/{50_SpendableBalances.py => bank/query/3_SpendableBalances.py} (100%) rename examples/chain_client/{51_SpendableBalancesByDenom.py => bank/query/4_SpendableBalancesByDenom.py} (100%) rename examples/chain_client/{52_TotalSupply.py => bank/query/5_TotalSupply.py} (100%) rename examples/chain_client/{53_SupplyOf.py => bank/query/6_SupplyOf.py} (100%) rename examples/chain_client/{54_DenomMetadata.py => bank/query/7_DenomMetadata.py} (100%) rename examples/chain_client/{55_DenomsMetadata.py => bank/query/8_DenomsMetadata.py} (100%) rename examples/chain_client/{56_DenomOwners.py => bank/query/9_DenomOwners.py} (100%) rename examples/chain_client/exchange/{6_MsgCreateDerivativeLimitOrder.py => 10_MsgCreateDerivativeLimitOrder.py} (90%) rename examples/chain_client/exchange/{7_MsgCreateDerivativeMarketOrder.py => 11_MsgCreateDerivativeMarketOrder.py} (90%) rename examples/chain_client/exchange/{8_MsgCancelDerivativeOrder.py => 12_MsgCancelDerivativeOrder.py} (98%) create mode 100644 examples/chain_client/exchange/13_MsgInstantBinaryOptionsMarketLaunch.py rename examples/chain_client/exchange/{16_MsgCreateBinaryOptionsLimitOrder.py => 14_MsgCreateBinaryOptionsLimitOrder.py} (93%) rename examples/chain_client/exchange/{17_MsgCreateBinaryOptionsMarketOrder.py => 15_MsgCreateBinaryOptionsMarketOrder.py} (90%) rename examples/chain_client/exchange/{18_MsgCancelBinaryOptionsOrder.py => 16_MsgCancelBinaryOptionsOrder.py} (98%) rename examples/chain_client/exchange/{10_MsgSubaccountTransfer.py => 17_MsgSubaccountTransfer.py} (96%) rename examples/chain_client/exchange/{15_ExternalTransfer.py => 18_MsgExternalTransfer.py} (96%) rename examples/chain_client/{13_MsgIncreasePositionMargin.py => exchange/20_MsgIncreasePositionMargin.py} (96%) rename examples/chain_client/exchange/{12_MsgRewardsOptOut.py => 21_MsgRewardsOptOut.py} (97%) rename examples/chain_client/{34_MsgAdminUpdateBinaryOptionsMarket.py => exchange/22_MsgAdminUpdateBinaryOptionsMarket.py} (96%) rename examples/chain_client/exchange/{9_MsgWithdraw.py => 2_MsgWithdraw.py} (95%) create mode 100644 examples/chain_client/exchange/3_MsgInstantSpotMarketLaunch.py create mode 100644 examples/chain_client/exchange/4_MsgInstantPerpetualMarketLaunch.py create mode 100644 examples/chain_client/exchange/5_MsgInstantExpiryFuturesMarketLaunch.py rename examples/chain_client/exchange/{3_MsgCreateSpotLimitOrder.py => 6_MsgCreateSpotLimitOrder.py} (94%) rename examples/chain_client/exchange/{4_MsgCreateSpotMarketOrder.py => 7_MsgCreateSpotMarketOrder.py} (94%) rename examples/chain_client/exchange/{5_MsgCancelSpotOrder.py => 8_MsgCancelSpotOrder.py} (100%) rename examples/chain_client/exchange/{11_MsgBatchUpdateOrders.py => 9_MsgBatchUpdateOrders.py} (83%) rename examples/chain_client/{41_MsgCreateInsuranceFund.py => insurance/1_MsgCreateInsuranceFund.py} (100%) rename examples/chain_client/{42_MsgUnderwrite.py => insurance/2_MsgUnderwrite.py} (100%) rename examples/chain_client/{43_MsgRequestRedemption.py => insurance/3_MsgRequestRedemption.py} (100%) rename examples/chain_client/{23_MsgRelayPriceFeedPrice.py => oracle/1_MsgRelayPriceFeedPrice.py} (100%) rename examples/chain_client/{36_MsgRelayProviderPrices.py => oracle/2_MsgRelayProviderPrices.py} (100%) rename examples/chain_client/{22_MsgSendToEth.py => peggy/1_MsgSendToEth.py} (100%) rename examples/chain_client/{25_MsgDelegate.py => staking/1_MsgDelegate.py} (100%) rename examples/chain_client/{71_CreateDenom.py => tokenfactory/1_CreateDenom.py} (100%) rename examples/chain_client/{72_MsgMint.py => tokenfactory/2_MsgMint.py} (100%) rename examples/chain_client/{73_MsgBurn.py => tokenfactory/3_MsgBurn.py} (100%) rename examples/chain_client/{75_MsgChangeAdmin.py => tokenfactory/4_MsgChangeAdmin.py} (100%) rename examples/chain_client/{74_MsgSetDenomMetadata.py => tokenfactory/5_MsgSetDenomMetadata.py} (100%) rename examples/chain_client/{68_DenomAuthorityMetadata.py => tokenfactory/query/1_DenomAuthorityMetadata.py} (100%) rename examples/chain_client/{69_DenomsFromCreator.py => tokenfactory/query/2_DenomsFromCreator.py} (100%) rename examples/chain_client/{70_TokenfactoryModuleState.py => tokenfactory/query/3_TokenfactoryModuleState.py} (100%) rename examples/chain_client/{37_GetTx.py => tx/query/1_GetTx.py} (100%) rename examples/chain_client/{40_MsgExecuteContract.py => wasm/1_MsgExecuteContract.py} (100%) rename examples/chain_client/{67_ContractsByCreator.py => wasm/query/10_ContractsByCreator.py} (100%) rename examples/chain_client/{58_ContractInfo.py => wasm/query/1_ContractInfo.py} (100%) rename examples/chain_client/{59_ContractHistory.py => wasm/query/2_ContractHistory.py} (100%) rename examples/chain_client/{60_ContractsByCode.py => wasm/query/3_ContractsByCode.py} (100%) rename examples/chain_client/{61_AllContractsState.py => wasm/query/4_AllContractsState.py} (100%) rename examples/chain_client/{62_RawContractState.py => wasm/query/5_RawContractState.py} (100%) rename examples/chain_client/{63_SmartContractState.py => wasm/query/6_SmartContractState.py} (100%) rename examples/chain_client/{64_SmartContractCode.py => wasm/query/7_SmartContractCode.py} (100%) rename examples/chain_client/{65_SmartContractCodes.py => wasm/query/8_SmartContractCodes.py} (100%) rename examples/chain_client/{66_SmartContractPinnedCodes.py => wasm/query/9_SmartContractPinnedCodes.py} (100%) create mode 100644 tests/test_composer_deprecation_warnings.py diff --git a/examples/chain_client/0_LocalOrderHash.py b/examples/chain_client/1_LocalOrderHash.py similarity index 75% rename from examples/chain_client/0_LocalOrderHash.py rename to examples/chain_client/1_LocalOrderHash.py index 770ad5bf..fbec8988 100644 --- a/examples/chain_client/0_LocalOrderHash.py +++ b/examples/chain_client/1_LocalOrderHash.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -40,57 +41,59 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" spot_orders = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=0.524, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("0.524"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=27.92, - quantity=0.01, - is_buy=False, - is_po=False, + price=Decimal("27.92"), + quantity=Decimal("0.01"), + order_type="SELL", cid=str(uuid.uuid4()), ), ] derivative_orders = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=deriv_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=10500, - quantity=0.01, - leverage=1.5, - is_buy=True, - is_po=False, + price=Decimal(10500), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(10500), leverage=Decimal(2), is_reduce_only=False + ), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.DerivativeOrder( + composer.derivative_order( market_id=deriv_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=65111, - quantity=0.01, - leverage=2, - is_buy=False, - is_reduce_only=False, + price=Decimal(65111), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(65111), leverage=Decimal(2), is_reduce_only=False + ), + order_type="SELL", cid=str(uuid.uuid4()), ), ] # prepare tx msg - spot_msg = composer.MsgBatchCreateSpotLimitOrders(sender=address.to_acc_bech32(), orders=spot_orders) + spot_msg = composer.msg_batch_create_spot_limit_orders(sender=address.to_acc_bech32(), orders=spot_orders) - deriv_msg = composer.MsgBatchCreateDerivativeLimitOrders(sender=address.to_acc_bech32(), orders=derivative_orders) + deriv_msg = composer.msg_batch_create_derivative_limit_orders( + sender=address.to_acc_bech32(), orders=derivative_orders + ) # compute order hashes order_hashes = order_hash_manager.compute_order_hashes( @@ -167,57 +170,59 @@ async def main() -> None: print("gas fee: {} INJ".format(gas_fee)) spot_orders = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id_2, fee_recipient=fee_recipient, - price=1.524, - quantity=0.01, - is_buy=True, - is_po=True, + price=Decimal("1.524"), + quantity=Decimal("0.01"), + order_type="BUY_PO", cid=str(uuid.uuid4()), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id_2, fee_recipient=fee_recipient, - price=27.92, - quantity=0.01, - is_buy=False, - is_po=False, + price=Decimal("27.92"), + quantity=Decimal("0.01"), + order_type="SELL_PO", cid=str(uuid.uuid4()), ), ] derivative_orders = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=deriv_market_id, subaccount_id=subaccount_id_2, fee_recipient=fee_recipient, - price=25111, - quantity=0.01, - leverage=1.5, - is_buy=True, - is_po=False, + price=Decimal(25111), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(25111), leverage=Decimal("1.5"), is_reduce_only=False + ), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.DerivativeOrder( + composer.derivative_order( market_id=deriv_market_id, subaccount_id=subaccount_id_2, fee_recipient=fee_recipient, - price=65111, - quantity=0.01, - leverage=2, - is_buy=False, - is_reduce_only=False, + price=Decimal(65111), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(25111), leverage=Decimal(2), is_reduce_only=False + ), + order_type="SELL", cid=str(uuid.uuid4()), ), ] # prepare tx msg - spot_msg = composer.MsgBatchCreateSpotLimitOrders(sender=address.to_acc_bech32(), orders=spot_orders) + spot_msg = composer.msg_batch_create_spot_limit_orders(sender=address.to_acc_bech32(), orders=spot_orders) - deriv_msg = composer.MsgBatchCreateDerivativeLimitOrders(sender=address.to_acc_bech32(), orders=derivative_orders) + deriv_msg = composer.msg_batch_create_derivative_limit_orders( + sender=address.to_acc_bech32(), orders=derivative_orders + ) # compute order hashes order_hashes = order_hash_manager.compute_order_hashes( diff --git a/examples/chain_client/38_StreamEventOrderFail.py b/examples/chain_client/2_StreamEventOrderFail.py similarity index 100% rename from examples/chain_client/38_StreamEventOrderFail.py rename to examples/chain_client/2_StreamEventOrderFail.py diff --git a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py deleted file mode 100644 index 7b8a6567..00000000 --- a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py +++ /dev/null @@ -1,98 +0,0 @@ -import asyncio -import os - -import dotenv -from grpc import RpcError - -from pyinjective.async_client import AsyncClient -from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE -from pyinjective.core.network import Network -from pyinjective.transaction import Transaction -from pyinjective.wallet import PrivateKey - - -async def main() -> None: - dotenv.load_dotenv() - configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") - - # select network: local, testnet, mainnet - network = Network.testnet() - - # initialize grpc client - client = AsyncClient(network) - composer = await client.composer() - await client.sync_timeout_height() - - # load account - priv_key = PrivateKey.from_hex(configured_private_key) - pub_key = priv_key.to_public_key() - address = pub_key.to_address() - await client.fetch_account(address.to_acc_bech32()) - - # prepare tx msg - msg = composer.MsgInstantBinaryOptionsMarketLaunch( - sender=address.to_acc_bech32(), - admin=address.to_acc_bech32(), - ticker="UFC-KHABIB-TKO-05/30/2023", - oracle_symbol="UFC-KHABIB-TKO-05/30/2023", - oracle_provider="UFC", - oracle_type="Provider", - quote_denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7", - quote_decimals=6, - oracle_scale_factor=6, - maker_fee_rate=0.0005, # 0.05% - taker_fee_rate=0.0010, # 0.10% - expiration_timestamp=1680730982, - settlement_timestamp=1690730982, - min_price_tick_size=0.01, - min_quantity_tick_size=0.01, - ) - - # build sim tx - tx = ( - Transaction() - .with_messages(msg) - .with_sequence(client.get_sequence()) - .with_account_num(client.get_number()) - .with_chain_id(network.chain_id) - ) - sim_sign_doc = tx.get_sign_doc(pub_key) - sim_sig = priv_key.sign(sim_sign_doc.SerializeToString()) - sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key) - - # simulate tx - try: - sim_res = await client.simulate(sim_tx_raw_bytes) - except RpcError as ex: - print(ex) - return - - sim_res_msg = sim_res["result"]["msgResponses"] - print("---Simulation Response---") - print(sim_res_msg) - - # build tx - gas_price = GAS_PRICE - gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation - gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0") - fee = [ - composer.coin( - amount=gas_price * gas_limit, - denom=network.fee_denom, - ) - ] - tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height) - sign_doc = tx.get_sign_doc(pub_key) - sig = priv_key.sign(sign_doc.SerializeToString()) - tx_raw_bytes = tx.get_tx_data(sig, pub_key) - - # broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode - res = await client.broadcast_tx_sync_mode(tx_raw_bytes) - print("---Transaction Response---") - print(res) - print("gas wanted: {}".format(gas_limit)) - print("gas fee: {} INJ".format(gas_fee)) - - -if __name__ == "__main__": - asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/44_MessageBroadcaster.py b/examples/chain_client/3_MessageBroadcaster.py similarity index 84% rename from examples/chain_client/44_MessageBroadcaster.py rename to examples/chain_client/3_MessageBroadcaster.py index 114a8700..6bd67033 100644 --- a/examples/chain_client/44_MessageBroadcaster.py +++ b/examples/chain_client/3_MessageBroadcaster.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -34,24 +35,22 @@ async def main() -> None: spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" spot_orders_to_create = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=3, - quantity=55, - is_buy=True, - is_po=False, - cid=str(uuid.uuid4()), + price=Decimal("3"), + quantity=Decimal("55"), + order_type="BUY", + cid=(str(uuid.uuid4())), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=300, - quantity=55, - is_buy=False, - is_po=False, + price=Decimal("300"), + quantity=Decimal("55"), + order_type="SELL", cid=str(uuid.uuid4()), ), ] diff --git a/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py b/examples/chain_client/4_MessageBroadcasterWithGranteeAccount.py similarity index 91% rename from examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py rename to examples/chain_client/4_MessageBroadcasterWithGranteeAccount.py index 8c0166e2..4e08397b 100644 --- a/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py +++ b/examples/chain_client/4_MessageBroadcasterWithGranteeAccount.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -40,15 +41,14 @@ async def main() -> None: 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, + msg = composer.msg_create_spot_limit_order( market_id=market_id, + sender=granter_inj_address, subaccount_id=granter_subaccount_id, fee_recipient=address.to_acc_bech32(), - price=7.523, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py b/examples/chain_client/5_MessageBroadcasterWithoutSimulation.py similarity index 86% rename from examples/chain_client/46_MessageBroadcasterWithoutSimulation.py rename to examples/chain_client/5_MessageBroadcasterWithoutSimulation.py index e6e87c5a..54a79bf8 100644 --- a/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py +++ b/examples/chain_client/5_MessageBroadcasterWithoutSimulation.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -34,24 +35,22 @@ async def main() -> None: spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" spot_orders_to_create = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=3, - quantity=55, - is_buy=True, - is_po=False, + price=Decimal("3"), + quantity=Decimal("55"), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=300, - quantity=55, - is_buy=False, - is_po=False, + price=Decimal("300"), + quantity=Decimal("55"), + order_type="SELL", cid=str(uuid.uuid4()), ), ] diff --git a/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py b/examples/chain_client/6_MessageBroadcasterWithGranteeAccountWithoutSimulation.py similarity index 91% rename from examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py rename to examples/chain_client/6_MessageBroadcasterWithGranteeAccountWithoutSimulation.py index b95114b7..4b7fbd2e 100644 --- a/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py +++ b/examples/chain_client/6_MessageBroadcasterWithGranteeAccountWithoutSimulation.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -39,15 +40,14 @@ async def main() -> None: 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, + msg = composer.msg_create_spot_limit_order( market_id=market_id, + sender=granter_inj_address, subaccount_id=granter_subaccount_id, fee_recipient=address.to_acc_bech32(), - price=7.523, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/49_ChainStream.py b/examples/chain_client/7_ChainStream.py similarity index 100% rename from examples/chain_client/49_ChainStream.py rename to examples/chain_client/7_ChainStream.py diff --git a/examples/chain_client/18_MsgBid.py b/examples/chain_client/auction/1_MsgBid.py similarity index 100% rename from examples/chain_client/18_MsgBid.py rename to examples/chain_client/auction/1_MsgBid.py diff --git a/examples/chain_client/39_Account.py b/examples/chain_client/auth/query/1_Account.py similarity index 100% rename from examples/chain_client/39_Account.py rename to examples/chain_client/auth/query/1_Account.py diff --git a/examples/chain_client/19_MsgGrant.py b/examples/chain_client/authz/1_MsgGrant.py similarity index 100% rename from examples/chain_client/19_MsgGrant.py rename to examples/chain_client/authz/1_MsgGrant.py diff --git a/examples/chain_client/20_MsgExec.py b/examples/chain_client/authz/2_MsgExec.py similarity index 95% rename from examples/chain_client/20_MsgExec.py rename to examples/chain_client/authz/2_MsgExec.py index 1203ff90..8d9891a5 100644 --- a/examples/chain_client/20_MsgExec.py +++ b/examples/chain_client/authz/2_MsgExec.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -37,15 +38,14 @@ async def main() -> None: granter_address = Address.from_acc_bech32(granter_inj_address) granter_subaccount_id = granter_address.get_subaccount_id(index=0) - msg0 = composer.MsgCreateSpotLimitOrder( + msg0 = composer.msg_create_spot_limit_order( sender=granter_inj_address, market_id=market_id, subaccount_id=granter_subaccount_id, fee_recipient=grantee, - price=7.523, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/21_MsgRevoke.py b/examples/chain_client/authz/3_MsgRevoke.py similarity index 100% rename from examples/chain_client/21_MsgRevoke.py rename to examples/chain_client/authz/3_MsgRevoke.py diff --git a/examples/chain_client/76_MsgExecuteContractCompat.py b/examples/chain_client/authz/4_MsgExecuteContractCompat.py similarity index 100% rename from examples/chain_client/76_MsgExecuteContractCompat.py rename to examples/chain_client/authz/4_MsgExecuteContractCompat.py diff --git a/examples/chain_client/27_Grants.py b/examples/chain_client/authz/query/1_Grants.py similarity index 100% rename from examples/chain_client/27_Grants.py rename to examples/chain_client/authz/query/1_Grants.py diff --git a/examples/chain_client/1_MsgSend.py b/examples/chain_client/bank/1_MsgSend.py similarity index 100% rename from examples/chain_client/1_MsgSend.py rename to examples/chain_client/bank/1_MsgSend.py diff --git a/examples/chain_client/57_SendEnabled.py b/examples/chain_client/bank/query/10_SendEnabled.py similarity index 100% rename from examples/chain_client/57_SendEnabled.py rename to examples/chain_client/bank/query/10_SendEnabled.py diff --git a/examples/chain_client/29_BankBalance.py b/examples/chain_client/bank/query/1_BankBalance.py similarity index 100% rename from examples/chain_client/29_BankBalance.py rename to examples/chain_client/bank/query/1_BankBalance.py diff --git a/examples/chain_client/28_BankBalances.py b/examples/chain_client/bank/query/2_BankBalances.py similarity index 100% rename from examples/chain_client/28_BankBalances.py rename to examples/chain_client/bank/query/2_BankBalances.py diff --git a/examples/chain_client/50_SpendableBalances.py b/examples/chain_client/bank/query/3_SpendableBalances.py similarity index 100% rename from examples/chain_client/50_SpendableBalances.py rename to examples/chain_client/bank/query/3_SpendableBalances.py diff --git a/examples/chain_client/51_SpendableBalancesByDenom.py b/examples/chain_client/bank/query/4_SpendableBalancesByDenom.py similarity index 100% rename from examples/chain_client/51_SpendableBalancesByDenom.py rename to examples/chain_client/bank/query/4_SpendableBalancesByDenom.py diff --git a/examples/chain_client/52_TotalSupply.py b/examples/chain_client/bank/query/5_TotalSupply.py similarity index 100% rename from examples/chain_client/52_TotalSupply.py rename to examples/chain_client/bank/query/5_TotalSupply.py diff --git a/examples/chain_client/53_SupplyOf.py b/examples/chain_client/bank/query/6_SupplyOf.py similarity index 100% rename from examples/chain_client/53_SupplyOf.py rename to examples/chain_client/bank/query/6_SupplyOf.py diff --git a/examples/chain_client/54_DenomMetadata.py b/examples/chain_client/bank/query/7_DenomMetadata.py similarity index 100% rename from examples/chain_client/54_DenomMetadata.py rename to examples/chain_client/bank/query/7_DenomMetadata.py diff --git a/examples/chain_client/55_DenomsMetadata.py b/examples/chain_client/bank/query/8_DenomsMetadata.py similarity index 100% rename from examples/chain_client/55_DenomsMetadata.py rename to examples/chain_client/bank/query/8_DenomsMetadata.py diff --git a/examples/chain_client/56_DenomOwners.py b/examples/chain_client/bank/query/9_DenomOwners.py similarity index 100% rename from examples/chain_client/56_DenomOwners.py rename to examples/chain_client/bank/query/9_DenomOwners.py diff --git a/examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/exchange/10_MsgCreateDerivativeLimitOrder.py similarity index 90% rename from examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py rename to examples/chain_client/exchange/10_MsgCreateDerivativeLimitOrder.py index 41a19307..4e0ff327 100644 --- a/examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py +++ b/examples/chain_client/exchange/10_MsgCreateDerivativeLimitOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,16 +37,17 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg - msg = composer.MsgCreateDerivativeLimitOrder( + msg = composer.msg_create_derivative_limit_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=50000, - quantity=0.1, - leverage=1, - is_buy=False, - is_reduce_only=False, + price=Decimal(50000), + quantity=Decimal(0.1), + margin=composer.calculate_margin( + quantity=Decimal(0.1), price=Decimal(50000), leverage=Decimal(1), is_reduce_only=False + ), + order_type="SELL", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py b/examples/chain_client/exchange/11_MsgCreateDerivativeMarketOrder.py similarity index 90% rename from examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py rename to examples/chain_client/exchange/11_MsgCreateDerivativeMarketOrder.py index 37b305ed..dfedf6d6 100644 --- a/examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py +++ b/examples/chain_client/exchange/11_MsgCreateDerivativeMarketOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,15 +37,16 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg - msg = composer.MsgCreateDerivativeMarketOrder( + msg = composer.msg_create_derivative_market_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=50000, - quantity=0.01, - leverage=3, - is_buy=True, + price=Decimal(50000), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(50000), leverage=Decimal(3), is_reduce_only=False + ), cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py b/examples/chain_client/exchange/12_MsgCancelDerivativeOrder.py similarity index 98% rename from examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py rename to examples/chain_client/exchange/12_MsgCancelDerivativeOrder.py index 43180b1f..20be2bd0 100644 --- a/examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py +++ b/examples/chain_client/exchange/12_MsgCancelDerivativeOrder.py @@ -35,7 +35,7 @@ async def main() -> None: order_hash = "0x667ee6f37f6d06bf473f4e1434e92ac98ff43c785405e2a511a0843daeca2de9" # prepare tx msg - msg = composer.MsgCancelDerivativeOrder( + msg = composer.msg_cancel_derivative_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, order_hash=order_hash ) diff --git a/examples/chain_client/exchange/13_MsgInstantBinaryOptionsMarketLaunch.py b/examples/chain_client/exchange/13_MsgInstantBinaryOptionsMarketLaunch.py new file mode 100644 index 00000000..a1ebde82 --- /dev/null +++ b/examples/chain_client/exchange/13_MsgInstantBinaryOptionsMarketLaunch.py @@ -0,0 +1,61 @@ +import asyncio +import os + +import dotenv + +from pyinjective.async_client import AsyncClient +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.core.network import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + composer = await client.composer() + await client.sync_timeout_height() + + message_broadcaster = MsgBroadcasterWithPk.new_using_simulation( + network=network, + private_key=configured_private_key, + ) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + # prepare tx msg + message = composer.msg_instant_binary_options_market_launch( + sender=address.to_acc_bech32(), + ticker="UFC-KHABIB-TKO-05/30/2023", + oracle_symbol="UFC-KHABIB-TKO-05/30/2023", + oracle_provider="UFC", + oracle_type="Provider", + quote_decimals=6, + oracle_scale_factor=6, + maker_fee_rate=0.0005, # 0.05% + taker_fee_rate=0.0010, # 0.10% + expiration_timestamp=1680730982, + settlement_timestamp=1690730982, + admin=address.to_acc_bech32(), + quote_denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7", + min_price_tick_size=0.01, + min_quantity_tick_size=0.01, + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([message]) + print("---Transaction Response---") + print(result) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py b/examples/chain_client/exchange/14_MsgCreateBinaryOptionsLimitOrder.py similarity index 93% rename from examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py rename to examples/chain_client/exchange/14_MsgCreateBinaryOptionsLimitOrder.py index 2a58e173..5ad8c59e 100644 --- a/examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py +++ b/examples/chain_client/exchange/14_MsgCreateBinaryOptionsLimitOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -40,17 +41,17 @@ async def main() -> None: denom = Denom(description="desc", base=0, quote=6, min_price_tick_size=1000, min_quantity_tick_size=0.0001) # prepare tx msg - msg = composer.MsgCreateBinaryOptionsLimitOrder( + msg = composer.msg_create_binary_options_limit_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=0.5, - quantity=1, - is_buy=False, - is_reduce_only=False, - denom=denom, + price=Decimal("0.5"), + quantity=Decimal("1"), + margin=Decimal("0.5"), + order_type="BUY", cid=str(uuid.uuid4()), + denom=denom, ) # build sim tx diff --git a/examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py b/examples/chain_client/exchange/15_MsgCreateBinaryOptionsMarketOrder.py similarity index 90% rename from examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py rename to examples/chain_client/exchange/15_MsgCreateBinaryOptionsMarketOrder.py index 2d07658f..9b68bc85 100644 --- a/examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py +++ b/examples/chain_client/exchange/15_MsgCreateBinaryOptionsMarketOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,15 +37,16 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg - msg = composer.MsgCreateBinaryOptionsMarketOrder( + msg = composer.msg_create_binary_options_market_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=0.5, - quantity=1, - is_buy=True, - is_reduce_only=False, + price=Decimal("0.5"), + quantity=Decimal(1), + margin=composer.calculate_margin( + quantity=Decimal(1), price=Decimal("0.5"), leverage=Decimal(1), is_reduce_only=False + ), cid=str(uuid.uuid4()), ) # build sim tx diff --git a/examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py b/examples/chain_client/exchange/16_MsgCancelBinaryOptionsOrder.py similarity index 98% rename from examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py rename to examples/chain_client/exchange/16_MsgCancelBinaryOptionsOrder.py index 82107f3c..582c6dc6 100644 --- a/examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py +++ b/examples/chain_client/exchange/16_MsgCancelBinaryOptionsOrder.py @@ -35,7 +35,7 @@ async def main() -> None: order_hash = "a975fbd72b874bdbf5caf5e1e8e2653937f33ce6dd14d241c06c8b1f7b56be46" # prepare tx msg - msg = composer.MsgCancelBinaryOptionsOrder( + msg = composer.msg_cancel_binary_options_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, order_hash=order_hash ) # build sim tx diff --git a/examples/chain_client/exchange/10_MsgSubaccountTransfer.py b/examples/chain_client/exchange/17_MsgSubaccountTransfer.py similarity index 96% rename from examples/chain_client/exchange/10_MsgSubaccountTransfer.py rename to examples/chain_client/exchange/17_MsgSubaccountTransfer.py index b68717b2..a50fc0cf 100644 --- a/examples/chain_client/exchange/10_MsgSubaccountTransfer.py +++ b/examples/chain_client/exchange/17_MsgSubaccountTransfer.py @@ -1,5 +1,6 @@ import asyncio import os +from decimal import Decimal import dotenv from grpc import RpcError @@ -32,11 +33,11 @@ async def main() -> None: dest_subaccount_id = address.get_subaccount_id(index=1) # prepare tx msg - msg = composer.MsgSubaccountTransfer( + msg = composer.msg_subaccount_transfer( sender=address.to_acc_bech32(), source_subaccount_id=subaccount_id, destination_subaccount_id=dest_subaccount_id, - amount=100, + amount=Decimal(100), denom="INJ", ) diff --git a/examples/chain_client/exchange/15_ExternalTransfer.py b/examples/chain_client/exchange/18_MsgExternalTransfer.py similarity index 96% rename from examples/chain_client/exchange/15_ExternalTransfer.py rename to examples/chain_client/exchange/18_MsgExternalTransfer.py index 3200be34..2bcc86a1 100644 --- a/examples/chain_client/exchange/15_ExternalTransfer.py +++ b/examples/chain_client/exchange/18_MsgExternalTransfer.py @@ -1,5 +1,6 @@ import asyncio import os +from decimal import Decimal import dotenv from grpc import RpcError @@ -32,11 +33,11 @@ async def main() -> None: dest_subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000" # prepare tx msg - msg = composer.MsgExternalTransfer( + msg = composer.msg_external_transfer( sender=address.to_acc_bech32(), source_subaccount_id=subaccount_id, destination_subaccount_id=dest_subaccount_id, - amount=100, + amount=Decimal(100), denom="INJ", ) diff --git a/examples/chain_client/exchange/19_MsgLiquidatePosition.py b/examples/chain_client/exchange/19_MsgLiquidatePosition.py index d80ba385..9788b865 100644 --- a/examples/chain_client/exchange/19_MsgLiquidatePosition.py +++ b/examples/chain_client/exchange/19_MsgLiquidatePosition.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,19 +37,21 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" cid = str(uuid.uuid4()) - order = composer.DerivativeOrder( + order = composer.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=39.01, # This should be the liquidation price - quantity=0.147, - leverage=1, + price=Decimal(39.01), # This should be the liquidation price + quantity=Decimal(0.147), + margin=composer.calculate_margin( + quantity=Decimal(0.147), price=Decimal(39.01), leverage=Decimal(1), is_reduce_only=False + ), + order_type="SELL", cid=cid, - is_buy=False, ) # prepare tx msg - msg = composer.MsgLiquidatePosition( + msg = composer.msg_liquidate_position( sender=address.to_acc_bech32(), subaccount_id="0x156df4d5bc8e7dd9191433e54bd6a11eeb390921000000000000000000000000", market_id=market_id, diff --git a/examples/chain_client/exchange/1_MsgDeposit.py b/examples/chain_client/exchange/1_MsgDeposit.py index 80b9f652..bbf64710 100644 --- a/examples/chain_client/exchange/1_MsgDeposit.py +++ b/examples/chain_client/exchange/1_MsgDeposit.py @@ -31,7 +31,9 @@ async def main() -> None: subaccount_id = address.get_subaccount_id(index=0) # prepare tx msg - msg = composer.MsgDeposit(sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=0.000001, denom="INJ") + msg = composer.msg_deposit( + sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=0.000001, denom="INJ" + ) # build sim tx tx = ( diff --git a/examples/chain_client/13_MsgIncreasePositionMargin.py b/examples/chain_client/exchange/20_MsgIncreasePositionMargin.py similarity index 96% rename from examples/chain_client/13_MsgIncreasePositionMargin.py rename to examples/chain_client/exchange/20_MsgIncreasePositionMargin.py index 775a41e5..276276e7 100644 --- a/examples/chain_client/13_MsgIncreasePositionMargin.py +++ b/examples/chain_client/exchange/20_MsgIncreasePositionMargin.py @@ -1,5 +1,6 @@ import asyncio import os +from decimal import Decimal import dotenv from grpc import RpcError @@ -34,12 +35,12 @@ async def main() -> None: market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" # prepare tx msg - msg = composer.MsgIncreasePositionMargin( + msg = composer.msg_increase_position_margin( sender=address.to_acc_bech32(), market_id=market_id, source_subaccount_id=subaccount_id, destination_subaccount_id=subaccount_id, - amount=2, + amount=Decimal(2), ) # build sim tx diff --git a/examples/chain_client/exchange/12_MsgRewardsOptOut.py b/examples/chain_client/exchange/21_MsgRewardsOptOut.py similarity index 97% rename from examples/chain_client/exchange/12_MsgRewardsOptOut.py rename to examples/chain_client/exchange/21_MsgRewardsOptOut.py index 8beaa1f4..2306b541 100644 --- a/examples/chain_client/exchange/12_MsgRewardsOptOut.py +++ b/examples/chain_client/exchange/21_MsgRewardsOptOut.py @@ -30,7 +30,7 @@ async def main() -> None: await client.fetch_account(address.to_acc_bech32()) # prepare tx msg - msg = composer.MsgRewardsOptOut(sender=address.to_acc_bech32()) + msg = composer.msg_rewards_opt_out(sender=address.to_acc_bech32()) # build sim tx tx = ( diff --git a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py b/examples/chain_client/exchange/22_MsgAdminUpdateBinaryOptionsMarket.py similarity index 96% rename from examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py rename to examples/chain_client/exchange/22_MsgAdminUpdateBinaryOptionsMarket.py index 0f39dcdb..b638b28a 100644 --- a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py +++ b/examples/chain_client/exchange/22_MsgAdminUpdateBinaryOptionsMarket.py @@ -1,5 +1,6 @@ import asyncio import os +from decimal import Decimal import dotenv from grpc import RpcError @@ -32,12 +33,12 @@ async def main() -> None: # prepare trade info market_id = "0xfafec40a7b93331c1fc89c23f66d11fbb48f38dfdd78f7f4fc4031fad90f6896" status = "Demolished" - settlement_price = 1 + settlement_price = Decimal(1) expiration_timestamp = 1685460582 settlement_timestamp = 1690730982 # prepare tx msg - msg = composer.MsgAdminUpdateBinaryOptionsMarket( + msg = composer.msg_admin_update_binary_options_market( sender=address.to_acc_bech32(), market_id=market_id, settlement_price=settlement_price, diff --git a/examples/chain_client/exchange/9_MsgWithdraw.py b/examples/chain_client/exchange/2_MsgWithdraw.py similarity index 95% rename from examples/chain_client/exchange/9_MsgWithdraw.py rename to examples/chain_client/exchange/2_MsgWithdraw.py index b198c0aa..1070d28c 100644 --- a/examples/chain_client/exchange/9_MsgWithdraw.py +++ b/examples/chain_client/exchange/2_MsgWithdraw.py @@ -31,7 +31,7 @@ async def main() -> None: subaccount_id = address.get_subaccount_id(index=0) # prepare tx msg - msg = composer.MsgWithdraw(sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=1, denom="USDT") + msg = composer.msg_withdraw(sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=1, denom="USDT") # build sim tx tx = ( diff --git a/examples/chain_client/exchange/3_MsgInstantSpotMarketLaunch.py b/examples/chain_client/exchange/3_MsgInstantSpotMarketLaunch.py new file mode 100644 index 00000000..90a177ec --- /dev/null +++ b/examples/chain_client/exchange/3_MsgInstantSpotMarketLaunch.py @@ -0,0 +1,54 @@ +import asyncio +import os +from decimal import Decimal + +import dotenv + +from pyinjective.async_client import AsyncClient +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.core.network import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + await client.initialize_tokens_from_chain_denoms() + composer = await client.composer() + await client.sync_timeout_height() + + message_broadcaster = MsgBroadcasterWithPk.new_using_simulation( + network=network, + private_key=configured_private_key, + ) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + # prepare tx msg + message = composer.msg_instant_spot_market_launch( + sender=address.to_acc_bech32(), + ticker="INJ/USDC", + base_denom="INJ", + quote_denom="USDC", + min_price_tick_size=Decimal("0.001"), + min_quantity_tick_size=Decimal("0.01"), + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([message]) + print("---Transaction Response---") + print(result) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/4_MsgInstantPerpetualMarketLaunch.py b/examples/chain_client/exchange/4_MsgInstantPerpetualMarketLaunch.py new file mode 100644 index 00000000..b2b5dff4 --- /dev/null +++ b/examples/chain_client/exchange/4_MsgInstantPerpetualMarketLaunch.py @@ -0,0 +1,61 @@ +import asyncio +import os +from decimal import Decimal + +import dotenv + +from pyinjective.async_client import AsyncClient +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.core.network import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + await client.initialize_tokens_from_chain_denoms() + composer = await client.composer() + await client.sync_timeout_height() + + message_broadcaster = MsgBroadcasterWithPk.new_using_simulation( + network=network, + private_key=configured_private_key, + ) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + # prepare tx msg + message = composer.msg_instant_perpetual_market_launch( + sender=address.to_acc_bech32(), + ticker="INJ/USDC PERP", + quote_denom="USDC", + oracle_base="INJ", + oracle_quote="USDC", + oracle_scale_factor=6, + oracle_type="Band", + maker_fee_rate=Decimal("-0.0001"), + taker_fee_rate=Decimal("0.001"), + initial_margin_ratio=Decimal("0.33"), + maintenance_margin_ratio=Decimal("0.095"), + min_price_tick_size=Decimal("0.001"), + min_quantity_tick_size=Decimal("0.01"), + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([message]) + print("---Transaction Response---") + print(result) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/5_MsgInstantExpiryFuturesMarketLaunch.py b/examples/chain_client/exchange/5_MsgInstantExpiryFuturesMarketLaunch.py new file mode 100644 index 00000000..d451fd15 --- /dev/null +++ b/examples/chain_client/exchange/5_MsgInstantExpiryFuturesMarketLaunch.py @@ -0,0 +1,62 @@ +import asyncio +import os +from decimal import Decimal + +import dotenv + +from pyinjective.async_client import AsyncClient +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.core.network import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + await client.initialize_tokens_from_chain_denoms() + composer = await client.composer() + await client.sync_timeout_height() + + message_broadcaster = MsgBroadcasterWithPk.new_using_simulation( + network=network, + private_key=configured_private_key, + ) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + # prepare tx msg + message = composer.msg_instant_expiry_futures_market_launch( + sender=address.to_acc_bech32(), + ticker="INJ/USDC FUT", + quote_denom="USDC", + oracle_base="INJ", + oracle_quote="USDC", + oracle_scale_factor=6, + oracle_type="Band", + expiry=2000000000, + maker_fee_rate=Decimal("-0.0001"), + taker_fee_rate=Decimal("0.001"), + initial_margin_ratio=Decimal("0.33"), + maintenance_margin_ratio=Decimal("0.095"), + min_price_tick_size=Decimal("0.001"), + min_quantity_tick_size=Decimal("0.01"), + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([message]) + print("---Transaction Response---") + print(result) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py b/examples/chain_client/exchange/6_MsgCreateSpotLimitOrder.py similarity index 94% rename from examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py rename to examples/chain_client/exchange/6_MsgCreateSpotLimitOrder.py index d3ca5f16..5b3b966a 100644 --- a/examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py +++ b/examples/chain_client/exchange/6_MsgCreateSpotLimitOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -37,15 +38,14 @@ async def main() -> None: cid = str(uuid.uuid4()) # prepare tx msg - msg = composer.MsgCreateSpotLimitOrder( + msg = composer.msg_create_spot_limit_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=7.523, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", cid=cid, ) diff --git a/examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py b/examples/chain_client/exchange/7_MsgCreateSpotMarketOrder.py similarity index 94% rename from examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py rename to examples/chain_client/exchange/7_MsgCreateSpotMarketOrder.py index 5229632f..36ea27de 100644 --- a/examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py +++ b/examples/chain_client/exchange/7_MsgCreateSpotMarketOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,14 +37,14 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg - msg = composer.MsgCreateSpotMarketOrder( - sender=address.to_acc_bech32(), + msg = composer.msg_create_spot_market_order( market_id=market_id, + sender=address.to_acc_bech32(), subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=10.522, - quantity=0.01, - is_buy=True, + price=Decimal("10.522"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/exchange/5_MsgCancelSpotOrder.py b/examples/chain_client/exchange/8_MsgCancelSpotOrder.py similarity index 100% rename from examples/chain_client/exchange/5_MsgCancelSpotOrder.py rename to examples/chain_client/exchange/8_MsgCancelSpotOrder.py diff --git a/examples/chain_client/exchange/11_MsgBatchUpdateOrders.py b/examples/chain_client/exchange/9_MsgBatchUpdateOrders.py similarity index 83% rename from examples/chain_client/exchange/11_MsgBatchUpdateOrders.py rename to examples/chain_client/exchange/9_MsgBatchUpdateOrders.py index 9efdc0a0..04e41058 100644 --- a/examples/chain_client/exchange/11_MsgBatchUpdateOrders.py +++ b/examples/chain_client/exchange/9_MsgBatchUpdateOrders.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -43,12 +44,12 @@ async def main() -> None: spot_market_id_cancel_2 = "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0" derivative_orders_to_cancel = [ - composer.OrderData( + composer.order_data( market_id=derivative_market_id_cancel, subaccount_id=subaccount_id, order_hash="0x48690013c382d5dbaff9989db04629a16a5818d7524e027d517ccc89fd068103", ), - composer.OrderData( + composer.order_data( market_id=derivative_market_id_cancel_2, subaccount_id=subaccount_id, order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", @@ -56,12 +57,12 @@ async def main() -> None: ] spot_orders_to_cancel = [ - composer.OrderData( + composer.order_data( market_id=spot_market_id_cancel, subaccount_id=subaccount_id, cid="0e5c3ad5-2cc4-4a2a-bbe5-b12697739163", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id_cancel_2, subaccount_id=subaccount_id, order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", @@ -69,49 +70,49 @@ async def main() -> None: ] derivative_orders_to_create = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=derivative_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=25000, - quantity=0.1, - leverage=1, - is_buy=True, - is_po=False, + price=Decimal(25000), + quantity=Decimal(0.1), + margin=composer.calculate_margin( + quantity=Decimal(0.1), price=Decimal(25000), leverage=Decimal(1), is_reduce_only=False + ), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.DerivativeOrder( + composer.derivative_order( market_id=derivative_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=50000, - quantity=0.01, - leverage=1, - is_buy=False, - is_po=False, + price=Decimal(50000), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(50000), leverage=Decimal(1), is_reduce_only=False + ), + order_type="SELL", cid=str(uuid.uuid4()), ), ] spot_orders_to_create = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=3, - quantity=55, - is_buy=True, - is_po=False, + price=Decimal("3"), + quantity=Decimal("55"), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=300, - quantity=55, - is_buy=False, - is_po=False, + price=Decimal("300"), + quantity=Decimal("55"), + order_type="SELL", cid=str(uuid.uuid4()), ), ] diff --git a/examples/chain_client/41_MsgCreateInsuranceFund.py b/examples/chain_client/insurance/1_MsgCreateInsuranceFund.py similarity index 100% rename from examples/chain_client/41_MsgCreateInsuranceFund.py rename to examples/chain_client/insurance/1_MsgCreateInsuranceFund.py diff --git a/examples/chain_client/42_MsgUnderwrite.py b/examples/chain_client/insurance/2_MsgUnderwrite.py similarity index 100% rename from examples/chain_client/42_MsgUnderwrite.py rename to examples/chain_client/insurance/2_MsgUnderwrite.py diff --git a/examples/chain_client/43_MsgRequestRedemption.py b/examples/chain_client/insurance/3_MsgRequestRedemption.py similarity index 100% rename from examples/chain_client/43_MsgRequestRedemption.py rename to examples/chain_client/insurance/3_MsgRequestRedemption.py diff --git a/examples/chain_client/23_MsgRelayPriceFeedPrice.py b/examples/chain_client/oracle/1_MsgRelayPriceFeedPrice.py similarity index 100% rename from examples/chain_client/23_MsgRelayPriceFeedPrice.py rename to examples/chain_client/oracle/1_MsgRelayPriceFeedPrice.py diff --git a/examples/chain_client/36_MsgRelayProviderPrices.py b/examples/chain_client/oracle/2_MsgRelayProviderPrices.py similarity index 100% rename from examples/chain_client/36_MsgRelayProviderPrices.py rename to examples/chain_client/oracle/2_MsgRelayProviderPrices.py diff --git a/examples/chain_client/22_MsgSendToEth.py b/examples/chain_client/peggy/1_MsgSendToEth.py similarity index 100% rename from examples/chain_client/22_MsgSendToEth.py rename to examples/chain_client/peggy/1_MsgSendToEth.py diff --git a/examples/chain_client/25_MsgDelegate.py b/examples/chain_client/staking/1_MsgDelegate.py similarity index 100% rename from examples/chain_client/25_MsgDelegate.py rename to examples/chain_client/staking/1_MsgDelegate.py diff --git a/examples/chain_client/71_CreateDenom.py b/examples/chain_client/tokenfactory/1_CreateDenom.py similarity index 100% rename from examples/chain_client/71_CreateDenom.py rename to examples/chain_client/tokenfactory/1_CreateDenom.py diff --git a/examples/chain_client/72_MsgMint.py b/examples/chain_client/tokenfactory/2_MsgMint.py similarity index 100% rename from examples/chain_client/72_MsgMint.py rename to examples/chain_client/tokenfactory/2_MsgMint.py diff --git a/examples/chain_client/73_MsgBurn.py b/examples/chain_client/tokenfactory/3_MsgBurn.py similarity index 100% rename from examples/chain_client/73_MsgBurn.py rename to examples/chain_client/tokenfactory/3_MsgBurn.py diff --git a/examples/chain_client/75_MsgChangeAdmin.py b/examples/chain_client/tokenfactory/4_MsgChangeAdmin.py similarity index 100% rename from examples/chain_client/75_MsgChangeAdmin.py rename to examples/chain_client/tokenfactory/4_MsgChangeAdmin.py diff --git a/examples/chain_client/74_MsgSetDenomMetadata.py b/examples/chain_client/tokenfactory/5_MsgSetDenomMetadata.py similarity index 100% rename from examples/chain_client/74_MsgSetDenomMetadata.py rename to examples/chain_client/tokenfactory/5_MsgSetDenomMetadata.py diff --git a/examples/chain_client/68_DenomAuthorityMetadata.py b/examples/chain_client/tokenfactory/query/1_DenomAuthorityMetadata.py similarity index 100% rename from examples/chain_client/68_DenomAuthorityMetadata.py rename to examples/chain_client/tokenfactory/query/1_DenomAuthorityMetadata.py diff --git a/examples/chain_client/69_DenomsFromCreator.py b/examples/chain_client/tokenfactory/query/2_DenomsFromCreator.py similarity index 100% rename from examples/chain_client/69_DenomsFromCreator.py rename to examples/chain_client/tokenfactory/query/2_DenomsFromCreator.py diff --git a/examples/chain_client/70_TokenfactoryModuleState.py b/examples/chain_client/tokenfactory/query/3_TokenfactoryModuleState.py similarity index 100% rename from examples/chain_client/70_TokenfactoryModuleState.py rename to examples/chain_client/tokenfactory/query/3_TokenfactoryModuleState.py diff --git a/examples/chain_client/37_GetTx.py b/examples/chain_client/tx/query/1_GetTx.py similarity index 100% rename from examples/chain_client/37_GetTx.py rename to examples/chain_client/tx/query/1_GetTx.py diff --git a/examples/chain_client/40_MsgExecuteContract.py b/examples/chain_client/wasm/1_MsgExecuteContract.py similarity index 100% rename from examples/chain_client/40_MsgExecuteContract.py rename to examples/chain_client/wasm/1_MsgExecuteContract.py diff --git a/examples/chain_client/67_ContractsByCreator.py b/examples/chain_client/wasm/query/10_ContractsByCreator.py similarity index 100% rename from examples/chain_client/67_ContractsByCreator.py rename to examples/chain_client/wasm/query/10_ContractsByCreator.py diff --git a/examples/chain_client/58_ContractInfo.py b/examples/chain_client/wasm/query/1_ContractInfo.py similarity index 100% rename from examples/chain_client/58_ContractInfo.py rename to examples/chain_client/wasm/query/1_ContractInfo.py diff --git a/examples/chain_client/59_ContractHistory.py b/examples/chain_client/wasm/query/2_ContractHistory.py similarity index 100% rename from examples/chain_client/59_ContractHistory.py rename to examples/chain_client/wasm/query/2_ContractHistory.py diff --git a/examples/chain_client/60_ContractsByCode.py b/examples/chain_client/wasm/query/3_ContractsByCode.py similarity index 100% rename from examples/chain_client/60_ContractsByCode.py rename to examples/chain_client/wasm/query/3_ContractsByCode.py diff --git a/examples/chain_client/61_AllContractsState.py b/examples/chain_client/wasm/query/4_AllContractsState.py similarity index 100% rename from examples/chain_client/61_AllContractsState.py rename to examples/chain_client/wasm/query/4_AllContractsState.py diff --git a/examples/chain_client/62_RawContractState.py b/examples/chain_client/wasm/query/5_RawContractState.py similarity index 100% rename from examples/chain_client/62_RawContractState.py rename to examples/chain_client/wasm/query/5_RawContractState.py diff --git a/examples/chain_client/63_SmartContractState.py b/examples/chain_client/wasm/query/6_SmartContractState.py similarity index 100% rename from examples/chain_client/63_SmartContractState.py rename to examples/chain_client/wasm/query/6_SmartContractState.py diff --git a/examples/chain_client/64_SmartContractCode.py b/examples/chain_client/wasm/query/7_SmartContractCode.py similarity index 100% rename from examples/chain_client/64_SmartContractCode.py rename to examples/chain_client/wasm/query/7_SmartContractCode.py diff --git a/examples/chain_client/65_SmartContractCodes.py b/examples/chain_client/wasm/query/8_SmartContractCodes.py similarity index 100% rename from examples/chain_client/65_SmartContractCodes.py rename to examples/chain_client/wasm/query/8_SmartContractCodes.py diff --git a/examples/chain_client/66_SmartContractPinnedCodes.py b/examples/chain_client/wasm/query/9_SmartContractPinnedCodes.py similarity index 100% rename from examples/chain_client/66_SmartContractPinnedCodes.py rename to examples/chain_client/wasm/query/9_SmartContractPinnedCodes.py diff --git a/pyinjective/composer.py b/pyinjective/composer.py index df353d6b..9a0807c9 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -13,7 +13,7 @@ from pyinjective.core.token import Token from pyinjective.proto.cosmos.authz.v1beta1 import authz_pb2 as cosmos_authz_pb, tx_pb2 as cosmos_authz_tx_pb from pyinjective.proto.cosmos.bank.v1beta1 import bank_pb2 as bank_pb, tx_pb2 as cosmos_bank_tx_pb -from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as cosmos_dot_base_dot_v1beta1_dot_coin__pb2 +from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as base_coin_pb from pyinjective.proto.cosmos.distribution.v1beta1 import ( distribution_pb2 as cosmos_distribution_pb2, tx_pb2 as cosmos_distribution_tx_pb, @@ -25,15 +25,19 @@ from pyinjective.proto.injective.auction.v1beta1 import tx_pb2 as injective_auction_tx_pb from pyinjective.proto.injective.exchange.v1beta1 import ( authz_pb2 as injective_authz_pb, - exchange_pb2 as injective_dot_exchange_dot_v1beta1_dot_exchange__pb2, + exchange_pb2 as injective_exchange_pb, tx_pb2 as injective_exchange_tx_pb, ) from pyinjective.proto.injective.insurance.v1beta1 import tx_pb2 as injective_insurance_tx_pb -from pyinjective.proto.injective.oracle.v1beta1 import tx_pb2 as injective_oracle_tx_pb +from pyinjective.proto.injective.oracle.v1beta1 import ( + oracle_pb2 as injective_oracle_pb, + tx_pb2 as injective_oracle_tx_pb, +) from pyinjective.proto.injective.peggy.v1 import msgs_pb2 as injective_peggy_tx_pb from pyinjective.proto.injective.stream.v1beta1 import query_pb2 as chain_stream_query from pyinjective.proto.injective.tokenfactory.v1beta1 import tx_pb2 as token_factory_tx_pb from pyinjective.proto.injective.wasmx.v1 import tx_pb2 as wasmx_tx_pb +from pyinjective.utils.denom import Denom REQUEST_TO_RESPONSE_TYPE_MAP = { "MsgCreateSpotLimitOrder": injective_exchange_tx_pb.MsgCreateSpotLimitOrderResponse, @@ -137,14 +141,14 @@ def Coin(self, amount: int, denom: str): This method is deprecated and will be removed soon. Please use `coin` instead """ warn("This method is deprecated. Use coin instead", DeprecationWarning, stacklevel=2) - return cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin(amount=str(amount), denom=denom) + return base_coin_pb.Coin(amount=str(amount), denom=denom) def coin(self, amount: int, denom: str): """ This method create an instance of Coin gRPC type, considering the amount is already expressed in chain format """ formatted_amount_string = str(int(amount)) - return cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin(amount=formatted_amount_string, denom=denom) + return base_coin_pb.Coin(amount=formatted_amount_string, denom=denom) def create_coin_amount(self, amount: Decimal, token_name: str): """ @@ -154,35 +158,38 @@ def create_coin_amount(self, amount: Decimal, token_name: str): chain_amount = token.chain_formatted_value(human_readable_value=amount) return self.coin(amount=int(chain_amount), denom=token.denom) - def get_order_mask(self, **kwargs): - order_mask = 0 - - if kwargs.get("is_conditional"): - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.CONDITIONAL - else: - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.REGULAR - - if kwargs.get("order_direction") == "buy": - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.DIRECTION_BUY_OR_HIGHER - - elif kwargs.get("order_direction") == "sell": - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.DIRECTION_SELL_OR_LOWER - - if kwargs.get("order_type") == "market": - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.TYPE_MARKET - - elif kwargs.get("order_type") == "limit": - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.TYPE_LIMIT - - if order_mask == 0: - order_mask = 1 - - return order_mask - def OrderData( self, market_id: str, subaccount_id: str, order_hash: Optional[str] = None, cid: Optional[str] = None, **kwargs ): - order_mask = self.get_order_mask(**kwargs) + """ + This method is deprecated and will be removed soon. Please use `order_data` instead + """ + warn("This method is deprecated. Use order_data instead", DeprecationWarning, stacklevel=2) + + is_conditional = kwargs.get("is_conditional", False) + is_buy = kwargs.get("order_direction", "buy") == "buy" + is_market_order = kwargs.get("order_type", "limit") == "market" + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) + + return injective_exchange_tx_pb.OrderData( + market_id=market_id, + subaccount_id=subaccount_id, + order_hash=order_hash, + order_mask=order_mask, + cid=cid, + ) + + def order_data( + self, + market_id: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + is_conditional: Optional[bool] = False, + is_buy: Optional[bool] = False, + is_market_order: Optional[bool] = False, + ) -> injective_exchange_tx_pb.OrderData: + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) return injective_exchange_tx_pb.OrderData( market_id=market_id, @@ -202,6 +209,11 @@ def SpotOrder( cid: Optional[str] = None, **kwargs, ): + """ + This method is deprecated and will be removed soon. Please use `spot_order` instead + """ + warn("This method is deprecated. Use spot_order instead", DeprecationWarning, stacklevel=2) + market = self.spot_markets[market_id] # prepare values @@ -210,20 +222,20 @@ def SpotOrder( trigger_price = market.price_to_chain_format(human_readable_value=Decimal(0)) if kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY + order_type = injective_exchange_pb.OrderType.BUY elif not kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL + order_type = injective_exchange_pb.OrderType.SELL elif kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY_PO + order_type = injective_exchange_pb.OrderType.BUY_PO elif not kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL_PO + order_type = injective_exchange_pb.OrderType.SELL_PO - return injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.SpotOrder( + return injective_exchange_pb.SpotOrder( market_id=market_id, - order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( + order_info=injective_exchange_pb.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=str(int(price)), @@ -234,6 +246,50 @@ def SpotOrder( trigger_price=str(int(trigger_price)), ) + def spot_order( + self, + market_id: str, + subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_pb.SpotOrder: + market = self.spot_markets[market_id] + + chain_quantity = f"{market.quantity_to_chain_format(human_readable_value=quantity).normalize():f}" + chain_price = f"{market.price_to_chain_format(human_readable_value=price).normalize():f}" + + trigger_price = trigger_price or Decimal(0) + chain_trigger_price = f"{market.price_to_chain_format(human_readable_value=trigger_price).normalize():f}" + + chain_order_type = injective_exchange_pb.OrderType.Value(order_type) + + return injective_exchange_pb.SpotOrder( + market_id=market_id, + order_info=injective_exchange_pb.OrderInfo( + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=chain_price, + quantity=chain_quantity, + cid=cid, + ), + order_type=chain_order_type, + trigger_price=chain_trigger_price, + ) + + def calculate_margin( + self, quantity: Decimal, price: Decimal, leverage: Decimal, is_reduce_only: bool = False + ) -> Decimal: + if is_reduce_only: + margin = Decimal(0) + else: + margin = quantity * price / leverage + + return margin + def DerivativeOrder( self, market_id: str, @@ -245,6 +301,10 @@ def DerivativeOrder( cid: Optional[str] = None, **kwargs, ): + """ + This method is deprecated and will be removed soon. Please use `derivative_order` instead + """ + warn("This method is deprecated. Use derivative_order instead", DeprecationWarning, stacklevel=2) market = self.derivative_markets[market_id] if kwargs.get("is_reduce_only", False): @@ -262,32 +322,32 @@ def DerivativeOrder( trigger_price = market.price_to_chain_format(human_readable_value=Decimal(str(trigger_price))) if kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY + order_type = injective_exchange_pb.OrderType.BUY elif not kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL + order_type = injective_exchange_pb.OrderType.SELL elif kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY_PO + order_type = injective_exchange_pb.OrderType.BUY_PO elif not kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL_PO + order_type = injective_exchange_pb.OrderType.SELL_PO elif kwargs.get("stop_buy"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.STOP_BUY + order_type = injective_exchange_pb.OrderType.STOP_BUY elif kwargs.get("stop_sell"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.STOP_SEll + order_type = injective_exchange_pb.OrderType.STOP_SEll elif kwargs.get("take_buy"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.TAKE_BUY + order_type = injective_exchange_pb.OrderType.TAKE_BUY elif kwargs.get("take_sell"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.TAKE_SELL + order_type = injective_exchange_pb.OrderType.TAKE_SELL - return injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.DerivativeOrder( + return injective_exchange_pb.DerivativeOrder( market_id=market_id, - order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( + order_info=injective_exchange_pb.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=str(int(price)), @@ -299,60 +359,121 @@ def DerivativeOrder( trigger_price=str(int(trigger_price)), ) - def BinaryOptionsOrder( + def derivative_order( self, market_id: str, subaccount_id: str, fee_recipient: str, - price: float, - quantity: float, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, cid: Optional[str] = None, - **kwargs, - ): - market = self.binary_option_markets[market_id] - denom = kwargs.get("denom", None) + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_pb.DerivativeOrder: + market = self.derivative_markets[market_id] - if kwargs.get("is_reduce_only", False): - margin = 0 - else: - margin = market.calculate_margin_in_chain_format( - human_readable_quantity=Decimal(str(quantity)), - human_readable_price=Decimal(str(price)), - is_buy=kwargs["is_buy"], - special_denom=denom, - ) + chain_quantity = market.quantity_to_chain_format(human_readable_value=quantity) + chain_price = market.price_to_chain_format(human_readable_value=price) + chain_margin = market.margin_to_chain_format(human_readable_value=margin) - # prepare values - price = market.price_to_chain_format(human_readable_value=Decimal(str(price)), special_denom=denom) - trigger_price = market.price_to_chain_format(human_readable_value=Decimal(str(0)), special_denom=denom) - quantity = market.quantity_to_chain_format(human_readable_value=Decimal(str(quantity)), special_denom=denom) + trigger_price = trigger_price or Decimal(0) + chain_trigger_price = market.price_to_chain_format(human_readable_value=trigger_price) - if kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY + return self._basic_derivative_order( + market_id=market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + chain_price=chain_price, + chain_quantity=chain_quantity, + chain_margin=chain_margin, + order_type=order_type, + cid=cid, + chain_trigger_price=chain_trigger_price, + ) - elif not kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL + def binary_options_order( + self, + market_id: str, + subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + denom: Optional[Denom] = None, + ) -> injective_exchange_pb.DerivativeOrder: + market = self.binary_option_markets[market_id] - elif kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY_PO + chain_quantity = market.quantity_to_chain_format(human_readable_value=quantity, special_denom=denom) + chain_price = market.price_to_chain_format(human_readable_value=price, special_denom=denom) + chain_margin = market.margin_to_chain_format(human_readable_value=margin, special_denom=denom) - elif not kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL_PO + trigger_price = trigger_price or Decimal(0) + chain_trigger_price = market.price_to_chain_format(human_readable_value=trigger_price, special_denom=denom) - return injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.DerivativeOrder( - market_id=market_id, - order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( - subaccount_id=subaccount_id, - fee_recipient=fee_recipient, - price=str(int(price)), - quantity=str(int(quantity)), - cid=cid, - ), - margin=str(int(margin)), + return self._basic_derivative_order( + market_id=market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + chain_price=chain_price, + chain_quantity=chain_quantity, + chain_margin=chain_margin, order_type=order_type, - trigger_price=str(int(trigger_price)), + cid=cid, + chain_trigger_price=chain_trigger_price, + ) + + # region Auction module + def MsgBid(self, sender: str, bid_amount: float, round: float): + be_amount = Decimal(str(bid_amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return injective_auction_tx_pb.MsgBid( + sender=sender, + round=round, + bid_amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), + ) + + # endregion + + # region Authz module + def MsgGrantGeneric(self, granter: str, grantee: str, msg_type: str, expire_in: int): + auth = cosmos_authz_pb.GenericAuthorization(msg=msg_type) + any_auth = any_pb2.Any() + any_auth.Pack(auth, type_url_prefix="") + + grant = cosmos_authz_pb.Grant( + authorization=any_auth, + expiration=timestamp_pb2.Timestamp(seconds=(int(time()) + expire_in)), + ) + + return cosmos_authz_tx_pb.MsgGrant(granter=granter, grantee=grantee, grant=grant) + + def MsgExec(self, grantee: str, msgs: List): + any_msgs: List[any_pb2.Any] = [] + for msg in msgs: + any_msg = any_pb2.Any() + any_msg.Pack(msg, type_url_prefix="") + any_msgs.append(any_msg) + + return cosmos_authz_tx_pb.MsgExec(grantee=grantee, msgs=any_msgs) + + def MsgRevoke(self, granter: str, grantee: str, msg_type: str): + return cosmos_authz_tx_pb.MsgRevoke(granter=granter, grantee=grantee, msg_type_url=msg_type) + + def msg_execute_contract_compat(self, sender: str, contract: str, msg: str, funds: str): + return wasmx_tx_pb.MsgExecuteContractCompat( + sender=sender, + contract=contract, + msg=msg, + funds=funds, ) + # endregion + + # region Bank module def MsgSend(self, from_address: str, to_address: str, amount: float, denom: str): coin = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) @@ -362,16 +483,14 @@ def MsgSend(self, from_address: str, to_address: str, amount: float, denom: str) amount=[coin], ) - def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): - return wasm_tx_pb.MsgExecuteContract( - sender=sender, - contract=contract, - msg=bytes(msg, "utf-8"), - funds=kwargs.get("funds") # funds is a list of cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin. - # The coins in the list must be sorted in alphabetical order by denoms. - ) + # endregion + # region Chain Exchange module def MsgDeposit(self, sender: str, subaccount_id: str, amount: float, denom: str): + """ + This method is deprecated and will be removed soon. Please use `msg_deposit` instead + """ + warn("This method is deprecated. Use msg_deposit instead", DeprecationWarning, stacklevel=2) coin = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgDeposit( @@ -380,6 +499,153 @@ def MsgDeposit(self, sender: str, subaccount_id: str, amount: float, denom: str) amount=coin, ) + def msg_deposit(self, sender: str, subaccount_id: str, amount: Decimal, denom: str): + coin = self.create_coin_amount(amount=amount, token_name=denom) + + return injective_exchange_tx_pb.MsgDeposit( + sender=sender, + subaccount_id=subaccount_id, + amount=coin, + ) + + def MsgWithdraw(self, sender: str, subaccount_id: str, amount: float, denom: str): + """ + This method is deprecated and will be removed soon. Please use `msg_withdraw` instead + """ + warn("This method is deprecated. Use msg_withdraw instead", DeprecationWarning, stacklevel=2) + be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) + + return injective_exchange_tx_pb.MsgWithdraw( + sender=sender, + subaccount_id=subaccount_id, + amount=be_amount, + ) + + def msg_withdraw(self, sender: str, subaccount_id: str, amount: Decimal, denom: str): + be_amount = self.create_coin_amount(amount=amount, token_name=denom) + + return injective_exchange_tx_pb.MsgWithdraw( + sender=sender, + subaccount_id=subaccount_id, + amount=be_amount, + ) + + def msg_instant_spot_market_launch( + self, + sender: str, + ticker: str, + base_denom: str, + quote_denom: str, + min_price_tick_size: Decimal, + min_quantity_tick_size: Decimal, + ) -> injective_exchange_tx_pb.MsgInstantSpotMarketLaunch: + base_token = self.tokens[base_denom] + quote_token = self.tokens[quote_denom] + + chain_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals - base_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + chain_min_quantity_tick_size = min_quantity_tick_size * Decimal( + f"1e{base_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + + return injective_exchange_tx_pb.MsgInstantSpotMarketLaunch( + sender=sender, + ticker=ticker, + base_denom=base_token.denom, + quote_denom=quote_token.denom, + min_price_tick_size=f"{chain_min_price_tick_size.normalize():f}", + min_quantity_tick_size=f"{chain_min_quantity_tick_size.normalize():f}", + ) + + def msg_instant_perpetual_market_launch( + self, + sender: str, + ticker: str, + quote_denom: str, + oracle_base: str, + oracle_quote: str, + oracle_scale_factor: int, + oracle_type: str, + maker_fee_rate: Decimal, + taker_fee_rate: Decimal, + initial_margin_ratio: Decimal, + maintenance_margin_ratio: Decimal, + min_price_tick_size: Decimal, + min_quantity_tick_size: Decimal, + ) -> injective_exchange_tx_pb.MsgInstantPerpetualMarketLaunch: + quote_token = self.tokens[quote_denom] + + chain_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + chain_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_initial_margin_ratio = initial_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maintenance_margin_ratio = maintenance_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return injective_exchange_tx_pb.MsgInstantPerpetualMarketLaunch( + sender=sender, + ticker=ticker, + quote_denom=quote_token.denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_scale_factor=oracle_scale_factor, + oracle_type=injective_oracle_pb.OracleType.Value(oracle_type), + maker_fee_rate=f"{chain_maker_fee_rate.normalize():f}", + taker_fee_rate=f"{chain_taker_fee_rate.normalize():f}", + initial_margin_ratio=f"{chain_initial_margin_ratio.normalize():f}", + maintenance_margin_ratio=f"{chain_maintenance_margin_ratio.normalize():f}", + min_price_tick_size=f"{chain_min_price_tick_size.normalize():f}", + min_quantity_tick_size=f"{chain_min_quantity_tick_size.normalize():f}", + ) + + def msg_instant_expiry_futures_market_launch( + self, + sender: str, + ticker: str, + quote_denom: str, + oracle_base: str, + oracle_quote: str, + oracle_scale_factor: int, + oracle_type: str, + expiry: int, + maker_fee_rate: Decimal, + taker_fee_rate: Decimal, + initial_margin_ratio: Decimal, + maintenance_margin_ratio: Decimal, + min_price_tick_size: Decimal, + min_quantity_tick_size: Decimal, + ) -> injective_exchange_tx_pb.MsgInstantPerpetualMarketLaunch: + quote_token = self.tokens[quote_denom] + + chain_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + chain_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_initial_margin_ratio = initial_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maintenance_margin_ratio = maintenance_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return injective_exchange_tx_pb.MsgInstantExpiryFuturesMarketLaunch( + sender=sender, + ticker=ticker, + quote_denom=quote_token.denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_scale_factor=oracle_scale_factor, + oracle_type=injective_oracle_pb.OracleType.Value(oracle_type), + expiry=expiry, + maker_fee_rate=f"{chain_maker_fee_rate.normalize():f}", + taker_fee_rate=f"{chain_taker_fee_rate.normalize():f}", + initial_margin_ratio=f"{chain_initial_margin_ratio.normalize():f}", + maintenance_margin_ratio=f"{chain_maintenance_margin_ratio.normalize():f}", + min_price_tick_size=f"{chain_min_price_tick_size.normalize():f}", + min_quantity_tick_size=f"{chain_min_quantity_tick_size.normalize():f}", + ) + def MsgCreateSpotLimitOrder( self, market_id: str, @@ -391,52 +657,151 @@ def MsgCreateSpotLimitOrder( cid: Optional[str] = None, **kwargs, ): + """ + This method is deprecated and will be removed soon. Please use `msg_create_spot_limit_order` instead + """ + warn("This method is deprecated. Use msg_create_spot_limit_order instead", DeprecationWarning, stacklevel=2) + + order_type_name = "BUY" + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) + + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + return injective_exchange_tx_pb.MsgCreateSpotLimitOrder( sender=sender, - order=self.SpotOrder( + order=self.spot_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=price, - quantity=quantity, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + order_type=order_type_name, cid=cid, - **kwargs, ), ) - def MsgCreateSpotMarketOrder( + def msg_create_spot_limit_order( self, market_id: str, sender: str, subaccount_id: str, fee_recipient: str, - price: float, - quantity: float, - is_buy: bool, + price: Decimal, + quantity: Decimal, + order_type: str, cid: Optional[str] = None, - ): - return injective_exchange_tx_pb.MsgCreateSpotMarketOrder( + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_tx_pb.MsgCreateSpotLimitOrder: + return injective_exchange_tx_pb.MsgCreateSpotLimitOrder( sender=sender, - order=self.SpotOrder( + order=self.spot_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=price, quantity=quantity, - is_buy=is_buy, + order_type=order_type, cid=cid, + trigger_price=trigger_price, ), ) - def MsgCancelSpotOrder( + def MsgBatchCreateSpotLimitOrders(self, sender: str, orders: List): + """ + This method is deprecated and will be removed soon. Please use `msg_batch_create_spot_limit_orders` instead + """ + warn( + "This method is deprecated. Use msg_batch_create_spot_limit_orders instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders(sender=sender, orders=orders) + + def msg_batch_create_spot_limit_orders( + self, sender: str, orders: List[injective_exchange_pb.SpotOrder] + ) -> injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders: + return injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders(sender=sender, orders=orders) + + def MsgCreateSpotMarketOrder( self, market_id: str, sender: str, subaccount_id: str, - order_hash: Optional[str] = None, + fee_recipient: str, + price: float, + quantity: float, + is_buy: bool, cid: Optional[str] = None, ): - return injective_exchange_tx_pb.MsgCancelSpotOrder( + """ + This method is deprecated and will be removed soon. Please use `msg_create_spot_market_order` instead + """ + warn("This method is deprecated. Use msg_create_spot_market_order instead", DeprecationWarning, stacklevel=2) + + order_type_name = "BUY" + if not is_buy: + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + return injective_exchange_tx_pb.MsgCreateSpotMarketOrder( + sender=sender, + order=self.spot_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + order_type=order_type_name, + cid=cid, + ), + ) + + def msg_create_spot_market_order( + self, + market_id: str, + sender: str, + subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_tx_pb.MsgCreateSpotMarketOrder: + return injective_exchange_tx_pb.MsgCreateSpotMarketOrder( + sender=sender, + order=self.spot_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ), + ) + + def MsgCancelSpotOrder( + self, + market_id: str, + sender: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + ): + """ + This method is deprecated and will be removed soon. Please use `msg_cancel_spot_order` instead + """ + warn("This method is deprecated. Use msg_cancel_spot_order instead", DeprecationWarning, stacklevel=2) + return injective_exchange_tx_pb.MsgCancelSpotOrder( sender=sender, market_id=market_id, subaccount_id=subaccount_id, @@ -444,14 +809,111 @@ def MsgCancelSpotOrder( cid=cid, ) - def MsgBatchCreateSpotLimitOrders(self, sender: str, orders: List): - return injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders(sender=sender, orders=orders) + def msg_cancel_spot_order( + self, + market_id: str, + sender: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + ) -> injective_exchange_tx_pb.MsgCancelSpotOrder: + return injective_exchange_tx_pb.MsgCancelSpotOrder( + sender=sender, + market_id=market_id, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + ) def MsgBatchCancelSpotOrders(self, sender: str, data: List): + """ + This method is deprecated and will be removed soon. Please use `msg_batch_cancel_spot_orders` instead + """ + warn("This method is deprecated. Use msg_batch_cancel_spot_orders instead", DeprecationWarning, stacklevel=2) return injective_exchange_tx_pb.MsgBatchCancelSpotOrders(sender=sender, data=data) - def MsgRewardsOptOut(self, sender: str): - return injective_exchange_tx_pb.MsgRewardsOptOut(sender=sender) + def msg_batch_cancel_spot_orders( + self, sender: str, orders_data: List[injective_exchange_tx_pb.OrderData] + ) -> injective_exchange_tx_pb.MsgBatchCancelSpotOrders: + return injective_exchange_tx_pb.MsgBatchCancelSpotOrders(sender=sender, data=orders_data) + + def MsgBatchUpdateOrders(self, sender: str, **kwargs): + """ + This method is deprecated and will be removed soon. Please use `msg_batch_update_orders` instead + """ + warn("This method is deprecated. Use msg_batch_update_orders instead", DeprecationWarning, stacklevel=2) + return injective_exchange_tx_pb.MsgBatchUpdateOrders( + sender=sender, + subaccount_id=kwargs.get("subaccount_id"), + spot_market_ids_to_cancel_all=kwargs.get("spot_market_ids_to_cancel_all"), + derivative_market_ids_to_cancel_all=kwargs.get("derivative_market_ids_to_cancel_all"), + spot_orders_to_cancel=kwargs.get("spot_orders_to_cancel"), + derivative_orders_to_cancel=kwargs.get("derivative_orders_to_cancel"), + spot_orders_to_create=kwargs.get("spot_orders_to_create"), + derivative_orders_to_create=kwargs.get("derivative_orders_to_create"), + binary_options_orders_to_cancel=kwargs.get("binary_options_orders_to_cancel"), + binary_options_market_ids_to_cancel_all=kwargs.get("binary_options_market_ids_to_cancel_all"), + binary_options_orders_to_create=kwargs.get("binary_options_orders_to_create"), + ) + + def msg_batch_update_orders( + self, + sender: str, + subaccount_id: Optional[str] = None, + spot_market_ids_to_cancel_all: Optional[List[str]] = None, + derivative_market_ids_to_cancel_all: Optional[List[str]] = None, + spot_orders_to_cancel: Optional[List[injective_exchange_tx_pb.OrderData]] = None, + derivative_orders_to_cancel: Optional[List[injective_exchange_tx_pb.OrderData]] = None, + spot_orders_to_create: Optional[List[injective_exchange_pb.SpotOrder]] = None, + derivative_orders_to_create: Optional[List[injective_exchange_pb.DerivativeOrder]] = None, + binary_options_orders_to_cancel: Optional[List[injective_exchange_tx_pb.OrderData]] = None, + binary_options_market_ids_to_cancel_all: Optional[List[str]] = None, + binary_options_orders_to_create: Optional[List[injective_exchange_pb.DerivativeOrder]] = None, + ) -> injective_exchange_tx_pb.MsgBatchUpdateOrders: + return injective_exchange_tx_pb.MsgBatchUpdateOrders( + sender=sender, + subaccount_id=subaccount_id, + spot_market_ids_to_cancel_all=spot_market_ids_to_cancel_all, + derivative_market_ids_to_cancel_all=derivative_market_ids_to_cancel_all, + spot_orders_to_cancel=spot_orders_to_cancel, + derivative_orders_to_cancel=derivative_orders_to_cancel, + spot_orders_to_create=spot_orders_to_create, + derivative_orders_to_create=derivative_orders_to_create, + binary_options_orders_to_cancel=binary_options_orders_to_cancel, + binary_options_market_ids_to_cancel_all=binary_options_market_ids_to_cancel_all, + binary_options_orders_to_create=binary_options_orders_to_create, + ) + + def MsgPrivilegedExecuteContract( + self, sender: str, contract: str, msg: str, **kwargs + ) -> injective_exchange_tx_pb.MsgPrivilegedExecuteContract: + """ + This method is deprecated and will be removed soon. Please use `msg_privileged_execute_contract` instead + """ + warn("This method is deprecated. Use msg_privileged_execute_contract instead", DeprecationWarning, stacklevel=2) + + return injective_exchange_tx_pb.MsgPrivilegedExecuteContract( + sender=sender, + contract_address=contract, + data=msg, + funds=kwargs.get("funds") # funds is a string of Coin strings, comma separated, + # e.g. 100000inj,20000000000usdt + ) + + def msg_privileged_execute_contract( + self, + sender: str, + contract_address: str, + data: str, + funds: Optional[str] = None, + ) -> injective_exchange_tx_pb.MsgPrivilegedExecuteContract: + # funds is a string of Coin strings, comma separated, e.g. 100000inj,20000000000usdt + return injective_exchange_tx_pb.MsgPrivilegedExecuteContract( + sender=sender, + contract_address=contract_address, + data=data, + funds=funds, + ) def MsgCreateDerivativeLimitOrder( self, @@ -464,46 +926,105 @@ def MsgCreateDerivativeLimitOrder( cid: Optional[str] = None, **kwargs, ): + """ + This method is deprecated and will be removed soon. Please use `msg_create_derivative_limit_order` instead + """ + warn( + "This method is deprecated. Use msg_create_derivative_limit_order instead", DeprecationWarning, stacklevel=2 + ) + + if kwargs.get("is_reduce_only", False): + margin = Decimal(0) + else: + margin = Decimal(str(price)) * Decimal(str(quantity)) / Decimal(str(kwargs["leverage"])) + + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) + + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + + elif kwargs.get("stop_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_BUY) + + elif kwargs.get("stop_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_SEll) + + elif kwargs.get("take_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_BUY) + + elif kwargs.get("take_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_SELL) + return injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder( sender=sender, - order=self.DerivativeOrder( + order=self.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=price, - quantity=quantity, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + margin=margin, + order_type=order_type, cid=cid, - **kwargs, + trigger_price=Decimal(str(kwargs["trigger_price"])) if "trigger_price" in kwargs else None, ), ) - def MsgCreateDerivativeMarketOrder( + def msg_create_derivative_limit_order( self, market_id: str, sender: str, subaccount_id: str, fee_recipient: str, - price: float, - quantity: float, - is_buy: bool, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, cid: Optional[str] = None, - **kwargs, - ): - return injective_exchange_tx_pb.MsgCreateDerivativeMarketOrder( + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder: + return injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder( sender=sender, - order=self.DerivativeOrder( + order=self.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=price, quantity=quantity, - is_buy=is_buy, + margin=margin, + order_type=order_type, cid=cid, - **kwargs, + trigger_price=trigger_price, ), ) - def MsgCreateBinaryOptionsLimitOrder( + def MsgBatchCreateDerivativeLimitOrders(self, sender: str, orders: List): + """ + This method is deprecated and will be removed soon. + Please use `msg_batch_create_derivative_limit_orders` instead + """ + warn( + "This method is deprecated. Use msg_batch_create_derivative_limit_orders instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders(sender=sender, orders=orders) + + def msg_batch_create_derivative_limit_orders( + self, + sender: str, + orders: List[injective_exchange_pb.DerivativeOrder], + ) -> injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders: + return injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders(sender=sender, orders=orders) + + def MsgCreateDerivativeMarketOrder( self, market_id: str, sender: str, @@ -514,95 +1035,156 @@ def MsgCreateBinaryOptionsLimitOrder( cid: Optional[str] = None, **kwargs, ): - return injective_exchange_tx_pb.MsgCreateBinaryOptionsLimitOrder( + """ + This method is deprecated and will be removed soon. Please use `msg_create_derivative_market_order` instead + """ + warn( + "This method is deprecated. Use msg_create_derivative_market_order instead", + DeprecationWarning, + stacklevel=2, + ) + + if kwargs.get("is_reduce_only", False): + margin = Decimal(0) + else: + margin = Decimal(str(price)) * Decimal(str(quantity)) / Decimal(str(kwargs["leverage"])) + + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) + + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + + elif kwargs.get("stop_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_BUY) + + elif kwargs.get("stop_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_SEll) + + elif kwargs.get("take_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_BUY) + + elif kwargs.get("take_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_SELL) + + return injective_exchange_tx_pb.MsgCreateDerivativeMarketOrder( sender=sender, - order=self.BinaryOptionsOrder( + order=self.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=price, - quantity=quantity, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + margin=margin, + order_type=order_type, cid=cid, - **kwargs, + trigger_price=Decimal(str(kwargs["trigger_price"])) if "trigger_price" in kwargs else None, ), ) - def MsgCreateBinaryOptionsMarketOrder( + def msg_create_derivative_market_order( self, market_id: str, sender: str, subaccount_id: str, fee_recipient: str, - price: float, - quantity: float, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, cid: Optional[str] = None, - **kwargs, - ): - return injective_exchange_tx_pb.MsgCreateBinaryOptionsMarketOrder( + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_tx_pb.MsgCreateDerivativeMarketOrder: + return injective_exchange_tx_pb.MsgCreateDerivativeMarketOrder( sender=sender, - order=self.BinaryOptionsOrder( + order=self.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=price, quantity=quantity, + margin=margin, + order_type=order_type, cid=cid, - **kwargs, + trigger_price=trigger_price, ), ) - def MsgCancelBinaryOptionsOrder( + def MsgCancelDerivativeOrder( self, - sender: str, market_id: str, + sender: str, subaccount_id: str, order_hash: Optional[str] = None, cid: Optional[str] = None, + **kwargs, ): - return injective_exchange_tx_pb.MsgCancelBinaryOptionsOrder( + """ + This method is deprecated and will be removed soon. Please use `msg_cancel_derivative_order` instead + """ + warn( + "This method is deprecated. Use msg_cancel_derivative_order instead", + DeprecationWarning, + stacklevel=2, + ) + + is_conditional = kwargs.get("is_conditional", False) + is_buy = kwargs.get("order_direction", "buy") == "buy" + is_market_order = kwargs.get("order_type", "limit") == "market" + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) + + return injective_exchange_tx_pb.MsgCancelDerivativeOrder( sender=sender, market_id=market_id, subaccount_id=subaccount_id, order_hash=order_hash, + order_mask=order_mask, cid=cid, ) - def MsgAdminUpdateBinaryOptionsMarket( + def msg_cancel_derivative_order( self, - sender: str, market_id: str, - status: str, - **kwargs, - ): - price_to_bytes = None - - if kwargs.get("settlement_price") is not None: - scale_price = Decimal((kwargs.get("settlement_price") * pow(10, 18))) - price_to_bytes = bytes(str(scale_price), "utf-8") - - else: - price_to_bytes = "" + sender: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + is_conditional: Optional[bool] = False, + is_buy: Optional[bool] = False, + is_market_order: Optional[bool] = False, + ) -> injective_exchange_tx_pb.MsgCancelDerivativeOrder: + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) - return injective_exchange_tx_pb.MsgAdminUpdateBinaryOptionsMarket( + return injective_exchange_tx_pb.MsgCancelDerivativeOrder( sender=sender, market_id=market_id, - settlement_price=price_to_bytes, - expiration_timestamp=kwargs.get("expiration_timestamp"), - settlement_timestamp=kwargs.get("settlement_timestamp"), - status=status, + subaccount_id=subaccount_id, + order_hash=order_hash, + order_mask=order_mask, + cid=cid, ) - def MsgRelayProviderPrices(self, sender: str, provider: str, symbols: list, prices: list): - oracle_prices = [] - - for price in prices: - scale_price = Decimal((price) * pow(10, 18)) - price_to_bytes = bytes(str(scale_price), "utf-8") - oracle_prices.append(price_to_bytes) - - return injective_oracle_tx_pb.MsgRelayProviderPrices( - sender=sender, provider=provider, symbols=symbols, prices=oracle_prices + def MsgBatchCancelDerivativeOrders(self, sender: str, data: List): + """ + This method is deprecated and will be removed soon. Please use `msg_batch_cancel_derivative_orders` instead + """ + warn( + "This method is deprecated. Use msg_batch_cancel_derivative_orders instead", + DeprecationWarning, + stacklevel=2, ) + return injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders(sender=sender, data=data) + + def msg_batch_cancel_derivative_orders( + self, sender: str, orders_data: List[injective_exchange_tx_pb.OrderData] + ) -> injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders: + return injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders(sender=sender, data=orders_data) def MsgInstantBinaryOptionsMarketLaunch( self, @@ -622,6 +1204,15 @@ def MsgInstantBinaryOptionsMarketLaunch( min_quantity_tick_size: float, **kwargs, ): + """ + This method is deprecated and will be removed soon. + Please use `msg_instant_binary_options_market_launch` instead + """ + warn( + "This method is deprecated. Use msg_instant_binary_options_market_launch instead", + DeprecationWarning, + stacklevel=2, + ) scaled_maker_fee_rate = Decimal((maker_fee_rate * pow(10, 18))) maker_fee_to_bytes = bytes(str(scaled_maker_fee_rate), "utf-8") @@ -651,75 +1242,281 @@ def MsgInstantBinaryOptionsMarketLaunch( admin=kwargs.get("admin"), ) - def MsgCancelDerivativeOrder( + def msg_instant_binary_options_market_launch( self, - market_id: str, sender: str, - subaccount_id: str, - order_hash: Optional[str] = None, - cid: Optional[str] = None, - **kwargs, - ): - order_mask = self.get_order_mask(**kwargs) - - return injective_exchange_tx_pb.MsgCancelDerivativeOrder( + ticker: str, + oracle_symbol: str, + oracle_provider: str, + oracle_type: str, + oracle_scale_factor: int, + maker_fee_rate: Decimal, + taker_fee_rate: Decimal, + expiration_timestamp: int, + settlement_timestamp: int, + admin: str, + quote_denom: str, + min_price_tick_size: Decimal, + min_quantity_tick_size: Decimal, + ) -> injective_exchange_tx_pb.MsgInstantPerpetualMarketLaunch: + quote_token = self.tokens[quote_denom] + + chain_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + chain_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return injective_exchange_tx_pb.MsgInstantBinaryOptionsMarketLaunch( sender=sender, - market_id=market_id, - subaccount_id=subaccount_id, - order_hash=order_hash, - order_mask=order_mask, - cid=cid, + ticker=ticker, + oracle_symbol=oracle_symbol, + oracle_provider=oracle_provider, + oracle_type=injective_oracle_pb.OracleType.Value(oracle_type), + oracle_scale_factor=oracle_scale_factor, + maker_fee_rate=f"{chain_maker_fee_rate.normalize():f}", + taker_fee_rate=f"{chain_taker_fee_rate.normalize():f}", + expiration_timestamp=expiration_timestamp, + settlement_timestamp=settlement_timestamp, + admin=admin, + quote_denom=quote_token.denom, + min_price_tick_size=f"{chain_min_price_tick_size.normalize():f}", + min_quantity_tick_size=f"{chain_min_quantity_tick_size.normalize():f}", ) - def MsgBatchCreateDerivativeLimitOrders(self, sender: str, orders: List): - return injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders(sender=sender, orders=orders) + def MsgCreateBinaryOptionsLimitOrder( + self, + market_id: str, + sender: str, + subaccount_id: str, + fee_recipient: str, + price: float, + quantity: float, + cid: Optional[str] = None, + **kwargs, + ): + """ + This method is deprecated and will be removed soon. Please use `msg_create_binary_options_limit_order` instead + """ + warn( + "This method is deprecated. Use msg_create_binary_options_limit_order instead", + DeprecationWarning, + stacklevel=2, + ) + if kwargs.get("is_reduce_only", False): + margin = Decimal(0) + else: + margin = Decimal(str(price)) * Decimal(str(quantity)) - def MsgBatchCancelDerivativeOrders(self, sender: str, data: List): - return injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders(sender=sender, data=data) + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) - def MsgBatchUpdateOrders(self, sender: str, **kwargs): - return injective_exchange_tx_pb.MsgBatchUpdateOrders( + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + + elif kwargs.get("stop_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_BUY) + + elif kwargs.get("stop_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_SEll) + + elif kwargs.get("take_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_BUY) + + elif kwargs.get("take_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_SELL) + + return injective_exchange_tx_pb.MsgCreateBinaryOptionsLimitOrder( sender=sender, - subaccount_id=kwargs.get("subaccount_id"), - spot_market_ids_to_cancel_all=kwargs.get("spot_market_ids_to_cancel_all"), - derivative_market_ids_to_cancel_all=kwargs.get("derivative_market_ids_to_cancel_all"), - spot_orders_to_cancel=kwargs.get("spot_orders_to_cancel"), - derivative_orders_to_cancel=kwargs.get("derivative_orders_to_cancel"), - spot_orders_to_create=kwargs.get("spot_orders_to_create"), - derivative_orders_to_create=kwargs.get("derivative_orders_to_create"), - binary_options_orders_to_cancel=kwargs.get("binary_options_orders_to_cancel"), - binary_options_market_ids_to_cancel_all=kwargs.get("binary_options_market_ids_to_cancel_all"), - binary_options_orders_to_create=kwargs.get("binary_options_orders_to_create"), + order=self.binary_options_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=Decimal(str(kwargs["trigger_price"])) if "trigger_price" in kwargs else None, + denom=kwargs.get("denom"), + ), ) - def MsgLiquidatePosition( + def msg_create_binary_options_limit_order( self, + market_id: str, sender: str, subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + denom: Optional[Denom] = None, + ) -> injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder: + return injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder( + sender=sender, + order=self.binary_options_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + denom=denom, + ), + ) + + def MsgCreateBinaryOptionsMarketOrder( + self, market_id: str, - order: Optional[injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.DerivativeOrder] = None, + sender: str, + subaccount_id: str, + fee_recipient: str, + price: float, + quantity: float, + cid: Optional[str] = None, + **kwargs, ): - return injective_exchange_tx_pb.MsgLiquidatePosition( - sender=sender, subaccount_id=subaccount_id, market_id=market_id, order=order + """ + This method is deprecated and will be removed soon. Please use `msg_create_binary_options_market_order` instead + """ + warn( + "This method is deprecated. Use msg_create_binary_options_market_order instead", + DeprecationWarning, + stacklevel=2, ) + if kwargs.get("is_reduce_only", False): + margin = Decimal(0) + else: + margin = Decimal(str(price)) * Decimal(str(quantity)) - def MsgIncreasePositionMargin( + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) + + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + + elif kwargs.get("stop_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_BUY) + + elif kwargs.get("stop_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_SEll) + + elif kwargs.get("take_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_BUY) + + elif kwargs.get("take_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_SELL) + + return injective_exchange_tx_pb.MsgCreateBinaryOptionsMarketOrder( + sender=sender, + order=self.binary_options_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=Decimal(str(kwargs["trigger_price"])) if "trigger_price" in kwargs else None, + denom=kwargs.get("denom"), + ), + ) + + def msg_create_binary_options_market_order( + self, + market_id: str, + sender: str, + subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + denom: Optional[Denom] = None, + ): + return injective_exchange_tx_pb.MsgCreateBinaryOptionsMarketOrder( + sender=sender, + order=self.binary_options_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + denom=denom, + ), + ) + + def MsgCancelBinaryOptionsOrder( self, sender: str, - source_subaccount_id: str, - destination_subaccount_id: str, market_id: str, - amount: float, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, ): - market = self.derivative_markets[market_id] + """ + This method is deprecated and will be removed soon. Please use `msg_cancel_binary_options_order` instead + """ + warn( + "This method is deprecated. Use msg_cancel_binary_options_order instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgCancelBinaryOptionsOrder( + sender=sender, + market_id=market_id, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + ) - additional_margin = market.margin_to_chain_format(human_readable_value=Decimal(str(amount))) - return injective_exchange_tx_pb.MsgIncreasePositionMargin( + def msg_cancel_binary_options_order( + self, + market_id: str, + sender: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + is_conditional: Optional[bool] = False, + is_buy: Optional[bool] = False, + is_market_order: Optional[bool] = False, + ) -> injective_exchange_tx_pb.MsgCancelBinaryOptionsOrder: + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) + + return injective_exchange_tx_pb.MsgCancelBinaryOptionsOrder( sender=sender, - source_subaccount_id=source_subaccount_id, - destination_subaccount_id=destination_subaccount_id, market_id=market_id, - amount=str(int(additional_margin)), + subaccount_id=subaccount_id, + order_hash=order_hash, + order_mask=order_mask, + cid=cid, ) def MsgSubaccountTransfer( @@ -730,6 +1527,14 @@ def MsgSubaccountTransfer( amount: int, denom: str, ): + """ + This method is deprecated and will be removed soon. Please use `msg_subaccount_transfer` instead + """ + warn( + "This method is deprecated. Use msg_subaccount_transfer instead", + DeprecationWarning, + stacklevel=2, + ) be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgSubaccountTransfer( @@ -739,12 +1544,20 @@ def MsgSubaccountTransfer( amount=be_amount, ) - def MsgWithdraw(self, sender: str, subaccount_id: str, amount: float, denom: str): - be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) + def msg_subaccount_transfer( + self, + sender: str, + source_subaccount_id: str, + destination_subaccount_id: str, + amount: Decimal, + denom: str, + ) -> injective_exchange_tx_pb.MsgSubaccountTransfer: + be_amount = self.create_coin_amount(amount=amount, token_name=denom) - return injective_exchange_tx_pb.MsgWithdraw( + return injective_exchange_tx_pb.MsgSubaccountTransfer( sender=sender, - subaccount_id=subaccount_id, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, amount=be_amount, ) @@ -756,6 +1569,14 @@ def MsgExternalTransfer( amount: int, denom: str, ): + """ + This method is deprecated and will be removed soon. Please use `msg_external_transfer` instead + """ + warn( + "This method is deprecated. Use msg_external_transfer instead", + DeprecationWarning, + stacklevel=2, + ) coin = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgExternalTransfer( @@ -765,129 +1586,184 @@ def MsgExternalTransfer( amount=coin, ) - def MsgBid(self, sender: str, bid_amount: float, round: float): - be_amount = Decimal(str(bid_amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + def msg_external_transfer( + self, + sender: str, + source_subaccount_id: str, + destination_subaccount_id: str, + amount: Decimal, + denom: str, + ) -> injective_exchange_tx_pb.MsgExternalTransfer: + coin = self.create_coin_amount(amount=amount, token_name=denom) - return injective_auction_tx_pb.MsgBid( + return injective_exchange_tx_pb.MsgExternalTransfer( sender=sender, - round=round, - bid_amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + amount=coin, ) - def MsgGrantGeneric(self, granter: str, grantee: str, msg_type: str, expire_in: int): - auth = cosmos_authz_pb.GenericAuthorization(msg=msg_type) - any_auth = any_pb2.Any() - any_auth.Pack(auth, type_url_prefix="") - - grant = cosmos_authz_pb.Grant( - authorization=any_auth, - expiration=timestamp_pb2.Timestamp(seconds=(int(time()) + expire_in)), + def MsgLiquidatePosition( + self, + sender: str, + subaccount_id: str, + market_id: str, + order: Optional[injective_exchange_pb.DerivativeOrder] = None, + ): + """ + This method is deprecated and will be removed soon. Please use `msg_liquidate_position` instead + """ + warn( + "This method is deprecated. Use msg_liquidate_position instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgLiquidatePosition( + sender=sender, subaccount_id=subaccount_id, market_id=market_id, order=order ) - return cosmos_authz_tx_pb.MsgGrant(granter=granter, grantee=grantee, grant=grant) + def msg_liquidate_position( + self, + sender: str, + subaccount_id: str, + market_id: str, + order: Optional[injective_exchange_pb.DerivativeOrder] = None, + ) -> injective_exchange_tx_pb.MsgLiquidatePosition: + return injective_exchange_tx_pb.MsgLiquidatePosition( + sender=sender, subaccount_id=subaccount_id, market_id=market_id, order=order + ) - def MsgGrantTyped( + def msg_emergency_settle_market( self, - granter: str, - grantee: str, - msg_type: str, - expire_in: int, + sender: str, subaccount_id: str, - **kwargs, + market_id: str, + ) -> injective_exchange_tx_pb.MsgEmergencySettleMarket: + return injective_exchange_tx_pb.MsgEmergencySettleMarket( + sender=sender, subaccount_id=subaccount_id, market_id=market_id + ) + + def MsgIncreasePositionMargin( + self, + sender: str, + source_subaccount_id: str, + destination_subaccount_id: str, + market_id: str, + amount: float, ): - auth = None - if msg_type == "CreateSpotLimitOrderAuthz": - auth = injective_authz_pb.CreateSpotLimitOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CreateSpotMarketOrderAuthz": - auth = injective_authz_pb.CreateSpotMarketOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchCreateSpotLimitOrdersAuthz": - auth = injective_authz_pb.BatchCreateSpotLimitOrdersAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CancelSpotOrderAuthz": - auth = injective_authz_pb.CancelSpotOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchCancelSpotOrdersAuthz": - auth = injective_authz_pb.BatchCancelSpotOrdersAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CreateDerivativeLimitOrderAuthz": - auth = injective_authz_pb.CreateDerivativeLimitOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CreateDerivativeMarketOrderAuthz": - auth = injective_authz_pb.CreateDerivativeMarketOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchCreateDerivativeLimitOrdersAuthz": - auth = injective_authz_pb.BatchCreateDerivativeLimitOrdersAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CancelDerivativeOrderAuthz": - auth = injective_authz_pb.CancelDerivativeOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchCancelDerivativeOrdersAuthz": - auth = injective_authz_pb.BatchCancelDerivativeOrdersAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchUpdateOrdersAuthz": - auth = injective_authz_pb.BatchUpdateOrdersAuthz( - subaccount_id=subaccount_id, - spot_markets=kwargs.get("spot_markets"), - derivative_markets=kwargs.get("derivative_markets"), - ) + """ + This method is deprecated and will be removed soon. Please use `msg_increase_position_margin` instead + """ + warn( + "This method is deprecated. Use msg_increase_position_margin instead", + DeprecationWarning, + stacklevel=2, + ) + market = self.derivative_markets[market_id] - any_auth = any_pb2.Any() - any_auth.Pack(auth, type_url_prefix="") + additional_margin = market.margin_to_chain_format(human_readable_value=Decimal(str(amount))) + return injective_exchange_tx_pb.MsgIncreasePositionMargin( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + market_id=market_id, + amount=str(int(additional_margin)), + ) - grant = cosmos_authz_pb.Grant( - authorization=any_auth, - expiration=timestamp_pb2.Timestamp(seconds=(int(time()) + expire_in)), + def msg_increase_position_margin( + self, + sender: str, + source_subaccount_id: str, + destination_subaccount_id: str, + market_id: str, + amount: Decimal, + ): + market = self.derivative_markets[market_id] + + additional_margin = market.margin_to_chain_format(human_readable_value=amount) + return injective_exchange_tx_pb.MsgIncreasePositionMargin( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + market_id=market_id, + amount=str(int(additional_margin)), ) - return cosmos_authz_tx_pb.MsgGrant(granter=granter, grantee=grantee, grant=grant) - - def MsgExec(self, grantee: str, msgs: List): - any_msgs: List[any_pb2.Any] = [] - for msg in msgs: - any_msg = any_pb2.Any() - any_msg.Pack(msg, type_url_prefix="") - any_msgs.append(any_msg) + def MsgRewardsOptOut(self, sender: str): + """ + This method is deprecated and will be removed soon. Please use `msg_rewards_opt_out` instead + """ + warn( + "This method is deprecated. Use msg_rewards_opt_out instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgRewardsOptOut(sender=sender) - return cosmos_authz_tx_pb.MsgExec(grantee=grantee, msgs=any_msgs) + def msg_rewards_opt_out(self, sender: str) -> injective_exchange_tx_pb.MsgRewardsOptOut: + return injective_exchange_tx_pb.MsgRewardsOptOut(sender=sender) - def MsgRevoke(self, granter: str, grantee: str, msg_type: str): - return cosmos_authz_tx_pb.MsgRevoke(granter=granter, grantee=grantee, msg_type_url=msg_type) + def MsgAdminUpdateBinaryOptionsMarket( + self, + sender: str, + market_id: str, + status: str, + **kwargs, + ): + """ + This method is deprecated and will be removed soon. Please use `msg_admin_update_binary_options_market` instead + """ + warn( + "This method is deprecated. Use msg_admin_update_binary_options_market instead", + DeprecationWarning, + stacklevel=2, + ) - def MsgRelayPriceFeedPrice(self, sender: list, base: list, quote: list, price: list): - return injective_oracle_tx_pb.MsgRelayPriceFeedPrice(sender=sender, base=base, quote=quote, price=price) + if kwargs.get("settlement_price") is not None: + scale_price = Decimal((kwargs.get("settlement_price") * pow(10, 18))) + price_to_bytes = bytes(str(scale_price), "utf-8") - def MsgSendToEth(self, denom: str, sender: str, eth_dest: str, amount: float, bridge_fee: float): - be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) - be_bridge_fee = self.create_coin_amount(amount=Decimal(str(bridge_fee)), token_name=denom) + else: + price_to_bytes = "" - return injective_peggy_tx_pb.MsgSendToEth( + return injective_exchange_tx_pb.MsgAdminUpdateBinaryOptionsMarket( sender=sender, - eth_dest=eth_dest, - amount=be_amount, - bridge_fee=be_bridge_fee, + market_id=market_id, + settlement_price=price_to_bytes, + expiration_timestamp=kwargs.get("expiration_timestamp"), + settlement_timestamp=kwargs.get("settlement_timestamp"), + status=status, ) - def MsgDelegate(self, delegator_address: str, validator_address: str, amount: float): - be_amount = Decimal(str(amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + def msg_admin_update_binary_options_market( + self, + sender: str, + market_id: str, + status: str, + settlement_price: Optional[Decimal] = None, + expiration_timestamp: Optional[int] = None, + settlement_timestamp: Optional[int] = None, + ) -> injective_exchange_tx_pb.MsgAdminUpdateBinaryOptionsMarket: + market = self.binary_option_markets[market_id] - return cosmos_staking_tx_pb.MsgDelegate( - delegator_address=delegator_address, - validator_address=validator_address, - amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), + if settlement_price is not None: + chain_settlement_price = market.price_to_chain_format(human_readable_value=settlement_price) + price_parameter = f"{chain_settlement_price.normalize():f}" + else: + price_parameter = None + + return injective_exchange_tx_pb.MsgAdminUpdateBinaryOptionsMarket( + sender=sender, + market_id=market_id, + settlement_price=price_parameter, + expiration_timestamp=expiration_timestamp, + settlement_timestamp=settlement_timestamp, + status=status, ) + # endregion + + # region Insurance module def MsgCreateInsuranceFund( self, sender: str, @@ -941,38 +1817,53 @@ def MsgRequestRedemption( amount=self.coin(amount=amount, denom=share_denom), ) - def MsgVote( - self, - proposal_id: str, - voter: str, - option: int, - ): - return cosmos_gov_tx_pb.MsgVote(proposal_id=proposal_id, voter=voter, option=option) + # endregion - def MsgPrivilegedExecuteContract( - self, sender: str, contract: str, msg: str, **kwargs - ) -> injective_exchange_tx_pb.MsgPrivilegedExecuteContract: - return injective_exchange_tx_pb.MsgPrivilegedExecuteContract( - sender=sender, - contract_address=contract, - data=msg, - funds=kwargs.get("funds") # funds is a string of Coin strings, comma separated, - # e.g. 100000inj,20000000000usdt + # region Oracle module + def MsgRelayProviderPrices(self, sender: str, provider: str, symbols: list, prices: list): + oracle_prices = [] + + for price in prices: + scale_price = Decimal((price) * pow(10, 18)) + price_to_bytes = bytes(str(scale_price), "utf-8") + oracle_prices.append(price_to_bytes) + + return injective_oracle_tx_pb.MsgRelayProviderPrices( + sender=sender, provider=provider, symbols=symbols, prices=oracle_prices ) - def MsgInstantiateContract( - self, sender: str, admin: str, code_id: int, label: str, message: bytes, **kwargs - ) -> wasm_tx_pb.MsgInstantiateContract: - return wasm_tx_pb.MsgInstantiateContract( + def MsgRelayPriceFeedPrice(self, sender: list, base: list, quote: list, price: list): + return injective_oracle_tx_pb.MsgRelayPriceFeedPrice(sender=sender, base=base, quote=quote, price=price) + + # endregion + + # region Peggy module + def MsgSendToEth(self, denom: str, sender: str, eth_dest: str, amount: float, bridge_fee: float): + be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) + be_bridge_fee = self.create_coin_amount(amount=Decimal(str(bridge_fee)), token_name=denom) + + return injective_peggy_tx_pb.MsgSendToEth( sender=sender, - admin=admin, - code_id=code_id, - label=label, - msg=message, - funds=kwargs.get("funds"), # funds is a list of cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin. - # The coins in the list must be sorted in alphabetical order by denoms. + eth_dest=eth_dest, + amount=be_amount, + bridge_fee=be_bridge_fee, + ) + + # endregion + + # region Staking module + def MsgDelegate(self, delegator_address: str, validator_address: str, amount: float): + be_amount = Decimal(str(amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return cosmos_staking_tx_pb.MsgDelegate( + delegator_address=delegator_address, + validator_address=validator_address, + amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), ) + # endregion + + # region Tokenfactory module def msg_create_denom( self, sender: str, @@ -990,14 +1881,14 @@ def msg_create_denom( def msg_mint( self, sender: str, - amount: cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin, + amount: base_coin_pb.Coin, ) -> token_factory_tx_pb.MsgMint: return token_factory_tx_pb.MsgMint(sender=sender, amount=amount) def msg_burn( self, sender: str, - amount: cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin, + amount: base_coin_pb.Coin, ) -> token_factory_tx_pb.MsgBurn: return token_factory_tx_pb.MsgBurn(sender=sender, amount=amount) @@ -1047,14 +1938,108 @@ def msg_change_admin( new_admin=new_admin, ) - def msg_execute_contract_compat(self, sender: str, contract: str, msg: str, funds: str): - return wasmx_tx_pb.MsgExecuteContractCompat( + # endregion + + # region Wasm module + def MsgInstantiateContract( + self, sender: str, admin: str, code_id: int, label: str, message: bytes, **kwargs + ) -> wasm_tx_pb.MsgInstantiateContract: + return wasm_tx_pb.MsgInstantiateContract( + sender=sender, + admin=admin, + code_id=code_id, + label=label, + msg=message, + funds=kwargs.get("funds"), # funds is a list of base_coin_pb.Coin. + # The coins in the list must be sorted in alphabetical order by denoms. + ) + + def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): + return wasm_tx_pb.MsgExecuteContract( sender=sender, contract=contract, - msg=msg, - funds=funds, + msg=bytes(msg, "utf-8"), + funds=kwargs.get("funds") # funds is a list of base_coin_pb.Coin. + # The coins in the list must be sorted in alphabetical order by denoms. + ) + + # endregion + + def MsgGrantTyped( + self, + granter: str, + grantee: str, + msg_type: str, + expire_in: int, + subaccount_id: str, + **kwargs, + ): + auth = None + if msg_type == "CreateSpotLimitOrderAuthz": + auth = injective_authz_pb.CreateSpotLimitOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CreateSpotMarketOrderAuthz": + auth = injective_authz_pb.CreateSpotMarketOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchCreateSpotLimitOrdersAuthz": + auth = injective_authz_pb.BatchCreateSpotLimitOrdersAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CancelSpotOrderAuthz": + auth = injective_authz_pb.CancelSpotOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchCancelSpotOrdersAuthz": + auth = injective_authz_pb.BatchCancelSpotOrdersAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CreateDerivativeLimitOrderAuthz": + auth = injective_authz_pb.CreateDerivativeLimitOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CreateDerivativeMarketOrderAuthz": + auth = injective_authz_pb.CreateDerivativeMarketOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchCreateDerivativeLimitOrdersAuthz": + auth = injective_authz_pb.BatchCreateDerivativeLimitOrdersAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CancelDerivativeOrderAuthz": + auth = injective_authz_pb.CancelDerivativeOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchCancelDerivativeOrdersAuthz": + auth = injective_authz_pb.BatchCancelDerivativeOrdersAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchUpdateOrdersAuthz": + auth = injective_authz_pb.BatchUpdateOrdersAuthz( + subaccount_id=subaccount_id, + spot_markets=kwargs.get("spot_markets"), + derivative_markets=kwargs.get("derivative_markets"), + ) + + any_auth = any_pb2.Any() + any_auth.Pack(auth, type_url_prefix="") + + grant = cosmos_authz_pb.Grant( + authorization=any_auth, + expiration=timestamp_pb2.Timestamp(seconds=(int(time()) + expire_in)), ) + return cosmos_authz_tx_pb.MsgGrant(granter=granter, grantee=grantee, grant=grant) + + def MsgVote( + self, + proposal_id: str, + voter: str, + option: int, + ): + return cosmos_gov_tx_pb.MsgVote(proposal_id=proposal_id, voter=voter, option=option) + def chain_stream_bank_balances_filter( self, accounts: Optional[List[str]] = None ) -> chain_stream_query.BankBalancesFilter: @@ -1144,7 +2129,7 @@ def MsgWithdrawValidatorCommission(self, validator_address: str): def msg_withdraw_validator_commission(self, validator_address: str): return cosmos_distribution_tx_pb.MsgWithdrawValidatorCommission(validator_address=validator_address) - def msg_fund_community_pool(self, amounts: List[cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin], depositor: str): + def msg_fund_community_pool(self, amounts: List[base_coin_pb.Coin], depositor: str): return cosmos_distribution_tx_pb.MsgFundCommunityPool(amount=amounts, depositor=depositor) def msg_update_distribution_params(self, authority: str, community_tax: str, withdraw_address_enabled: bool): @@ -1154,9 +2139,7 @@ def msg_update_distribution_params(self, authority: str, community_tax: str, wit ) return cosmos_distribution_tx_pb.MsgUpdateParams(authority=authority, params=params) - def msg_community_pool_spend( - self, authority: str, recipient: str, amount: List[cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin] - ): + def msg_community_pool_spend(self, authority: str, recipient: str, amount: List[base_coin_pb.Coin]): return cosmos_distribution_tx_pb.MsgCommunityPoolSpend(authority=authority, recipient=recipient, amount=amount) # data field format: [request-msg-header][raw-byte-msg-response] @@ -1369,3 +2352,61 @@ def _initialize_markets_and_tokens_from_files(self): self.spot_markets = spot_markets self.derivative_markets = derivative_markets self.binary_option_markets = dict() + + def _order_mask(self, is_conditional: bool, is_buy: bool, is_market_order: bool) -> int: + order_mask = 0 + + if is_conditional: + order_mask += injective_exchange_pb.OrderMask.CONDITIONAL + else: + order_mask += injective_exchange_pb.OrderMask.REGULAR + + if is_buy: + order_mask += injective_exchange_pb.OrderMask.DIRECTION_BUY_OR_HIGHER + else: + order_mask += injective_exchange_pb.OrderMask.DIRECTION_SELL_OR_LOWER + + if is_market_order: + order_mask += injective_exchange_pb.OrderMask.TYPE_MARKET + else: + order_mask += injective_exchange_pb.OrderMask.TYPE_LIMIT + + if order_mask == 0: + order_mask = 1 + + return order_mask + + def _basic_derivative_order( + self, + market_id: str, + subaccount_id: str, + fee_recipient: str, + chain_price: Decimal, + chain_quantity: Decimal, + chain_margin: Decimal, + order_type: str, + cid: Optional[str] = None, + chain_trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_pb.DerivativeOrder: + formatted_quantity = f"{chain_quantity.normalize():f}" + formatted_price = f"{chain_price.normalize():f}" + formatted_margin = f"{chain_margin.normalize():f}" + + trigger_price = chain_trigger_price or Decimal(0) + formatted_trigger_price = f"{trigger_price.normalize():f}" + + chain_order_type = injective_exchange_pb.OrderType.Value(order_type) + + return injective_exchange_pb.DerivativeOrder( + market_id=market_id, + order_info=injective_exchange_pb.OrderInfo( + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=formatted_price, + quantity=formatted_quantity, + cid=cid, + ), + order_type=chain_order_type, + margin=formatted_margin, + trigger_price=formatted_trigger_price, + ) diff --git a/pyinjective/core/market.py b/pyinjective/core/market.py index 2bd4fe1b..66063130 100644 --- a/pyinjective/core/market.py +++ b/pyinjective/core/market.py @@ -169,6 +169,17 @@ def price_to_chain_format(self, human_readable_value: Decimal, special_denom: Op return extended_chain_formatted_value + def margin_to_chain_format(self, human_readable_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal: + decimals = self.quote_token.decimals if special_denom is None else special_denom.quote + min_quantity_tick_size = ( + self.min_quantity_tick_size if special_denom is None else special_denom.min_quantity_tick_size + ) + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // min_quantity_tick_size) * min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + def calculate_margin_in_chain_format( self, human_readable_quantity: Decimal, diff --git a/tests/core/test_gas_limit_estimator.py b/tests/core/test_gas_limit_estimator.py index 916c47a9..293f5f25 100644 --- a/tests/core/test_gas_limit_estimator.py +++ b/tests/core/test_gas_limit_estimator.py @@ -24,26 +24,24 @@ def test_estimation_for_batch_create_spot_limit_orders(self): spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=5, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("5"), + quantity=Decimal("1"), + order_type="BUY", ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=4, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("4"), + quantity=Decimal("1"), + order_type="BUY", ), ] - message = composer.MsgBatchCreateSpotLimitOrders(sender="sender", orders=orders) + message = composer.msg_batch_create_spot_limit_orders(sender="sender", orders=orders) estimator = GasLimitEstimator.for_message(message=message) expected_order_gas_limit = 50000 @@ -55,23 +53,23 @@ def test_estimation_for_batch_cancel_spot_orders(self): spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", ), ] - message = composer.MsgBatchCancelSpotOrders(sender="sender", data=orders) + message = composer.msg_batch_cancel_spot_orders(sender="sender", orders_data=orders) estimator = GasLimitEstimator.for_message(message=message) expected_order_gas_limit = 50000 @@ -83,28 +81,26 @@ def test_estimation_for_batch_create_derivative_limit_orders(self): market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" composer = Composer(network="testnet") orders = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=3, - quantity=1, - leverage=1, - is_buy=True, - is_po=False, + price=Decimal(3), + quantity=Decimal(1), + margin=Decimal(3), + order_type="BUY", ), - composer.DerivativeOrder( + composer.derivative_order( 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, + price=Decimal(20), + quantity=Decimal(1), + margin=Decimal(20), + order_type="SELL", ), ] - message = composer.MsgBatchCreateDerivativeLimitOrders(sender="sender", orders=orders) + message = composer.msg_batch_create_derivative_limit_orders(sender="sender", orders=orders) estimator = GasLimitEstimator.for_message(message=message) expected_order_gas_limit = 70_000 @@ -116,23 +112,23 @@ def test_estimation_for_batch_cancel_derivative_orders(self): spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", ), ] - message = composer.MsgBatchCancelDerivativeOrders(sender="sender", data=orders) + message = composer.msg_batch_cancel_derivative_orders(sender="sender", orders_data=orders) estimator = GasLimitEstimator.for_message(message=message) expected_order_gas_limit = 60_000 @@ -144,23 +140,21 @@ def test_estimation_for_batch_update_orders_to_create_spot_orders(self): market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.SpotOrder( + composer.spot_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=5, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("5"), + quantity=Decimal("1"), + order_type="BUY", ), - composer.SpotOrder( + composer.spot_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=4, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("4"), + quantity=Decimal("1"), + order_type="BUY", ), ] message = composer.MsgBatchUpdateOrders( @@ -181,25 +175,23 @@ def test_estimation_for_batch_update_orders_to_create_derivative_orders(self): market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" composer = Composer(network="testnet") orders = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=3, - quantity=1, - leverage=1, - is_buy=True, - is_po=False, + price=Decimal(3), + quantity=Decimal(1), + margin=Decimal(3), + order_type="BUY", ), - composer.DerivativeOrder( + composer.derivative_order( 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, + price=Decimal(20), + quantity=Decimal(1), + margin=Decimal(20), + order_type="SELL", ), ] message = composer.MsgBatchUpdateOrders( @@ -238,25 +230,23 @@ def test_estimation_for_batch_update_orders_to_create_binary_orders(self, usdt_t ) composer.binary_option_markets[market.id] = market orders = [ - composer.BinaryOptionsOrder( + composer.binary_options_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=3, - quantity=1, - leverage=1, - is_buy=True, - is_po=False, + price=Decimal(3), + quantity=Decimal(1), + margin=Decimal(3), + order_type="BUY", ), - composer.BinaryOptionsOrder( + composer.binary_options_order( 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, + price=Decimal(20), + quantity=Decimal(1), + margin=Decimal(20), + order_type="SELL", ), ] message = composer.MsgBatchUpdateOrders( @@ -278,17 +268,17 @@ def test_estimation_for_batch_update_orders_to_cancel_spot_orders(self): market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", @@ -312,17 +302,17 @@ def test_estimation_for_batch_update_orders_to_cancel_derivative_orders(self): market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", @@ -346,17 +336,17 @@ def test_estimation_for_batch_update_orders_to_cancel_binary_orders(self): market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", @@ -441,14 +431,13 @@ def test_estimation_for_exec_message(self): market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.SpotOrder( + composer.spot_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=5, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("5"), + quantity=Decimal("1"), + order_type="BUY", ), ] inner_message = composer.MsgBatchUpdateOrders( @@ -510,15 +499,14 @@ def test_estimation_for_governance_message(self): def test_estimation_for_generic_exchange_message(self): composer = Composer(network="testnet") - message = composer.MsgCreateSpotLimitOrder( + message = composer.msg_create_spot_limit_order( 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, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", ) estimator = GasLimitEstimator.for_message(message=message) diff --git a/tests/core/test_market.py b/tests/core/test_market.py index ede8aea5..48c2f5e5 100644 --- a/tests/core/test_market.py +++ b/tests/core/test_market.py @@ -248,6 +248,42 @@ def test_convert_price_to_chain_format_without_fixed_denom(self, first_match_bet assert quantized_chain_format_value == chain_value + def test_convert_margin_to_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=4, + min_quantity_tick_size=100, + min_price_tick_size=10000, + ) + + chain_value = first_match_bet_market.margin_to_chain_format( + human_readable_value=original_quantity, + special_denom=fixed_denom, + ) + price_decimals = fixed_denom.quote + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = (expected_value // Decimal(str(fixed_denom.min_quantity_tick_size))) * Decimal( + str(fixed_denom.min_quantity_tick_size) + ) + quantized_chain_format_value = quantized_value * Decimal("1e18") + + assert quantized_chain_format_value == chain_value + + def test_convert_margin_to_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + + chain_value = first_match_bet_market.margin_to_chain_format(human_readable_value=original_quantity) + price_decimals = first_match_bet_market.quote_token.decimals + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ( + expected_value // first_match_bet_market.min_quantity_tick_size + ) * first_match_bet_market.min_quantity_tick_size + quantized_chain_format_value = quantized_value * Decimal("1e18") + + assert quantized_chain_format_value == chain_value + def test_calculate_margin_for_buy_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): original_quantity = Decimal("123.456789") original_price = Decimal("0.6789") diff --git a/tests/core/test_message_based_transaction_fee_calculator.py b/tests/core/test_message_based_transaction_fee_calculator.py index 23e263c9..b1d774e0 100644 --- a/tests/core/test_message_based_transaction_fee_calculator.py +++ b/tests/core/test_message_based_transaction_fee_calculator.py @@ -117,15 +117,14 @@ async def test_gas_fee_for_exchange_message(self): gas_price=5_000_000, ) - message = composer.MsgCreateSpotLimitOrder( + message = composer.msg_create_spot_limit_order( 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, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", ) transaction = Transaction() transaction.with_messages(message) @@ -148,15 +147,14 @@ async def test_gas_fee_for_msg_exec_message(self): gas_price=5_000_000, ) - inner_message = composer.MsgCreateSpotLimitOrder( + inner_message = composer.msg_create_spot_limit_order( 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, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", ) message = composer.MsgExec(grantee="grantee", msgs=[inner_message]) transaction = Transaction() @@ -184,15 +182,14 @@ async def test_gas_fee_for_two_messages_in_one_transaction(self): gas_price=5_000_000, ) - inner_message = composer.MsgCreateSpotLimitOrder( + inner_message = composer.msg_create_spot_limit_order( 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, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", ) message = composer.MsgExec(grantee="grantee", msgs=[inner_message]) diff --git a/tests/test_composer.py b/tests/test_composer.py index a0cca2ab..2dcbd056 100644 --- a/tests/test_composer.py +++ b/tests/test_composer.py @@ -2,12 +2,11 @@ from decimal import Decimal import pytest +from google.protobuf import json_format from pyinjective.composer import Composer -from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from pyinjective.constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS from pyinjective.core.network import Network -from pyinjective.proto.injective.exchange.v1beta1 import exchange_pb2 -from pyinjective.utils.denom import Denom from tests.model_fixtures.markets_fixtures import btc_usdt_perp_market # noqa: F401 from tests.model_fixtures.markets_fixtures import first_match_bet_market # noqa: F401 from tests.model_fixtures.markets_fixtures import inj_token # noqa: F401 @@ -57,211 +56,6 @@ def test_composer_initialization_from_ini_files(self): assert 6 == inj_usdt_spot_market.quote_token.decimals assert 6 == inj_usdt_perp_market.quote_token.decimals - def test_buy_spot_order_creation(self, basic_composer: Composer, inj_usdt_spot_market: SpotMarket): - fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - price = 6.869 - quantity = 1587 - order = basic_composer.SpotOrder( - market_id=inj_usdt_spot_market.id, - subaccount_id="1", - fee_recipient=fee_recipient, - price=price, - quantity=quantity, - is_buy=True, - ) - - price_decimals = inj_usdt_spot_market.quote_token.decimals - inj_usdt_spot_market.base_token.decimals - chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") - expected_price = ( - (chain_format_price // inj_usdt_spot_market.min_price_tick_size) - * inj_usdt_spot_market.min_price_tick_size - * Decimal("1e18") - ) - chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{inj_usdt_spot_market.base_token.decimals}") - expected_quantity = ( - (chain_format_quantity // inj_usdt_spot_market.min_quantity_tick_size) - * inj_usdt_spot_market.min_quantity_tick_size - * Decimal("1e18") - ) - - assert order.market_id == inj_usdt_spot_market.id - assert order.order_info.subaccount_id == "1" - assert order.order_info.fee_recipient == fee_recipient - assert order.order_info.price == str(int(expected_price)) - assert order.order_info.quantity == str(int(expected_quantity)) - assert order.order_type == exchange_pb2.OrderType.BUY - assert order.trigger_price == "0" - - def test_buy_derivative_order_creation(self, basic_composer: Composer, btc_usdt_perp_market: DerivativeMarket): - fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - price = 6.869 - quantity = 1587 - leverage = 2 - order = basic_composer.DerivativeOrder( - market_id=btc_usdt_perp_market.id, - subaccount_id="1", - fee_recipient=fee_recipient, - price=price, - quantity=quantity, - is_buy=True, - leverage=leverage, - ) - - price_decimals = btc_usdt_perp_market.quote_token.decimals - chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") - expected_price = ( - (chain_format_price // btc_usdt_perp_market.min_price_tick_size) - * btc_usdt_perp_market.min_price_tick_size - * Decimal("1e18") - ) - chain_format_quantity = Decimal(str(quantity)) - expected_quantity = ( - (chain_format_quantity // btc_usdt_perp_market.min_quantity_tick_size) - * btc_usdt_perp_market.min_quantity_tick_size - * Decimal("1e18") - ) - chain_format_margin = (chain_format_quantity * chain_format_price) / Decimal(leverage) - expected_margin = ( - (chain_format_margin // btc_usdt_perp_market.min_quantity_tick_size) - * btc_usdt_perp_market.min_quantity_tick_size - * Decimal("1e18") - ) - - assert order.market_id == btc_usdt_perp_market.id - assert order.order_info.subaccount_id == "1" - assert order.order_info.fee_recipient == fee_recipient - assert order.order_info.price == str(int(expected_price)) - assert order.order_info.quantity == str(int(expected_quantity)) - assert order.order_type == exchange_pb2.OrderType.BUY - assert order.margin == str(int(expected_margin)) - assert order.trigger_price == "0" - - def test_increase_position_margin(self, basic_composer: Composer, btc_usdt_perp_market: DerivativeMarket): - sender = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - amount = 1587.789 - message = basic_composer.MsgIncreasePositionMargin( - sender=sender, - source_subaccount_id="1", - destination_subaccount_id="2", - market_id=btc_usdt_perp_market.id, - amount=amount, - ) - - price_decimals = btc_usdt_perp_market.quote_token.decimals - chain_format_margin = Decimal(str(amount)) * Decimal(f"1e{price_decimals}") - expected_margin = ( - (chain_format_margin // btc_usdt_perp_market.min_quantity_tick_size) - * btc_usdt_perp_market.min_quantity_tick_size - * Decimal("1e18") - ) - - assert message.market_id == btc_usdt_perp_market.id - assert message.sender == sender - assert message.source_subaccount_id == "1" - assert message.destination_subaccount_id == "2" - assert message.amount == str(int(expected_margin)) - - def test_buy_binary_option_order_creation_with_fixed_denom( - self, basic_composer: Composer, first_match_bet_market: BinaryOptionMarket - ): - fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - price = 6.869 - quantity = 1587 - fixed_denom = Denom( - description="Fixed denom", - base=2, - quote=6, - min_price_tick_size=1000, - min_quantity_tick_size=10000, - ) - - order = basic_composer.BinaryOptionsOrder( - market_id=first_match_bet_market.id, - subaccount_id="1", - fee_recipient=fee_recipient, - price=price, - quantity=quantity, - is_buy=True, - denom=fixed_denom, - ) - - price_decimals = fixed_denom.quote - chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") - expected_price = ( - (chain_format_price // Decimal(str(fixed_denom.min_price_tick_size))) - * Decimal(str(fixed_denom.min_price_tick_size)) - * Decimal("1e18") - ) - quantity_decimals = fixed_denom.base - chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{quantity_decimals}") - expected_quantity = ( - (chain_format_quantity // Decimal(str(fixed_denom.min_quantity_tick_size))) - * Decimal(str(fixed_denom.min_quantity_tick_size)) - * Decimal("1e18") - ) - chain_format_margin = chain_format_quantity * chain_format_price - expected_margin = ( - (chain_format_margin // Decimal(str(fixed_denom.min_quantity_tick_size))) - * Decimal(str(fixed_denom.min_quantity_tick_size)) - * Decimal("1e18") - ) - - assert order.market_id == first_match_bet_market.id - assert order.order_info.subaccount_id == "1" - assert order.order_info.fee_recipient == fee_recipient - assert order.order_info.price == str(int(expected_price)) - assert order.order_info.quantity == str(int(expected_quantity)) - assert order.order_type == exchange_pb2.OrderType.BUY - assert order.margin == str(int(expected_margin)) - assert order.trigger_price == "0" - - def test_buy_binary_option_order_creation_without_fixed_denom( - self, - basic_composer: Composer, - first_match_bet_market: BinaryOptionMarket, - ): - fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - price = 6.869 - quantity = 1587 - - order = basic_composer.BinaryOptionsOrder( - market_id=first_match_bet_market.id, - subaccount_id="1", - fee_recipient=fee_recipient, - price=price, - quantity=quantity, - is_buy=True, - ) - - price_decimals = first_match_bet_market.quote_token.decimals - chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") - expected_price = ( - (chain_format_price // first_match_bet_market.min_price_tick_size) - * first_match_bet_market.min_price_tick_size - * Decimal("1e18") - ) - chain_format_quantity = Decimal(str(quantity)) - expected_quantity = ( - (chain_format_quantity // first_match_bet_market.min_quantity_tick_size) - * first_match_bet_market.min_quantity_tick_size - * Decimal("1e18") - ) - chain_format_margin = chain_format_quantity * chain_format_price - expected_margin = ( - (chain_format_margin // first_match_bet_market.min_quantity_tick_size) - * first_match_bet_market.min_quantity_tick_size - * Decimal("1e18") - ) - - assert order.market_id == first_match_bet_market.id - assert order.order_info.subaccount_id == "1" - assert order.order_info.fee_recipient == fee_recipient - assert order.order_info.price == str(int(expected_price)) - assert order.order_info.quantity == str(int(expected_quantity)) - assert order.order_type == exchange_pb2.OrderType.BUY - assert order.margin == str(int(expected_margin)) - assert order.trigger_price == "0" - def test_msg_create_denom(self, basic_composer: Composer): sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" subdenom = "inj-test" @@ -380,3 +174,1259 @@ def test_msg_execute_contract_compat(self, basic_composer): assert message.contract == contract assert message.msg == msg assert message.funds == funds + + def test_msg_deposit(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + amount = Decimal(100) + denom = "INJ" + + token = basic_composer.tokens[denom] + + expected_amount = token.chain_formatted_value(human_readable_value=Decimal(amount)) + + message = basic_composer.msg_deposit( + sender=sender, + subaccount_id=subaccount_id, + amount=amount, + denom=denom, + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "amount": { + "amount": f"{expected_amount.normalize():f}", + "denom": token.denom, + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_withdraw(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + amount = Decimal(100) + denom = "INJ" + + token = basic_composer.tokens[denom] + + expected_amount = token.chain_formatted_value(human_readable_value=Decimal(amount)) + + message = basic_composer.msg_withdraw( + sender=sender, + subaccount_id=subaccount_id, + amount=amount, + denom=denom, + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "amount": { + "amount": f"{expected_amount.normalize():f}", + "denom": token.denom, + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_instant_spot_market_launch(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + ticker = "INJ/USDT" + base_denom = "INJ" + quote_denom = "USDT" + min_price_tick_size = Decimal("0.01") + min_quantity_tick_size = Decimal("1") + + base_token = basic_composer.tokens[base_denom] + quote_token = basic_composer.tokens[quote_denom] + + expected_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals - base_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + expected_min_quantity_tick_size = min_quantity_tick_size * Decimal( + f"1e{base_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + + message = basic_composer.msg_instant_spot_market_launch( + sender=sender, + ticker=ticker, + base_denom=base_denom, + quote_denom=quote_denom, + min_price_tick_size=min_price_tick_size, + min_quantity_tick_size=min_quantity_tick_size, + ) + + expected_message = { + "sender": sender, + "ticker": ticker, + "baseDenom": base_token.denom, + "quoteDenom": quote_token.denom, + "minPriceTickSize": f"{expected_min_price_tick_size.normalize():f}", + "minQuantityTickSize": f"{expected_min_quantity_tick_size.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_instant_perpetual_market_launch(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + ticker = "BTC/INJ PERP" + quote_denom = "INJ" + oracle_base = "BTC" + oracle_quote = "INJ" + oracle_scale_factor = 6 + oracle_type = "Band" + min_price_tick_size = Decimal("0.01") + min_quantity_tick_size = Decimal("1") + maker_fee_rate = Decimal("0.001") + taker_fee_rate = Decimal("-0.002") + initial_margin_ratio = Decimal("0.05") + maintenance_margin_ratio = Decimal("0.03") + + quote_token = basic_composer.tokens[quote_denom] + + expected_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + expected_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_initial_margin_ratio = initial_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maintenance_margin_ratio = maintenance_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + message = basic_composer.msg_instant_perpetual_market_launch( + sender=sender, + ticker=ticker, + quote_denom=quote_denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_scale_factor=oracle_scale_factor, + oracle_type=oracle_type, + maker_fee_rate=maker_fee_rate, + taker_fee_rate=taker_fee_rate, + initial_margin_ratio=initial_margin_ratio, + maintenance_margin_ratio=maintenance_margin_ratio, + min_price_tick_size=min_price_tick_size, + min_quantity_tick_size=min_quantity_tick_size, + ) + + expected_message = { + "sender": sender, + "ticker": ticker, + "quoteDenom": quote_token.denom, + "oracleBase": oracle_base, + "oracleQuote": oracle_quote, + "oracleScaleFactor": oracle_scale_factor, + "oracleType": oracle_type, + "makerFeeRate": f"{expected_maker_fee_rate.normalize():f}", + "takerFeeRate": f"{expected_taker_fee_rate.normalize():f}", + "initialMarginRatio": f"{expected_initial_margin_ratio.normalize():f}", + "maintenanceMarginRatio": f"{expected_maintenance_margin_ratio.normalize():f}", + "minPriceTickSize": f"{expected_min_price_tick_size.normalize():f}", + "minQuantityTickSize": f"{expected_min_quantity_tick_size.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_instant_expiry_futures_market_launch(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + ticker = "BTC/INJ PERP" + quote_denom = "INJ" + oracle_base = "BTC" + oracle_quote = "INJ" + oracle_scale_factor = 6 + oracle_type = "Band" + expiry = 1630000000 + min_price_tick_size = Decimal("0.01") + min_quantity_tick_size = Decimal("1") + maker_fee_rate = Decimal("0.001") + taker_fee_rate = Decimal("-0.002") + initial_margin_ratio = Decimal("0.05") + maintenance_margin_ratio = Decimal("0.03") + + quote_token = basic_composer.tokens[quote_denom] + + expected_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + expected_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_initial_margin_ratio = initial_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maintenance_margin_ratio = maintenance_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + message = basic_composer.msg_instant_expiry_futures_market_launch( + sender=sender, + ticker=ticker, + quote_denom=quote_denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_scale_factor=oracle_scale_factor, + oracle_type=oracle_type, + expiry=expiry, + maker_fee_rate=maker_fee_rate, + taker_fee_rate=taker_fee_rate, + initial_margin_ratio=initial_margin_ratio, + maintenance_margin_ratio=maintenance_margin_ratio, + min_price_tick_size=min_price_tick_size, + min_quantity_tick_size=min_quantity_tick_size, + ) + + expected_message = { + "sender": sender, + "ticker": ticker, + "quoteDenom": quote_token.denom, + "oracleBase": oracle_base, + "oracleQuote": oracle_quote, + "oracleType": oracle_type, + "oracleScaleFactor": oracle_scale_factor, + "expiry": str(expiry), + "makerFeeRate": f"{expected_maker_fee_rate.normalize():f}", + "takerFeeRate": f"{expected_taker_fee_rate.normalize():f}", + "initialMarginRatio": f"{expected_initial_margin_ratio.normalize():f}", + "maintenanceMarginRatio": f"{expected_maintenance_margin_ratio.normalize():f}", + "minPriceTickSize": f"{expected_min_price_tick_size.normalize():f}", + "minQuantityTickSize": f"{expected_min_quantity_tick_size.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_spot_order(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + order = basic_composer.spot_order( + market_id=spot_market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = spot_market.price_to_chain_format(human_readable_value=price) + expected_quantity = spot_market.quantity_to_chain_format(human_readable_value=quantity) + expected_trigger_price = spot_market.price_to_chain_format(human_readable_value=trigger_price) + + expected_order = { + "marketId": spot_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=order, + including_default_value_fields=True, + ) + assert dict_message == expected_order + + def test_derivative_order(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + order = basic_composer.derivative_order( + market_id=derivative_market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = derivative_market.price_to_chain_format(human_readable_value=price) + expected_quantity = derivative_market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = derivative_market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = derivative_market.price_to_chain_format(human_readable_value=trigger_price) + + expected_order = { + "marketId": derivative_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "orderType": order_type, + "margin": f"{expected_margin.normalize():f}", + "triggerPrice": f"{expected_trigger_price.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=order, + including_default_value_fields=True, + ) + assert dict_message == expected_order + + def test_msg_create_spot_limit_order(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_spot_limit_order( + market_id=spot_market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = spot_market.price_to_chain_format(human_readable_value=price) + expected_quantity = spot_market.quantity_to_chain_format(human_readable_value=quantity) + expected_trigger_price = spot_market.price_to_chain_format(human_readable_value=trigger_price) + + assert "injective.exchange.v1beta1.MsgCreateSpotLimitOrder" == message.DESCRIPTOR.full_name + expected_message = { + "sender": sender, + "order": { + "marketId": spot_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_create_spot_limit_orders(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + order = basic_composer.spot_order( + market_id=spot_market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + message = basic_composer.msg_batch_create_spot_limit_orders( + sender=sender, + orders=[order], + ) + + expected_message = { + "sender": sender, + "orders": [json_format.MessageToDict(message=order, including_default_value_fields=True)], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_spot_market_order(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_spot_market_order( + market_id=spot_market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = spot_market.price_to_chain_format(human_readable_value=price) + expected_quantity = spot_market.quantity_to_chain_format(human_readable_value=quantity) + expected_trigger_price = spot_market.price_to_chain_format(human_readable_value=trigger_price) + + assert "injective.exchange.v1beta1.MsgCreateSpotMarketOrder" == message.DESCRIPTOR.full_name + expected_message = { + "sender": sender, + "order": { + "marketId": spot_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_cancel_spot_order(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + order_hash = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + cid = "test_cid" + + message = basic_composer.msg_cancel_spot_order( + market_id=spot_market.id, + sender=sender, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + ) + + expected_message = { + "sender": sender, + "marketId": spot_market.id, + "subaccountId": subaccount_id, + "orderHash": order_hash, + "cid": cid, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_cancel_spot_orders(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + + order_data = basic_composer.order_data( + market_id=spot_market.id, + subaccount_id=subaccount_id, + order_hash="0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000", + ) + + message = basic_composer.msg_batch_cancel_spot_orders( + sender=sender, + orders_data=[order_data], + ) + + assert "injective.exchange.v1beta1.MsgBatchCancelSpotOrders" == message.DESCRIPTOR.full_name + expected_message = { + "sender": sender, + "data": [json_format.MessageToDict(message=order_data, including_default_value_fields=True)], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_update_orders(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + derivative_market = list(basic_composer.derivative_markets.values())[0] + binary_options_market = list(basic_composer.binary_option_markets.values())[0] + + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + spot_market_id = spot_market.id + derivative_market_id = derivative_market.id + binary_options_market_id = binary_options_market.id + spot_order_to_cancel = basic_composer.order_data( + market_id=spot_market_id, + subaccount_id=subaccount_id, + order_hash="0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000", + ) + derivative_order_to_cancel = basic_composer.order_data( + market_id=derivative_market_id, + subaccount_id=subaccount_id, + order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", + ) + binary_options_order_to_cancel = basic_composer.order_data( + market_id=binary_options_market_id, + subaccount_id=subaccount_id, + order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", + ) + spot_order_to_create = basic_composer.spot_order( + market_id=spot_market_id, + subaccount_id=subaccount_id, + fee_recipient="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + price=Decimal("36.1"), + quantity=Decimal("100"), + order_type="BUY", + cid="test_cid", + trigger_price=Decimal("43.5"), + ) + derivative_order_to_create = basic_composer.derivative_order( + market_id=derivative_market_id, + subaccount_id=subaccount_id, + fee_recipient="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + price=Decimal("36.1"), + quantity=Decimal("100"), + margin=Decimal("36.1") * Decimal("100"), + order_type="BUY", + ) + binary_options_order_to_create = basic_composer.binary_options_order( + market_id=binary_options_market_id, + subaccount_id=subaccount_id, + fee_recipient="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + price=Decimal("36.1"), + quantity=Decimal("100"), + margin=Decimal("36.1") * Decimal("100"), + order_type="BUY", + ) + + message = basic_composer.msg_batch_update_orders( + sender=sender, + subaccount_id=subaccount_id, + spot_market_ids_to_cancel_all=[spot_market_id], + derivative_market_ids_to_cancel_all=[derivative_market_id], + spot_orders_to_cancel=[spot_order_to_cancel], + derivative_orders_to_cancel=[derivative_order_to_cancel], + spot_orders_to_create=[spot_order_to_create], + derivative_orders_to_create=[derivative_order_to_create], + binary_options_orders_to_cancel=[binary_options_order_to_cancel], + binary_options_market_ids_to_cancel_all=[binary_options_market_id], + binary_options_orders_to_create=[binary_options_order_to_create], + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "spotMarketIdsToCancelAll": [spot_market_id], + "derivativeMarketIdsToCancelAll": [derivative_market_id], + "spotOrdersToCancel": [ + json_format.MessageToDict(message=spot_order_to_cancel, including_default_value_fields=True) + ], + "derivativeOrdersToCancel": [ + json_format.MessageToDict(message=derivative_order_to_cancel, including_default_value_fields=True) + ], + "spotOrdersToCreate": [ + json_format.MessageToDict(message=spot_order_to_create, including_default_value_fields=True) + ], + "derivativeOrdersToCreate": [ + json_format.MessageToDict(message=derivative_order_to_create, including_default_value_fields=True) + ], + "binaryOptionsOrdersToCancel": [ + json_format.MessageToDict(message=binary_options_order_to_cancel, including_default_value_fields=True) + ], + "binaryOptionsMarketIdsToCancelAll": [binary_options_market_id], + "binaryOptionsOrdersToCreate": [ + json_format.MessageToDict(message=binary_options_order_to_create, including_default_value_fields=True) + ], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_privileged_execute_contract(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + contract_address = "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7" + data = "test_data" + funds = "100inj,420peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7" + + message = basic_composer.msg_privileged_execute_contract( + sender=sender, + contract_address=contract_address, + data=data, + funds=funds, + ) + + expected_message = { + "sender": sender, + "funds": funds, + "contractAddress": contract_address, + "data": data, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_derivative_limit_order(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_derivative_limit_order( + market_id=derivative_market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = derivative_market.price_to_chain_format(human_readable_value=price) + expected_quantity = derivative_market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = derivative_market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = derivative_market.price_to_chain_format(human_readable_value=trigger_price) + + expected_message = { + "sender": sender, + "order": { + "marketId": derivative_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "margin": f"{expected_margin.normalize():f}", + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_create_derivative_limit_orders(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + order = basic_composer.derivative_order( + market_id=derivative_market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=price * quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + message = basic_composer.msg_batch_create_derivative_limit_orders( + sender=sender, + orders=[order], + ) + + expected_message = { + "sender": sender, + "orders": [json_format.MessageToDict(message=order, including_default_value_fields=True)], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_derivative_market_order(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_derivative_market_order( + market_id=derivative_market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = derivative_market.price_to_chain_format(human_readable_value=price) + expected_quantity = derivative_market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = derivative_market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = derivative_market.price_to_chain_format(human_readable_value=trigger_price) + + expected_message = { + "sender": sender, + "order": { + "marketId": derivative_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "margin": f"{expected_margin.normalize():f}", + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_cancel_derivative_order(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + order_hash = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + cid = "test_cid" + is_conditional = False + is_buy = True + is_market_order = False + + expected_order_mask = basic_composer._order_mask( + is_conditional=is_conditional, + is_buy=is_buy, + is_market_order=is_market_order, + ) + + message = basic_composer.msg_cancel_derivative_order( + market_id=derivative_market.id, + sender=sender, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + is_conditional=is_conditional, + is_buy=is_buy, + is_market_order=is_market_order, + ) + + expected_message = { + "sender": sender, + "marketId": derivative_market.id, + "subaccountId": subaccount_id, + "orderHash": order_hash, + "orderMask": expected_order_mask, + "cid": cid, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_cancel_derivative_orders(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + + order_data = basic_composer.order_data( + market_id=derivative_market.id, + subaccount_id=subaccount_id, + order_hash="0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000", + ) + + message = basic_composer.msg_batch_cancel_derivative_orders( + sender=sender, + orders_data=[order_data], + ) + + expected_message = { + "sender": sender, + "data": [json_format.MessageToDict(message=order_data, including_default_value_fields=True)], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_instant_binary_options_market_launch(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + ticker = "B2500/INJ" + oracle_symbol = "B2500_1/INJ" + oracle_provider = "Injective" + oracle_scale_factor = 6 + oracle_type = "Band" + quote_denom = "INJ" + min_price_tick_size = Decimal("0.01") + min_quantity_tick_size = Decimal("1") + maker_fee_rate = Decimal("0.001") + taker_fee_rate = Decimal("-0.002") + expiration_timestamp = 1630000000 + settlement_timestamp = 1660000000 + admin = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + + quote_token = basic_composer.tokens[quote_denom] + + expected_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + expected_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + message = basic_composer.msg_instant_binary_options_market_launch( + sender=sender, + ticker=ticker, + oracle_symbol=oracle_symbol, + oracle_provider=oracle_provider, + oracle_type=oracle_type, + oracle_scale_factor=oracle_scale_factor, + maker_fee_rate=maker_fee_rate, + taker_fee_rate=taker_fee_rate, + expiration_timestamp=expiration_timestamp, + settlement_timestamp=settlement_timestamp, + admin=admin, + quote_denom=quote_denom, + min_price_tick_size=min_price_tick_size, + min_quantity_tick_size=min_quantity_tick_size, + ) + + expected_message = { + "sender": sender, + "ticker": ticker, + "oracleSymbol": oracle_symbol, + "oracleProvider": oracle_provider, + "oracleType": oracle_type, + "oracleScaleFactor": oracle_scale_factor, + "makerFeeRate": f"{expected_maker_fee_rate.normalize():f}", + "takerFeeRate": f"{expected_taker_fee_rate.normalize():f}", + "expirationTimestamp": str(expiration_timestamp), + "settlementTimestamp": str(settlement_timestamp), + "admin": admin, + "quoteDenom": quote_token.denom, + "minPriceTickSize": f"{expected_min_price_tick_size.normalize():f}", + "minQuantityTickSize": f"{expected_min_quantity_tick_size.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_binary_options_limit_order(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_binary_options_limit_order( + market_id=market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = market.price_to_chain_format(human_readable_value=price) + expected_quantity = market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = market.price_to_chain_format(human_readable_value=trigger_price) + + expected_message = { + "sender": sender, + "order": { + "marketId": market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "margin": f"{expected_margin.normalize():f}", + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_binary_options_market_order(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_binary_options_market_order( + market_id=market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = market.price_to_chain_format(human_readable_value=price) + expected_quantity = market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = market.price_to_chain_format(human_readable_value=trigger_price) + + expected_message = { + "sender": sender, + "order": { + "marketId": market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "margin": f"{expected_margin.normalize():f}", + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_cancel_derivative_order(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + order_hash = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + cid = "test_cid" + is_conditional = False + is_buy = True + is_market_order = False + + expected_order_mask = basic_composer._order_mask( + is_conditional=is_conditional, + is_buy=is_buy, + is_market_order=is_market_order, + ) + + message = basic_composer.msg_cancel_derivative_order( + market_id=market.id, + sender=sender, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + is_conditional=is_conditional, + is_buy=is_buy, + is_market_order=is_market_order, + ) + + expected_message = { + "sender": sender, + "marketId": market.id, + "subaccountId": subaccount_id, + "orderHash": order_hash, + "orderMask": expected_order_mask, + "cid": cid, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_subaccount_transfer(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + source_subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + destination_subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000002" + amount = Decimal(100) + denom = "INJ" + + token = basic_composer.tokens[denom] + + expected_amount = token.chain_formatted_value(human_readable_value=amount) + + message = basic_composer.msg_subaccount_transfer( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + amount=amount, + denom=denom, + ) + + expected_message = { + "sender": sender, + "sourceSubaccountId": source_subaccount_id, + "destinationSubaccountId": destination_subaccount_id, + "amount": { + "amount": f"{expected_amount.normalize():f}", + "denom": token.denom, + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_external_transfer(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + source_subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + destination_subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000" + amount = Decimal(100) + denom = "INJ" + + token = basic_composer.tokens[denom] + + expected_amount = token.chain_formatted_value(human_readable_value=amount) + + message = basic_composer.msg_subaccount_transfer( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + amount=amount, + denom=denom, + ) + + expected_message = { + "sender": sender, + "sourceSubaccountId": source_subaccount_id, + "destinationSubaccountId": destination_subaccount_id, + "amount": { + "amount": f"{expected_amount.normalize():f}", + "denom": token.denom, + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_liquidate_position(self, basic_composer): + market = list(basic_composer.derivative_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + order = basic_composer.derivative_order( + market_id=market.id, + subaccount_id=subaccount_id, + fee_recipient="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + price=Decimal("36.1"), + quantity=Decimal("100"), + margin=Decimal("36.1") * Decimal("100"), + order_type="BUY", + ) + + message = basic_composer.msg_liquidate_position( + sender=sender, + subaccount_id=subaccount_id, + market_id=market.id, + order=order, + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "marketId": market.id, + "order": json_format.MessageToDict(message=order, including_default_value_fields=True), + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_emergency_settle_market(self, basic_composer): + market = list(basic_composer.derivative_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + + message = basic_composer.msg_emergency_settle_market( + sender=sender, + subaccount_id=subaccount_id, + market_id=market.id, + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "marketId": market.id, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_external_transfer(self, basic_composer): + market = list(basic_composer.derivative_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + source_subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + destination_subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000" + amount = Decimal(100) + + expected_amount = market.margin_to_chain_format(human_readable_value=amount) + + message = basic_composer.msg_increase_position_margin( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + market_id=market.id, + amount=amount, + ) + + expected_message = { + "sender": sender, + "sourceSubaccountId": source_subaccount_id, + "destinationSubaccountId": destination_subaccount_id, + "marketId": market.id, + "amount": f"{expected_amount.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_rewards_opt_out(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + + message = basic_composer.msg_rewards_opt_out( + sender=sender, + ) + + expected_message = { + "sender": sender, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_admin_update_binary_options_market(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + status = "Paused" + settlement_price = Decimal("100.5") + expiration_timestamp = 1630000000 + settlement_timestamp = 1660000000 + + expected_settlement_price = market.price_to_chain_format(human_readable_value=settlement_price) + + message = basic_composer.msg_admin_update_binary_options_market( + sender=sender, + market_id=market.id, + status=status, + settlement_price=settlement_price, + expiration_timestamp=expiration_timestamp, + settlement_timestamp=settlement_timestamp, + ) + + expected_message = { + "sender": sender, + "marketId": market.id, + "settlementPrice": f"{expected_settlement_price.normalize():f}", + "expirationTimestamp": str(expiration_timestamp), + "settlementTimestamp": str(settlement_timestamp), + "status": status, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message diff --git a/tests/test_composer_deprecation_warnings.py b/tests/test_composer_deprecation_warnings.py new file mode 100644 index 00000000..20a86779 --- /dev/null +++ b/tests/test_composer_deprecation_warnings.py @@ -0,0 +1,522 @@ +import warnings +from decimal import Decimal + +import pytest + +from pyinjective.composer import Composer +from pyinjective.core.network import Network +from tests.model_fixtures.markets_fixtures import btc_usdt_perp_market # noqa: F401 +from tests.model_fixtures.markets_fixtures import first_match_bet_market # noqa: F401 +from tests.model_fixtures.markets_fixtures import inj_token # noqa: F401 +from tests.model_fixtures.markets_fixtures import inj_usdt_spot_market # noqa: F401 +from tests.model_fixtures.markets_fixtures import usdt_perp_token # noqa: F401 +from tests.model_fixtures.markets_fixtures import usdt_token # noqa: F401 + + +class TestComposerDeprecationWarnings: + @pytest.fixture + def basic_composer(self, inj_usdt_spot_market, btc_usdt_perp_market, first_match_bet_market): + composer = Composer( + network=Network.devnet().string(), + spot_markets={inj_usdt_spot_market.id: inj_usdt_spot_market}, + derivative_markets={btc_usdt_perp_market.id: btc_usdt_perp_market}, + binary_option_markets={first_match_bet_market.id: first_match_bet_market}, + tokens={ + inj_usdt_spot_market.base_token.symbol: inj_usdt_spot_market.base_token, + inj_usdt_spot_market.quote_token.symbol: inj_usdt_spot_market.quote_token, + btc_usdt_perp_market.quote_token.symbol: btc_usdt_perp_market.quote_token, + }, + ) + + return composer + + def test_msg_deposit_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgDeposit(sender="sender", subaccount_id="subaccount id", amount=1, denom="INJ") + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_deposit instead" + + def test_msg_withdraw_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgWithdraw(sender="sender", subaccount_id="subaccount id", amount=1, denom="USDT") + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_withdraw instead" + + def teste_order_data_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.OrderData( + market_id="market id", + subaccount_id="subaccount id", + order_hash="order hash", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use order_data instead" + + def test_spot_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.SpotOrder( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + is_buy=True, + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use spot_order instead" + + def test_derivative_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.DerivativeOrder( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + is_buy=True, + cid="cid", + leverage=1, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use derivative_order instead" + + def test_msg_create_spot_limit_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCreateSpotLimitOrder( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_create_spot_limit_order instead" + ) + + def test_msg_batch_create_spot_limit_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + order = composer.spot_order( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=Decimal(1), + quantity=Decimal(1), + order_type="BUY", + ) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchCreateSpotLimitOrders( + sender="sender", + orders=[order], + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_batch_create_spot_limit_orders instead" + ) + + def test_msg_create_spot_market_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCreateSpotMarketOrder( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + is_buy=True, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_spot_market_order instead" + ) + + def test_msg_cancel_spot_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCancelSpotOrder( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + sender="sender", + subaccount_id="subaccount id", + order_hash="order hash", + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_cancel_spot_order instead" + + def test_msg_batch_cancel_spot_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + orders = [ + composer.order_data( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + subaccount_id="subaccount_id", + order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", + ), + ] + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchCancelSpotOrders(sender="sender", data=orders) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_batch_cancel_spot_orders instead" + ) + + def test_msg_batch_update_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchUpdateOrders(sender="sender") + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_batch_update_orders instead" + + def test_msg_privileged_execute_contract_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgPrivilegedExecuteContract( + sender="sender", + contract="contract", + msg="msg", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_privileged_execute_contract instead" + ) + + def test_msg_create_derivative_limit_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCreateDerivativeLimitOrder( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + leverage=1, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_derivative_limit_order instead" + ) + + def test_msg_batch_create_derivative_limit_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + order = composer.derivative_order( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=Decimal(1), + quantity=Decimal(1), + margin=Decimal(1), + order_type="BUY", + ) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchCreateDerivativeLimitOrders( + sender="sender", + orders=[order], + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_batch_create_derivative_limit_orders instead" + ) + + def test_msg_create_derivative_market_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCreateDerivativeMarketOrder( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + leverage=1, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_derivative_market_order instead" + ) + + def test_msg_cancel_derivative_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCancelDerivativeOrder( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + sender="sender", + subaccount_id="subaccount id", + order_hash="order hash", + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_cancel_derivative_order instead" + ) + + def test_msg_batch_cancel_derivative_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + orders = [ + composer.order_data( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + subaccount_id="subaccount_id", + order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", + ), + ] + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchCancelDerivativeOrders(sender="sender", data=orders) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_batch_cancel_derivative_orders instead" + ) + + def test_msg_instant_binary_options_market_launch_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgInstantBinaryOptionsMarketLaunch( + sender="sender", + ticker="B2400/INJ", + oracle_symbol="B2400/INJ", + oracle_provider="injective", + oracle_type="Band", + oracle_scale_factor=6, + maker_fee_rate=0.001, + taker_fee_rate=0.001, + expiration_timestamp=1630000000, + settlement_timestamp=1630000000, + quote_denom="inj", + quote_decimals=18, + min_price_tick_size=0.01, + min_quantity_tick_size=0.01, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_instant_binary_options_market_launch instead" + ) + + def test_msg_create_binary_options_limit_order_deprecation_warning(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + + with warnings.catch_warnings(record=True) as all_warnings: + basic_composer.MsgCreateBinaryOptionsLimitOrder( + market_id=market.id, + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + is_buy=True, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_binary_options_limit_order instead" + ) + + def test_msg_create_binary_options_market_order_deprecation_warning(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + + with warnings.catch_warnings(record=True) as all_warnings: + basic_composer.MsgCreateBinaryOptionsMarketOrder( + market_id=market.id, + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + is_buy=True, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_binary_options_market_order instead" + ) + + def test_msg_cancel_binary_options_order_deprecation_warning(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + + with warnings.catch_warnings(record=True) as all_warnings: + basic_composer.MsgCancelBinaryOptionsOrder( + market_id=market.id, + sender="sender", + subaccount_id="subaccount id", + order_hash="order hash", + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_cancel_binary_options_order instead" + ) + + def test_msg_subaccount_transfer_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgSubaccountTransfer( + sender="sender", + source_subaccount_id="source subaccount id", + destination_subaccount_id="destination subaccount id", + amount=1, + denom="INJ", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_subaccount_transfer instead" + + def test_msg_external_transfer_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgExternalTransfer( + sender="sender", + source_subaccount_id="source subaccount id", + destination_subaccount_id="destination subaccount id", + amount=1, + denom="INJ", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_external_transfer instead" + + def test_msg_liquidate_position_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgLiquidatePosition( + sender="sender", + subaccount_id="subaccount id", + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_liquidate_position instead" + + def test_msg_increase_position_margin_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgIncreasePositionMargin( + sender="sender", + source_subaccount_id="source_subaccount id", + destination_subaccount_id="destination_subaccount id", + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + amount=1, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_increase_position_margin instead" + ) + + def test_msg_rewards_opt_out_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgRewardsOptOut( + sender="sender", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_rewards_opt_out instead" + + def test_msg_admin_update_binary_options_market_deprecation_warning(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + + with warnings.catch_warnings(record=True) as all_warnings: + basic_composer.MsgAdminUpdateBinaryOptionsMarket( + sender="sender", + market_id=market.id, + status="Paused", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_admin_update_binary_options_market instead" + ) diff --git a/tests/test_orderhash.py b/tests/test_orderhash.py index c57b6305..c2940d8d 100644 --- a/tests/test_orderhash.py +++ b/tests/test_orderhash.py @@ -1,3 +1,5 @@ +from decimal import Decimal + from pyinjective import PrivateKey from pyinjective.composer import Composer from pyinjective.core.network import Network @@ -22,23 +24,21 @@ def test_spot_order_hash(self, requests_mock): fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" spot_orders = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=0.524, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("0.524"), + quantity=Decimal("0.01"), + order_type="BUY", ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=27.92, - quantity=0.01, - is_buy=False, - is_po=False, + price=Decimal("27.92"), + quantity=Decimal("0.01"), + order_type="SELL", ), ] From 25d3444ea6eb3455e6144975281071128049aade Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 27 Feb 2024 10:50:54 -0300 Subject: [PATCH 3/7] (feat) Adde CodeRabbit configuration file --- .coderabbit.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 00000000..8e534ba3 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,6 @@ +reviews: + auto_review: + base_branches: + - "master" + - "dev" + - "feat/.*" From 4d6ce1b20a77c776ea8dd2d2a64e9b7b460b2e76 Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 20 Feb 2024 12:52:10 -0300 Subject: [PATCH 4/7] (feat) Added support for all chain exchange module queries. Included new example scripts for all the queries and unit tests. --- ...drawAddress.py => 1_SetWithdrawAddress.py} | 0 ...Reward.py => 2_WithdrawDelegatorReward.py} | 0 ...on.py => 3_WithdrawValidatorCommission.py} | 0 ...ommunityPool.py => 4_FundCommunityPool.py} | 0 .../1_ValidatorDistributionInfo.py | 0 .../2_ValidatorOutstandingRewards.py | 0 .../{ => query}/3_ValidatorCommission.py | 0 .../{ => query}/4_ValidatorSlashes.py | 0 .../{ => query}/5_DelegationRewards.py | 0 .../{ => query}/6_DelegationTotalRewards.py | 0 .../{ => query}/7_DelegatorValidators.py | 0 .../{ => query}/8_DelegatorWithdrawAddress.py | 0 .../{ => query}/9_CommunityPool.py | 0 .../10_MsgSubaccountTransfer.py} | 0 .../11_MsgBatchUpdateOrders.py} | 0 .../12_MsgRewardsOptOut.py} | 0 .../15_ExternalTransfer.py} | 0 .../16_MsgCreateBinaryOptionsLimitOrder.py} | 0 .../17_MsgCreateBinaryOptionsMarketOrder.py} | 0 .../18_MsgCancelBinaryOptionsOrder.py} | 0 .../19_MsgLiquidatePosition.py} | 0 .../1_MsgDeposit.py} | 0 .../3_MsgCreateSpotLimitOrder.py | 0 .../4_MsgCreateSpotMarketOrder.py | 0 .../{ => exchange}/5_MsgCancelSpotOrder.py | 0 .../6_MsgCreateDerivativeLimitOrder.py | 0 .../7_MsgCreateDerivativeMarketOrder.py | 0 .../8_MsgCancelDerivativeOrder.py | 0 .../9_MsgWithdraw.py} | 0 .../exchange/query/10_SpotMarkets.py | 22 + .../exchange/query/11_SpotMarket.py | 21 + .../exchange/query/12_FullSpotMarkets.py | 23 + .../exchange/query/13_FullSpotMarket.py | 22 + .../exchange/query/14_SpotOrderbook.py | 26 + .../exchange/query/15_TraderSpotOrders.py | 37 + .../query/16_AccountAddressSpotOrders.py | 35 + .../exchange/query/17_SpotOrdersByHashes.py | 38 + .../exchange/query/18_SubaccountOrders.py | 37 + .../query/19_TraderSpotTransientOrders.py | 37 + .../exchange/query/1_SubaccountDeposits.py | 34 + .../exchange/query/20_SpotMidPriceAndTOB.py | 21 + .../query/21_DerivativeMidPriceAndTOB.py | 21 + .../exchange/query/22_DerivativeOrderbook.py | 25 + .../query/23_TraderDerivativeOrders.py | 37 + .../24_AccountAddressDerivativeOrders.py | 35 + .../query/25_DerivativeOrdersByHashes.py | 38 + .../26_TraderDerivativeTransientOrders.py | 37 + .../exchange/query/27_DerivativeMarkets.py | 22 + .../exchange/query/28_DerivativeMarket.py | 21 + .../query/29_DerivativeMarketAddress.py | 21 + .../exchange/query/2_SubaccountDeposit.py | 34 + .../exchange/query/30_SubaccountTradeNonce.py | 36 + .../exchange/query/31_Positions.py | 19 + .../exchange/query/32_SubaccountPositions.py | 36 + .../query/33_SubaccountPossitionInMarket.py | 37 + ...34_SubaccountEffectivePossitionInMarket.py | 37 + .../exchange/query/35_PerpetualMarketInfo.py | 21 + .../query/36_ExpiryFuturesMarketInfo.py | 21 + .../query/37_PerpetualMarketFunding.py | 21 + .../query/38_SubaccountOrderMetadata.py | 36 + .../exchange/query/39_TradeRewardPoints.py | 34 + .../exchange/query/3_ExchangeBalances.py | 18 + .../query/40_PendingTradeRewardPoints.py | 34 + .../query/41_FeeDiscountAccountInfo.py | 34 + .../exchange/query/42_FeeDiscountSchedule.py | 19 + .../exchange/query/43_BalanceMismatches.py | 19 + .../query/44_BalanceWithBalanceHolds.py | 19 + .../query/45_FeeDiscountTierStatistics.py | 19 + .../exchange/query/46_MitoVaultInfos.py | 19 + .../query/47_QueryMarketIDFromVault.py | 19 + .../query/48_HistoricalTradeRecords.py | 21 + .../exchange/query/49_IsOptedOutOfRewards.py | 34 + .../exchange/query/4_AggregateVolume.py | 36 + .../query/50_OptedOutOfRewardsAccounts.py | 19 + .../exchange/query/51_MarketVolatility.py | 30 + .../exchange/query/52_BinaryOptionsMarkets.py | 19 + .../53_TraderDerivativeConditionalOrders.py | 37 + .../54_MarketAtomicExecutionFeeMultiplier.py | 21 + .../exchange/query/5_AggregateVolumes.py | 34 + .../exchange/query/6_AggregateMarketVolume.py | 21 + .../query/7_AggregateMarketVolumes.py | 21 + .../exchange/query/8_DenomDecimal.py | 19 + .../exchange/query/9_DenomDecimals.py | 19 + pyinjective/async_client.py | 393 +++ .../chain/grpc/chain_grpc_exchange_api.py | 572 ++++ .../configurable_exchange_query_servicer.py | 325 +++ .../grpc/test_chain_grpc_exchange_api.py | 2466 +++++++++++++++++ 87 files changed, 5229 insertions(+) rename examples/chain_client/distribution/{10_SetWithdrawAddress.py => 1_SetWithdrawAddress.py} (100%) rename examples/chain_client/distribution/{11_WithdrawDelegatorReward.py => 2_WithdrawDelegatorReward.py} (100%) rename examples/chain_client/distribution/{12_WithdrawValidatorCommission.py => 3_WithdrawValidatorCommission.py} (100%) rename examples/chain_client/distribution/{13_FundCommunityPool.py => 4_FundCommunityPool.py} (100%) rename examples/chain_client/distribution/{ => query}/1_ValidatorDistributionInfo.py (100%) rename examples/chain_client/distribution/{ => query}/2_ValidatorOutstandingRewards.py (100%) rename examples/chain_client/distribution/{ => query}/3_ValidatorCommission.py (100%) rename examples/chain_client/distribution/{ => query}/4_ValidatorSlashes.py (100%) rename examples/chain_client/distribution/{ => query}/5_DelegationRewards.py (100%) rename examples/chain_client/distribution/{ => query}/6_DelegationTotalRewards.py (100%) rename examples/chain_client/distribution/{ => query}/7_DelegatorValidators.py (100%) rename examples/chain_client/distribution/{ => query}/8_DelegatorWithdrawAddress.py (100%) rename examples/chain_client/distribution/{ => query}/9_CommunityPool.py (100%) rename examples/chain_client/{16_MsgSubaccountTransfer.py => exchange/10_MsgSubaccountTransfer.py} (100%) rename examples/chain_client/{17_MsgBatchUpdateOrders.py => exchange/11_MsgBatchUpdateOrders.py} (100%) rename examples/chain_client/{24_MsgRewardsOptOut.py => exchange/12_MsgRewardsOptOut.py} (100%) rename examples/chain_client/{30_ExternalTransfer.py => exchange/15_ExternalTransfer.py} (100%) rename examples/chain_client/{31_MsgCreateBinaryOptionsLimitOrder.py => exchange/16_MsgCreateBinaryOptionsLimitOrder.py} (100%) rename examples/chain_client/{32_MsgCreateBinaryOptionsMarketOrder.py => exchange/17_MsgCreateBinaryOptionsMarketOrder.py} (100%) rename examples/chain_client/{33_MsgCancelBinaryOptionsOrder.py => exchange/18_MsgCancelBinaryOptionsOrder.py} (100%) rename examples/chain_client/{77_MsgLiquidatePosition.py => exchange/19_MsgLiquidatePosition.py} (100%) rename examples/chain_client/{2_MsgDeposit.py => exchange/1_MsgDeposit.py} (100%) rename examples/chain_client/{ => exchange}/3_MsgCreateSpotLimitOrder.py (100%) rename examples/chain_client/{ => exchange}/4_MsgCreateSpotMarketOrder.py (100%) rename examples/chain_client/{ => exchange}/5_MsgCancelSpotOrder.py (100%) rename examples/chain_client/{ => exchange}/6_MsgCreateDerivativeLimitOrder.py (100%) rename examples/chain_client/{ => exchange}/7_MsgCreateDerivativeMarketOrder.py (100%) rename examples/chain_client/{ => exchange}/8_MsgCancelDerivativeOrder.py (100%) rename examples/chain_client/{15_MsgWithdraw.py => exchange/9_MsgWithdraw.py} (100%) create mode 100644 examples/chain_client/exchange/query/10_SpotMarkets.py create mode 100644 examples/chain_client/exchange/query/11_SpotMarket.py create mode 100644 examples/chain_client/exchange/query/12_FullSpotMarkets.py create mode 100644 examples/chain_client/exchange/query/13_FullSpotMarket.py create mode 100644 examples/chain_client/exchange/query/14_SpotOrderbook.py create mode 100644 examples/chain_client/exchange/query/15_TraderSpotOrders.py create mode 100644 examples/chain_client/exchange/query/16_AccountAddressSpotOrders.py create mode 100644 examples/chain_client/exchange/query/17_SpotOrdersByHashes.py create mode 100644 examples/chain_client/exchange/query/18_SubaccountOrders.py create mode 100644 examples/chain_client/exchange/query/19_TraderSpotTransientOrders.py create mode 100644 examples/chain_client/exchange/query/1_SubaccountDeposits.py create mode 100644 examples/chain_client/exchange/query/20_SpotMidPriceAndTOB.py create mode 100644 examples/chain_client/exchange/query/21_DerivativeMidPriceAndTOB.py create mode 100644 examples/chain_client/exchange/query/22_DerivativeOrderbook.py create mode 100644 examples/chain_client/exchange/query/23_TraderDerivativeOrders.py create mode 100644 examples/chain_client/exchange/query/24_AccountAddressDerivativeOrders.py create mode 100644 examples/chain_client/exchange/query/25_DerivativeOrdersByHashes.py create mode 100644 examples/chain_client/exchange/query/26_TraderDerivativeTransientOrders.py create mode 100644 examples/chain_client/exchange/query/27_DerivativeMarkets.py create mode 100644 examples/chain_client/exchange/query/28_DerivativeMarket.py create mode 100644 examples/chain_client/exchange/query/29_DerivativeMarketAddress.py create mode 100644 examples/chain_client/exchange/query/2_SubaccountDeposit.py create mode 100644 examples/chain_client/exchange/query/30_SubaccountTradeNonce.py create mode 100644 examples/chain_client/exchange/query/31_Positions.py create mode 100644 examples/chain_client/exchange/query/32_SubaccountPositions.py create mode 100644 examples/chain_client/exchange/query/33_SubaccountPossitionInMarket.py create mode 100644 examples/chain_client/exchange/query/34_SubaccountEffectivePossitionInMarket.py create mode 100644 examples/chain_client/exchange/query/35_PerpetualMarketInfo.py create mode 100644 examples/chain_client/exchange/query/36_ExpiryFuturesMarketInfo.py create mode 100644 examples/chain_client/exchange/query/37_PerpetualMarketFunding.py create mode 100644 examples/chain_client/exchange/query/38_SubaccountOrderMetadata.py create mode 100644 examples/chain_client/exchange/query/39_TradeRewardPoints.py create mode 100644 examples/chain_client/exchange/query/3_ExchangeBalances.py create mode 100644 examples/chain_client/exchange/query/40_PendingTradeRewardPoints.py create mode 100644 examples/chain_client/exchange/query/41_FeeDiscountAccountInfo.py create mode 100644 examples/chain_client/exchange/query/42_FeeDiscountSchedule.py create mode 100644 examples/chain_client/exchange/query/43_BalanceMismatches.py create mode 100644 examples/chain_client/exchange/query/44_BalanceWithBalanceHolds.py create mode 100644 examples/chain_client/exchange/query/45_FeeDiscountTierStatistics.py create mode 100644 examples/chain_client/exchange/query/46_MitoVaultInfos.py create mode 100644 examples/chain_client/exchange/query/47_QueryMarketIDFromVault.py create mode 100644 examples/chain_client/exchange/query/48_HistoricalTradeRecords.py create mode 100644 examples/chain_client/exchange/query/49_IsOptedOutOfRewards.py create mode 100644 examples/chain_client/exchange/query/4_AggregateVolume.py create mode 100644 examples/chain_client/exchange/query/50_OptedOutOfRewardsAccounts.py create mode 100644 examples/chain_client/exchange/query/51_MarketVolatility.py create mode 100644 examples/chain_client/exchange/query/52_BinaryOptionsMarkets.py create mode 100644 examples/chain_client/exchange/query/53_TraderDerivativeConditionalOrders.py create mode 100644 examples/chain_client/exchange/query/54_MarketAtomicExecutionFeeMultiplier.py create mode 100644 examples/chain_client/exchange/query/5_AggregateVolumes.py create mode 100644 examples/chain_client/exchange/query/6_AggregateMarketVolume.py create mode 100644 examples/chain_client/exchange/query/7_AggregateMarketVolumes.py create mode 100644 examples/chain_client/exchange/query/8_DenomDecimal.py create mode 100644 examples/chain_client/exchange/query/9_DenomDecimals.py create mode 100644 pyinjective/client/chain/grpc/chain_grpc_exchange_api.py create mode 100644 tests/client/chain/grpc/configurable_exchange_query_servicer.py create mode 100644 tests/client/chain/grpc/test_chain_grpc_exchange_api.py diff --git a/examples/chain_client/distribution/10_SetWithdrawAddress.py b/examples/chain_client/distribution/1_SetWithdrawAddress.py similarity index 100% rename from examples/chain_client/distribution/10_SetWithdrawAddress.py rename to examples/chain_client/distribution/1_SetWithdrawAddress.py diff --git a/examples/chain_client/distribution/11_WithdrawDelegatorReward.py b/examples/chain_client/distribution/2_WithdrawDelegatorReward.py similarity index 100% rename from examples/chain_client/distribution/11_WithdrawDelegatorReward.py rename to examples/chain_client/distribution/2_WithdrawDelegatorReward.py diff --git a/examples/chain_client/distribution/12_WithdrawValidatorCommission.py b/examples/chain_client/distribution/3_WithdrawValidatorCommission.py similarity index 100% rename from examples/chain_client/distribution/12_WithdrawValidatorCommission.py rename to examples/chain_client/distribution/3_WithdrawValidatorCommission.py diff --git a/examples/chain_client/distribution/13_FundCommunityPool.py b/examples/chain_client/distribution/4_FundCommunityPool.py similarity index 100% rename from examples/chain_client/distribution/13_FundCommunityPool.py rename to examples/chain_client/distribution/4_FundCommunityPool.py diff --git a/examples/chain_client/distribution/1_ValidatorDistributionInfo.py b/examples/chain_client/distribution/query/1_ValidatorDistributionInfo.py similarity index 100% rename from examples/chain_client/distribution/1_ValidatorDistributionInfo.py rename to examples/chain_client/distribution/query/1_ValidatorDistributionInfo.py diff --git a/examples/chain_client/distribution/2_ValidatorOutstandingRewards.py b/examples/chain_client/distribution/query/2_ValidatorOutstandingRewards.py similarity index 100% rename from examples/chain_client/distribution/2_ValidatorOutstandingRewards.py rename to examples/chain_client/distribution/query/2_ValidatorOutstandingRewards.py diff --git a/examples/chain_client/distribution/3_ValidatorCommission.py b/examples/chain_client/distribution/query/3_ValidatorCommission.py similarity index 100% rename from examples/chain_client/distribution/3_ValidatorCommission.py rename to examples/chain_client/distribution/query/3_ValidatorCommission.py diff --git a/examples/chain_client/distribution/4_ValidatorSlashes.py b/examples/chain_client/distribution/query/4_ValidatorSlashes.py similarity index 100% rename from examples/chain_client/distribution/4_ValidatorSlashes.py rename to examples/chain_client/distribution/query/4_ValidatorSlashes.py diff --git a/examples/chain_client/distribution/5_DelegationRewards.py b/examples/chain_client/distribution/query/5_DelegationRewards.py similarity index 100% rename from examples/chain_client/distribution/5_DelegationRewards.py rename to examples/chain_client/distribution/query/5_DelegationRewards.py diff --git a/examples/chain_client/distribution/6_DelegationTotalRewards.py b/examples/chain_client/distribution/query/6_DelegationTotalRewards.py similarity index 100% rename from examples/chain_client/distribution/6_DelegationTotalRewards.py rename to examples/chain_client/distribution/query/6_DelegationTotalRewards.py diff --git a/examples/chain_client/distribution/7_DelegatorValidators.py b/examples/chain_client/distribution/query/7_DelegatorValidators.py similarity index 100% rename from examples/chain_client/distribution/7_DelegatorValidators.py rename to examples/chain_client/distribution/query/7_DelegatorValidators.py diff --git a/examples/chain_client/distribution/8_DelegatorWithdrawAddress.py b/examples/chain_client/distribution/query/8_DelegatorWithdrawAddress.py similarity index 100% rename from examples/chain_client/distribution/8_DelegatorWithdrawAddress.py rename to examples/chain_client/distribution/query/8_DelegatorWithdrawAddress.py diff --git a/examples/chain_client/distribution/9_CommunityPool.py b/examples/chain_client/distribution/query/9_CommunityPool.py similarity index 100% rename from examples/chain_client/distribution/9_CommunityPool.py rename to examples/chain_client/distribution/query/9_CommunityPool.py diff --git a/examples/chain_client/16_MsgSubaccountTransfer.py b/examples/chain_client/exchange/10_MsgSubaccountTransfer.py similarity index 100% rename from examples/chain_client/16_MsgSubaccountTransfer.py rename to examples/chain_client/exchange/10_MsgSubaccountTransfer.py diff --git a/examples/chain_client/17_MsgBatchUpdateOrders.py b/examples/chain_client/exchange/11_MsgBatchUpdateOrders.py similarity index 100% rename from examples/chain_client/17_MsgBatchUpdateOrders.py rename to examples/chain_client/exchange/11_MsgBatchUpdateOrders.py diff --git a/examples/chain_client/24_MsgRewardsOptOut.py b/examples/chain_client/exchange/12_MsgRewardsOptOut.py similarity index 100% rename from examples/chain_client/24_MsgRewardsOptOut.py rename to examples/chain_client/exchange/12_MsgRewardsOptOut.py diff --git a/examples/chain_client/30_ExternalTransfer.py b/examples/chain_client/exchange/15_ExternalTransfer.py similarity index 100% rename from examples/chain_client/30_ExternalTransfer.py rename to examples/chain_client/exchange/15_ExternalTransfer.py diff --git a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py b/examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py similarity index 100% rename from examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py rename to examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py diff --git a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py b/examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py similarity index 100% rename from examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py rename to examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py diff --git a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py b/examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py similarity index 100% rename from examples/chain_client/33_MsgCancelBinaryOptionsOrder.py rename to examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py diff --git a/examples/chain_client/77_MsgLiquidatePosition.py b/examples/chain_client/exchange/19_MsgLiquidatePosition.py similarity index 100% rename from examples/chain_client/77_MsgLiquidatePosition.py rename to examples/chain_client/exchange/19_MsgLiquidatePosition.py diff --git a/examples/chain_client/2_MsgDeposit.py b/examples/chain_client/exchange/1_MsgDeposit.py similarity index 100% rename from examples/chain_client/2_MsgDeposit.py rename to examples/chain_client/exchange/1_MsgDeposit.py diff --git a/examples/chain_client/3_MsgCreateSpotLimitOrder.py b/examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py similarity index 100% rename from examples/chain_client/3_MsgCreateSpotLimitOrder.py rename to examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py diff --git a/examples/chain_client/4_MsgCreateSpotMarketOrder.py b/examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py similarity index 100% rename from examples/chain_client/4_MsgCreateSpotMarketOrder.py rename to examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py diff --git a/examples/chain_client/5_MsgCancelSpotOrder.py b/examples/chain_client/exchange/5_MsgCancelSpotOrder.py similarity index 100% rename from examples/chain_client/5_MsgCancelSpotOrder.py rename to examples/chain_client/exchange/5_MsgCancelSpotOrder.py diff --git a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py similarity index 100% rename from examples/chain_client/6_MsgCreateDerivativeLimitOrder.py rename to examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py diff --git a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py b/examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py similarity index 100% rename from examples/chain_client/7_MsgCreateDerivativeMarketOrder.py rename to examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py diff --git a/examples/chain_client/8_MsgCancelDerivativeOrder.py b/examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py similarity index 100% rename from examples/chain_client/8_MsgCancelDerivativeOrder.py rename to examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py diff --git a/examples/chain_client/15_MsgWithdraw.py b/examples/chain_client/exchange/9_MsgWithdraw.py similarity index 100% rename from examples/chain_client/15_MsgWithdraw.py rename to examples/chain_client/exchange/9_MsgWithdraw.py diff --git a/examples/chain_client/exchange/query/10_SpotMarkets.py b/examples/chain_client/exchange/query/10_SpotMarkets.py new file mode 100644 index 00000000..4cedc9d7 --- /dev/null +++ b/examples/chain_client/exchange/query/10_SpotMarkets.py @@ -0,0 +1,22 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + spot_markets = await client.fetch_chain_spot_markets( + status="Active", + market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"], + ) + print(spot_markets) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/11_SpotMarket.py b/examples/chain_client/exchange/query/11_SpotMarket.py new file mode 100644 index 00000000..0e774edf --- /dev/null +++ b/examples/chain_client/exchange/query/11_SpotMarket.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + spot_market = await client.fetch_chain_spot_market( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + print(spot_market) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/12_FullSpotMarkets.py b/examples/chain_client/exchange/query/12_FullSpotMarkets.py new file mode 100644 index 00000000..cfefee28 --- /dev/null +++ b/examples/chain_client/exchange/query/12_FullSpotMarkets.py @@ -0,0 +1,23 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + spot_markets = await client.fetch_chain_full_spot_markets( + status="Active", + market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"], + with_mid_price_and_tob=True, + ) + print(spot_markets) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/13_FullSpotMarket.py b/examples/chain_client/exchange/query/13_FullSpotMarket.py new file mode 100644 index 00000000..6a39269d --- /dev/null +++ b/examples/chain_client/exchange/query/13_FullSpotMarket.py @@ -0,0 +1,22 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + spot_market = await client.fetch_chain_full_spot_market( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + with_mid_price_and_tob=True, + ) + print(spot_market) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/14_SpotOrderbook.py b/examples/chain_client/exchange/query/14_SpotOrderbook.py new file mode 100644 index 00000000..7b5a9aa1 --- /dev/null +++ b/examples/chain_client/exchange/query/14_SpotOrderbook.py @@ -0,0 +1,26 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + pagination = PaginationOption(limit=2) + + orderbook = await client.fetch_chain_spot_orderbook( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + order_side="Buy", + pagination=pagination, + ) + print(orderbook) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/15_TraderSpotOrders.py b/examples/chain_client/exchange/query/15_TraderSpotOrders.py new file mode 100644 index 00000000..0cc96b6f --- /dev/null +++ b/examples/chain_client/exchange/query/15_TraderSpotOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_trader_spot_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id=subaccount_id, + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/16_AccountAddressSpotOrders.py b/examples/chain_client/exchange/query/16_AccountAddressSpotOrders.py new file mode 100644 index 00000000..8e50fa95 --- /dev/null +++ b/examples/chain_client/exchange/query/16_AccountAddressSpotOrders.py @@ -0,0 +1,35 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + orders = await client.fetch_chain_account_address_spot_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + account_address=address.to_acc_bech32(), + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/17_SpotOrdersByHashes.py b/examples/chain_client/exchange/query/17_SpotOrdersByHashes.py new file mode 100644 index 00000000..641eb6f5 --- /dev/null +++ b/examples/chain_client/exchange/query/17_SpotOrdersByHashes.py @@ -0,0 +1,38 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_spot_orders_by_hashes( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id=subaccount_id, + order_hashes=["0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"], + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/18_SubaccountOrders.py b/examples/chain_client/exchange/query/18_SubaccountOrders.py new file mode 100644 index 00000000..4983f827 --- /dev/null +++ b/examples/chain_client/exchange/query/18_SubaccountOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_subaccount_orders( + subaccount_id=subaccount_id, + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/19_TraderSpotTransientOrders.py b/examples/chain_client/exchange/query/19_TraderSpotTransientOrders.py new file mode 100644 index 00000000..2b29c2c0 --- /dev/null +++ b/examples/chain_client/exchange/query/19_TraderSpotTransientOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_trader_spot_transient_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id=subaccount_id, + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/1_SubaccountDeposits.py b/examples/chain_client/exchange/query/1_SubaccountDeposits.py new file mode 100644 index 00000000..f9afb8ae --- /dev/null +++ b/examples/chain_client/exchange/query/1_SubaccountDeposits.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + deposits = await client.fetch_subaccount_deposits(subaccount_id=subaccount_id) + print(deposits) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/20_SpotMidPriceAndTOB.py b/examples/chain_client/exchange/query/20_SpotMidPriceAndTOB.py new file mode 100644 index 00000000..35493ffd --- /dev/null +++ b/examples/chain_client/exchange/query/20_SpotMidPriceAndTOB.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + prices = await client.fetch_spot_mid_price_and_tob( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + print(prices) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/21_DerivativeMidPriceAndTOB.py b/examples/chain_client/exchange/query/21_DerivativeMidPriceAndTOB.py new file mode 100644 index 00000000..5b5c5fff --- /dev/null +++ b/examples/chain_client/exchange/query/21_DerivativeMidPriceAndTOB.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + prices = await client.fetch_derivative_mid_price_and_tob( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(prices) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/22_DerivativeOrderbook.py b/examples/chain_client/exchange/query/22_DerivativeOrderbook.py new file mode 100644 index 00000000..465a62b6 --- /dev/null +++ b/examples/chain_client/exchange/query/22_DerivativeOrderbook.py @@ -0,0 +1,25 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + pagination = PaginationOption(limit=2) + + orderbook = await client.fetch_chain_derivative_orderbook( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + pagination=pagination, + ) + print(orderbook) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/23_TraderDerivativeOrders.py b/examples/chain_client/exchange/query/23_TraderDerivativeOrders.py new file mode 100644 index 00000000..61e98ba1 --- /dev/null +++ b/examples/chain_client/exchange/query/23_TraderDerivativeOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_trader_spot_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id=subaccount_id, + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/24_AccountAddressDerivativeOrders.py b/examples/chain_client/exchange/query/24_AccountAddressDerivativeOrders.py new file mode 100644 index 00000000..469c99fb --- /dev/null +++ b/examples/chain_client/exchange/query/24_AccountAddressDerivativeOrders.py @@ -0,0 +1,35 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + orders = await client.fetch_chain_account_address_spot_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + account_address=address.to_acc_bech32(), + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/25_DerivativeOrdersByHashes.py b/examples/chain_client/exchange/query/25_DerivativeOrdersByHashes.py new file mode 100644 index 00000000..ea700e6d --- /dev/null +++ b/examples/chain_client/exchange/query/25_DerivativeOrdersByHashes.py @@ -0,0 +1,38 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_spot_orders_by_hashes( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id=subaccount_id, + order_hashes=["0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"], + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/26_TraderDerivativeTransientOrders.py b/examples/chain_client/exchange/query/26_TraderDerivativeTransientOrders.py new file mode 100644 index 00000000..c5548d59 --- /dev/null +++ b/examples/chain_client/exchange/query/26_TraderDerivativeTransientOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_chain_trader_derivative_transient_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id=subaccount_id, + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/27_DerivativeMarkets.py b/examples/chain_client/exchange/query/27_DerivativeMarkets.py new file mode 100644 index 00000000..2f4bbc5a --- /dev/null +++ b/examples/chain_client/exchange/query/27_DerivativeMarkets.py @@ -0,0 +1,22 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + derivative_markets = await client.fetch_chain_derivative_markets( + status="Active", + market_ids=["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"], + ) + print(derivative_markets) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/28_DerivativeMarket.py b/examples/chain_client/exchange/query/28_DerivativeMarket.py new file mode 100644 index 00000000..152381f5 --- /dev/null +++ b/examples/chain_client/exchange/query/28_DerivativeMarket.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + derivative_market = await client.fetch_chain_derivative_market( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(derivative_market) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/29_DerivativeMarketAddress.py b/examples/chain_client/exchange/query/29_DerivativeMarketAddress.py new file mode 100644 index 00000000..c2d88805 --- /dev/null +++ b/examples/chain_client/exchange/query/29_DerivativeMarketAddress.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + address = await client.fetch_derivative_market_address( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(address) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/2_SubaccountDeposit.py b/examples/chain_client/exchange/query/2_SubaccountDeposit.py new file mode 100644 index 00000000..5002397d --- /dev/null +++ b/examples/chain_client/exchange/query/2_SubaccountDeposit.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + deposit = await client.fetch_subaccount_deposit(subaccount_id=subaccount_id, denom="inj") + print(deposit) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/30_SubaccountTradeNonce.py b/examples/chain_client/exchange/query/30_SubaccountTradeNonce.py new file mode 100644 index 00000000..ad81aca3 --- /dev/null +++ b/examples/chain_client/exchange/query/30_SubaccountTradeNonce.py @@ -0,0 +1,36 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + nonce = await client.fetch_subaccount_trade_nonce( + subaccount_id=subaccount_id, + ) + print(nonce) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/31_Positions.py b/examples/chain_client/exchange/query/31_Positions.py new file mode 100644 index 00000000..ae494b6a --- /dev/null +++ b/examples/chain_client/exchange/query/31_Positions.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + positions = await client.fetch_chain_positions() + print(positions) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/32_SubaccountPositions.py b/examples/chain_client/exchange/query/32_SubaccountPositions.py new file mode 100644 index 00000000..000d95b6 --- /dev/null +++ b/examples/chain_client/exchange/query/32_SubaccountPositions.py @@ -0,0 +1,36 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + positions = await client.fetch_chain_subaccount_positions( + subaccount_id=subaccount_id, + ) + print(positions) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/33_SubaccountPossitionInMarket.py b/examples/chain_client/exchange/query/33_SubaccountPossitionInMarket.py new file mode 100644 index 00000000..4e0f1ddb --- /dev/null +++ b/examples/chain_client/exchange/query/33_SubaccountPossitionInMarket.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + position = await client.fetch_chain_subaccount_position_in_market( + subaccount_id=subaccount_id, + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(position) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/34_SubaccountEffectivePossitionInMarket.py b/examples/chain_client/exchange/query/34_SubaccountEffectivePossitionInMarket.py new file mode 100644 index 00000000..e729e77c --- /dev/null +++ b/examples/chain_client/exchange/query/34_SubaccountEffectivePossitionInMarket.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + position = await client.fetch_chain_subaccount_effective_position_in_market( + subaccount_id=subaccount_id, + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(position) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/35_PerpetualMarketInfo.py b/examples/chain_client/exchange/query/35_PerpetualMarketInfo.py new file mode 100644 index 00000000..ca27f552 --- /dev/null +++ b/examples/chain_client/exchange/query/35_PerpetualMarketInfo.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_info = await client.fetch_chain_perpetual_market_info( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(market_info) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/36_ExpiryFuturesMarketInfo.py b/examples/chain_client/exchange/query/36_ExpiryFuturesMarketInfo.py new file mode 100644 index 00000000..4053013c --- /dev/null +++ b/examples/chain_client/exchange/query/36_ExpiryFuturesMarketInfo.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_info = await client.fetch_chain_expiry_futures_market_info( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(market_info) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/37_PerpetualMarketFunding.py b/examples/chain_client/exchange/query/37_PerpetualMarketFunding.py new file mode 100644 index 00000000..099c2a0f --- /dev/null +++ b/examples/chain_client/exchange/query/37_PerpetualMarketFunding.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + funding = await client.fetch_chain_perpetual_market_funding( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(funding) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/38_SubaccountOrderMetadata.py b/examples/chain_client/exchange/query/38_SubaccountOrderMetadata.py new file mode 100644 index 00000000..f4af9d38 --- /dev/null +++ b/examples/chain_client/exchange/query/38_SubaccountOrderMetadata.py @@ -0,0 +1,36 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + metadata = await client.fetch_subaccount_order_metadata( + subaccount_id=subaccount_id, + ) + print(metadata) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/39_TradeRewardPoints.py b/examples/chain_client/exchange/query/39_TradeRewardPoints.py new file mode 100644 index 00000000..13f08730 --- /dev/null +++ b/examples/chain_client/exchange/query/39_TradeRewardPoints.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + points = await client.fetch_trade_reward_points( + accounts=[address.to_acc_bech32()], + ) + print(points) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/3_ExchangeBalances.py b/examples/chain_client/exchange/query/3_ExchangeBalances.py new file mode 100644 index 00000000..091bf10c --- /dev/null +++ b/examples/chain_client/exchange/query/3_ExchangeBalances.py @@ -0,0 +1,18 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + # initialize grpc client + client = AsyncClient(network) + + balances = await client.fetch_exchange_balances() + print(balances) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/40_PendingTradeRewardPoints.py b/examples/chain_client/exchange/query/40_PendingTradeRewardPoints.py new file mode 100644 index 00000000..fa3e8aa2 --- /dev/null +++ b/examples/chain_client/exchange/query/40_PendingTradeRewardPoints.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + points = await client.fetch_pending_trade_reward_points( + accounts=[address.to_acc_bech32()], + ) + print(points) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/41_FeeDiscountAccountInfo.py b/examples/chain_client/exchange/query/41_FeeDiscountAccountInfo.py new file mode 100644 index 00000000..15fbb7ce --- /dev/null +++ b/examples/chain_client/exchange/query/41_FeeDiscountAccountInfo.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + fee_discount = await client.fetch_fee_discount_account_info( + account=address.to_acc_bech32(), + ) + print(fee_discount) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/42_FeeDiscountSchedule.py b/examples/chain_client/exchange/query/42_FeeDiscountSchedule.py new file mode 100644 index 00000000..a0ae96cb --- /dev/null +++ b/examples/chain_client/exchange/query/42_FeeDiscountSchedule.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + schedule = await client.fetch_fee_discount_schedule() + print(schedule) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/43_BalanceMismatches.py b/examples/chain_client/exchange/query/43_BalanceMismatches.py new file mode 100644 index 00000000..c7f7ca5e --- /dev/null +++ b/examples/chain_client/exchange/query/43_BalanceMismatches.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + mismatches = await client.fetch_balance_mismatches(dust_factor=1) + print(mismatches) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/44_BalanceWithBalanceHolds.py b/examples/chain_client/exchange/query/44_BalanceWithBalanceHolds.py new file mode 100644 index 00000000..6587c59a --- /dev/null +++ b/examples/chain_client/exchange/query/44_BalanceWithBalanceHolds.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + balance = await client.fetch_balance_with_balance_holds() + print(balance) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/45_FeeDiscountTierStatistics.py b/examples/chain_client/exchange/query/45_FeeDiscountTierStatistics.py new file mode 100644 index 00000000..5671e4ce --- /dev/null +++ b/examples/chain_client/exchange/query/45_FeeDiscountTierStatistics.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + statistics = await client.fetch_fee_discount_tier_statistics() + print(statistics) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/46_MitoVaultInfos.py b/examples/chain_client/exchange/query/46_MitoVaultInfos.py new file mode 100644 index 00000000..3faa5cb9 --- /dev/null +++ b/examples/chain_client/exchange/query/46_MitoVaultInfos.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + infos = await client.fetch_mito_vault_infos() + print(infos) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/47_QueryMarketIDFromVault.py b/examples/chain_client/exchange/query/47_QueryMarketIDFromVault.py new file mode 100644 index 00000000..e699dbaa --- /dev/null +++ b/examples/chain_client/exchange/query/47_QueryMarketIDFromVault.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_id = await client.fetch_market_id_from_vault(vault_address="inj1qg5ega6dykkxc307y25pecuufrjkxkag6xhp6y") + print(market_id) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/48_HistoricalTradeRecords.py b/examples/chain_client/exchange/query/48_HistoricalTradeRecords.py new file mode 100644 index 00000000..6b93200f --- /dev/null +++ b/examples/chain_client/exchange/query/48_HistoricalTradeRecords.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + records = await client.fetch_historical_trade_records( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + ) + print(records) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/49_IsOptedOutOfRewards.py b/examples/chain_client/exchange/query/49_IsOptedOutOfRewards.py new file mode 100644 index 00000000..28c0925c --- /dev/null +++ b/examples/chain_client/exchange/query/49_IsOptedOutOfRewards.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + is_opted_out = await client.fetch_is_opted_out_of_rewards( + account=address.to_acc_bech32(), + ) + print(is_opted_out) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/4_AggregateVolume.py b/examples/chain_client/exchange/query/4_AggregateVolume.py new file mode 100644 index 00000000..35c334a5 --- /dev/null +++ b/examples/chain_client/exchange/query/4_AggregateVolume.py @@ -0,0 +1,36 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + + subaccount_id = address.get_subaccount_id(index=0) + + volume = await client.fetch_aggregate_volume(account=address.to_acc_bech32()) + print(volume) + + volume = await client.fetch_aggregate_volume(account=subaccount_id) + print(volume) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/50_OptedOutOfRewardsAccounts.py b/examples/chain_client/exchange/query/50_OptedOutOfRewardsAccounts.py new file mode 100644 index 00000000..9940f799 --- /dev/null +++ b/examples/chain_client/exchange/query/50_OptedOutOfRewardsAccounts.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + opted_out = await client.fetch_opted_out_of_rewards_accounts() + print(opted_out) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/51_MarketVolatility.py b/examples/chain_client/exchange/query/51_MarketVolatility.py new file mode 100644 index 00000000..3173ca39 --- /dev/null +++ b/examples/chain_client/exchange/query/51_MarketVolatility.py @@ -0,0 +1,30 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + trade_grouping_sec = 10 + max_age = 0 + include_raw_history = True + include_metadata = True + volatility = await client.fetch_market_volatility( + market_id=market_id, + trade_grouping_sec=trade_grouping_sec, + max_age=max_age, + include_raw_history=include_raw_history, + include_metadata=include_metadata, + ) + print(volatility) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/52_BinaryOptionsMarkets.py b/examples/chain_client/exchange/query/52_BinaryOptionsMarkets.py new file mode 100644 index 00000000..4448a4ec --- /dev/null +++ b/examples/chain_client/exchange/query/52_BinaryOptionsMarkets.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + markets = await client.fetch_chain_binary_options_markets(status="Active") + print(markets) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/53_TraderDerivativeConditionalOrders.py b/examples/chain_client/exchange/query/53_TraderDerivativeConditionalOrders.py new file mode 100644 index 00000000..fd65e68f --- /dev/null +++ b/examples/chain_client/exchange/query/53_TraderDerivativeConditionalOrders.py @@ -0,0 +1,37 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + subaccount_id = address.get_subaccount_id(index=0) + + orders = await client.fetch_trader_derivative_conditional_orders( + subaccount_id=subaccount_id, + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(orders) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/54_MarketAtomicExecutionFeeMultiplier.py b/examples/chain_client/exchange/query/54_MarketAtomicExecutionFeeMultiplier.py new file mode 100644 index 00000000..328028d3 --- /dev/null +++ b/examples/chain_client/exchange/query/54_MarketAtomicExecutionFeeMultiplier.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + multiplier = await client.fetch_market_atomic_execution_fee_multiplier( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + print(multiplier) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/5_AggregateVolumes.py b/examples/chain_client/exchange/query/5_AggregateVolumes.py new file mode 100644 index 00000000..6effe4be --- /dev/null +++ b/examples/chain_client/exchange/query/5_AggregateVolumes.py @@ -0,0 +1,34 @@ +import asyncio +import os + +import dotenv + +from pyinjective import PrivateKey +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + + volume = await client.fetch_aggregate_volumes( + accounts=[address.to_acc_bech32()], + market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"], + ) + print(volume) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/6_AggregateMarketVolume.py b/examples/chain_client/exchange/query/6_AggregateMarketVolume.py new file mode 100644 index 00000000..b3262d82 --- /dev/null +++ b/examples/chain_client/exchange/query/6_AggregateMarketVolume.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + + volume = await client.fetch_aggregate_market_volume(market_id=market_id) + print(volume) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/7_AggregateMarketVolumes.py b/examples/chain_client/exchange/query/7_AggregateMarketVolumes.py new file mode 100644 index 00000000..23dfa0ec --- /dev/null +++ b/examples/chain_client/exchange/query/7_AggregateMarketVolumes.py @@ -0,0 +1,21 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + volume = await client.fetch_aggregate_market_volumes( + market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"], + ) + print(volume) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/8_DenomDecimal.py b/examples/chain_client/exchange/query/8_DenomDecimal.py new file mode 100644 index 00000000..2079f5e8 --- /dev/null +++ b/examples/chain_client/exchange/query/8_DenomDecimal.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + deposits = await client.fetch_denom_decimal(denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5") + print(deposits) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/query/9_DenomDecimals.py b/examples/chain_client/exchange/query/9_DenomDecimals.py new file mode 100644 index 00000000..d96df30b --- /dev/null +++ b/examples/chain_client/exchange/query/9_DenomDecimals.py @@ -0,0 +1,19 @@ +import asyncio + +from pyinjective.async_client import AsyncClient +from pyinjective.core.network import Network + + +async def main() -> None: + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + + deposits = await client.fetch_denom_decimals(denoms=["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"]) + print(deposits) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index dea12f12..0af37da0 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -13,6 +13,7 @@ from pyinjective.client.chain.grpc.chain_grpc_authz_api import ChainGrpcAuthZApi from pyinjective.client.chain.grpc.chain_grpc_bank_api import ChainGrpcBankApi from pyinjective.client.chain.grpc.chain_grpc_distribution_api import ChainGrpcDistributionApi +from pyinjective.client.chain.grpc.chain_grpc_exchange_api import ChainGrpcExchangeApi from pyinjective.client.chain.grpc.chain_grpc_token_factory_api import ChainGrpcTokenFactoryApi from pyinjective.client.chain.grpc.chain_grpc_wasm_api import ChainGrpcWasmApi from pyinjective.client.chain.grpc_stream.chain_grpc_chain_stream import ChainGrpcChainStream @@ -185,6 +186,12 @@ def __init__( metadata_query_provider=self._chain_cookie_metadata_requestor ), ) + self.chain_exchange_api = ChainGrpcExchangeApi( + channel=self.chain_channel, + metadata_provider=lambda: self.network.chain_metadata( + metadata_query_provider=self._chain_cookie_metadata_requestor + ), + ) self.token_factory_api = ChainGrpcTokenFactoryApi( channel=self.chain_channel, metadata_provider=lambda: self.network.chain_metadata( @@ -639,6 +646,392 @@ async def fetch_delegator_withdraw_address( async def fetch_community_pool(self) -> Dict[str, Any]: return await self.distribution_api.fetch_community_pool() + # Exchange module + + async def fetch_subaccount_deposits( + self, + subaccount_id: Optional[str] = None, + subaccount_trader: Optional[str] = None, + subaccount_nonce: Optional[int] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_deposits( + subaccount_id=subaccount_id, + subaccount_trader=subaccount_trader, + subaccount_nonce=subaccount_nonce, + ) + + async def fetch_subaccount_deposit( + self, + subaccount_id: str, + denom: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_deposit( + subaccount_id=subaccount_id, + denom=denom, + ) + + async def fetch_exchange_balances(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_exchange_balances() + + async def fetch_aggregate_volume(self, account: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_aggregate_volume(account=account) + + async def fetch_aggregate_volumes( + self, + accounts: Optional[List[str]] = None, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_aggregate_volumes( + accounts=accounts, + market_ids=market_ids, + ) + + async def fetch_aggregate_market_volume( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_aggregate_market_volume( + market_id=market_id, + ) + + async def fetch_aggregate_market_volumes( + self, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_aggregate_market_volumes( + market_ids=market_ids, + ) + + async def fetch_denom_decimal(self, denom: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_denom_decimal(denom=denom) + + async def fetch_denom_decimals(self, denoms: Optional[List[str]] = None) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_denom_decimals(denoms=denoms) + + async def fetch_chain_spot_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_spot_markets( + status=status, + market_ids=market_ids, + ) + + async def fetch_chain_spot_market( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_spot_market( + market_id=market_id, + ) + + async def fetch_chain_full_spot_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_full_spot_markets( + status=status, + market_ids=market_ids, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + + async def fetch_chain_full_spot_market( + self, + market_id: str, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_full_spot_market( + market_id=market_id, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + + async def fetch_chain_spot_orderbook( + self, + market_id: str, + order_side: Optional[str] = None, + limit_cumulative_notional: Optional[str] = None, + limit_cumulative_quantity: Optional[str] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + # Order side could be "Side_Unspecified", "Buy", "Sell" + return await self.chain_exchange_api.fetch_spot_orderbook( + market_id=market_id, + order_side=order_side, + limit_cumulative_notional=limit_cumulative_notional, + limit_cumulative_quantity=limit_cumulative_quantity, + pagination=pagination, + ) + + async def fetch_chain_trader_spot_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_spot_orders( + market_id=market_id, + subaccount_id=subaccount_id, + ) + + async def fetch_chain_account_address_spot_orders( + self, + market_id: str, + account_address: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_account_address_spot_orders( + market_id=market_id, + account_address=account_address, + ) + + async def fetch_chain_spot_orders_by_hashes( + self, + market_id: str, + subaccount_id: str, + order_hashes: List[str], + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_spot_orders_by_hashes( + market_id=market_id, + subaccount_id=subaccount_id, + order_hashes=order_hashes, + ) + + async def fetch_chain_subaccount_orders( + self, + subaccount_id: str, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_orders( + subaccount_id=subaccount_id, + market_id=market_id, + ) + + async def fetch_chain_trader_spot_transient_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_spot_transient_orders( + market_id=market_id, + subaccount_id=subaccount_id, + ) + + async def fetch_spot_mid_price_and_tob( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_spot_mid_price_and_tob( + market_id=market_id, + ) + + async def fetch_derivative_mid_price_and_tob( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_mid_price_and_tob( + market_id=market_id, + ) + + async def fetch_chain_derivative_orderbook( + self, + market_id: str, + limit_cumulative_notional: Optional[str] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_orderbook( + market_id=market_id, + limit_cumulative_notional=limit_cumulative_notional, + pagination=pagination, + ) + + async def fetch_chain_trader_derivative_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_derivative_orders( + market_id=market_id, + subaccount_id=subaccount_id, + ) + + async def fetch_chain_account_address_derivative_orders( + self, + market_id: str, + account_address: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_account_address_derivative_orders( + market_id=market_id, + account_address=account_address, + ) + + async def fetch_chain_derivative_orders_by_hashes( + self, + market_id: str, + subaccount_id: str, + order_hashes: List[str], + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_orders_by_hashes( + market_id=market_id, + subaccount_id=subaccount_id, + order_hashes=order_hashes, + ) + + async def fetch_chain_trader_derivative_transient_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_derivative_transient_orders( + market_id=market_id, + subaccount_id=subaccount_id, + ) + + async def fetch_chain_derivative_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_markets( + status=status, + market_ids=market_ids, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + + async def fetch_chain_derivative_market( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_market( + market_id=market_id, + ) + + async def fetch_derivative_market_address(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_derivative_market_address(market_id=market_id) + + async def fetch_subaccount_trade_nonce(self, subaccount_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_trade_nonce(subaccount_id=subaccount_id) + + async def fetch_chain_positions(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_positions() + + async def fetch_chain_subaccount_positions(self, subaccount_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_positions(subaccount_id=subaccount_id) + + async def fetch_chain_subaccount_position_in_market(self, subaccount_id: str, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_position_in_market( + subaccount_id=subaccount_id, + market_id=market_id, + ) + + async def fetch_chain_subaccount_effective_position_in_market( + self, subaccount_id: str, market_id: str + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_effective_position_in_market( + subaccount_id=subaccount_id, + market_id=market_id, + ) + + async def fetch_chain_perpetual_market_info(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_perpetual_market_info(market_id=market_id) + + async def fetch_chain_expiry_futures_market_info(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_expiry_futures_market_info(market_id=market_id) + + async def fetch_chain_perpetual_market_funding(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_perpetual_market_funding(market_id=market_id) + + async def fetch_subaccount_order_metadata(self, subaccount_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_subaccount_order_metadata(subaccount_id=subaccount_id) + + async def fetch_trade_reward_points( + self, + accounts: Optional[List[str]] = None, + pending_pool_timestamp: Optional[int] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trade_reward_points( + accounts=accounts, + pending_pool_timestamp=pending_pool_timestamp, + ) + + async def fetch_pending_trade_reward_points( + self, + accounts: Optional[List[str]] = None, + pending_pool_timestamp: Optional[int] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_pending_trade_reward_points( + accounts=accounts, + pending_pool_timestamp=pending_pool_timestamp, + ) + + async def fetch_fee_discount_account_info(self, account: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_fee_discount_account_info(account=account) + + async def fetch_fee_discount_schedule(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_fee_discount_schedule() + + async def fetch_balance_mismatches(self, dust_factor: int) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_balance_mismatches(dust_factor=dust_factor) + + async def fetch_balance_with_balance_holds(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_balance_with_balance_holds() + + async def fetch_fee_discount_tier_statistics(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_fee_discount_tier_statistics() + + async def fetch_mito_vault_infos(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_mito_vault_infos() + + async def fetch_market_id_from_vault(self, vault_address: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_market_id_from_vault(vault_address=vault_address) + + async def fetch_historical_trade_records(self, market_id: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_historical_trade_records(market_id=market_id) + + async def fetch_is_opted_out_of_rewards(self, account: str) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_is_opted_out_of_rewards(account=account) + + async def fetch_opted_out_of_rewards_accounts(self) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_opted_out_of_rewards_accounts() + + async def fetch_market_volatility( + self, + market_id: str, + trade_grouping_sec: Optional[int] = None, + max_age: Optional[int] = None, + include_raw_history: Optional[bool] = None, + include_metadata: Optional[bool] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_market_volatility( + market_id=market_id, + trade_grouping_sec=trade_grouping_sec, + max_age=max_age, + include_raw_history=include_raw_history, + include_metadata=include_metadata, + ) + + async def fetch_chain_binary_options_markets(self, status: Optional[str] = None) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_binary_options_markets(status=status) + + async def fetch_trader_derivative_conditional_orders( + self, + subaccount_id: Optional[str] = None, + market_id: Optional[str] = None, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_trader_derivative_conditional_orders( + subaccount_id=subaccount_id, + market_id=market_id, + ) + + async def fetch_market_atomic_execution_fee_multiplier( + self, + market_id: str, + ) -> Dict[str, Any]: + return await self.chain_exchange_api.fetch_market_atomic_execution_fee_multiplier( + market_id=market_id, + ) + # Injective Exchange client methods # Auction RPC diff --git a/pyinjective/client/chain/grpc/chain_grpc_exchange_api.py b/pyinjective/client/chain/grpc/chain_grpc_exchange_api.py new file mode 100644 index 00000000..217c0d34 --- /dev/null +++ b/pyinjective/client/chain/grpc/chain_grpc_exchange_api.py @@ -0,0 +1,572 @@ +from typing import Any, Callable, Dict, List, Optional + +from grpc.aio import Channel + +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.proto.injective.exchange.v1beta1 import ( + query_pb2 as exchange_query_pb, + query_pb2_grpc as exchange_query_grpc, +) +from pyinjective.utils.grpc_api_request_assistant import GrpcApiRequestAssistant + + +class ChainGrpcExchangeApi: + def __init__(self, channel: Channel, metadata_provider: Callable): + self._stub = exchange_query_grpc.QueryStub(channel) + self._assistant = GrpcApiRequestAssistant(metadata_provider=metadata_provider) + + async def fetch_exchange_params(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryExchangeParamsRequest() + response = await self._execute_call(call=self._stub.QueryExchangeParams, request=request) + + return response + + async def fetch_subaccount_deposits( + self, + subaccount_id: Optional[str] = None, + subaccount_trader: Optional[str] = None, + subaccount_nonce: Optional[int] = None, + ) -> Dict[str, Any]: + subaccount = None + if subaccount_trader is not None or subaccount_nonce is not None: + subaccount = exchange_query_pb.Subaccount( + trader=subaccount_trader, + subaccount_nonce=subaccount_nonce, + ) + + request = exchange_query_pb.QuerySubaccountDepositsRequest(subaccount_id=subaccount_id, subaccount=subaccount) + response = await self._execute_call(call=self._stub.SubaccountDeposits, request=request) + + return response + + async def fetch_subaccount_deposit( + self, + subaccount_id: str, + denom: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountDepositRequest( + subaccount_id=subaccount_id, + denom=denom, + ) + response = await self._execute_call(call=self._stub.SubaccountDeposit, request=request) + + return response + + async def fetch_exchange_balances(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryExchangeBalancesRequest() + response = await self._execute_call(call=self._stub.ExchangeBalances, request=request) + + return response + + async def fetch_aggregate_volume(self, account: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryAggregateVolumeRequest(account=account) + response = await self._execute_call(call=self._stub.AggregateVolume, request=request) + + return response + + async def fetch_aggregate_volumes( + self, + accounts: Optional[List[str]] = None, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryAggregateVolumesRequest(accounts=accounts, market_ids=market_ids) + response = await self._execute_call(call=self._stub.AggregateVolumes, request=request) + + return response + + async def fetch_aggregate_market_volume(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryAggregateMarketVolumeRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.AggregateMarketVolume, request=request) + + return response + + async def fetch_aggregate_market_volumes(self, market_ids: Optional[List[str]] = None) -> Dict[str, Any]: + request = exchange_query_pb.QueryAggregateMarketVolumesRequest(market_ids=market_ids) + response = await self._execute_call(call=self._stub.AggregateMarketVolumes, request=request) + + return response + + async def fetch_denom_decimal(self, denom: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryDenomDecimalRequest(denom=denom) + response = await self._execute_call(call=self._stub.DenomDecimal, request=request) + + return response + + async def fetch_denom_decimals(self, denoms: Optional[List[str]] = None) -> Dict[str, Any]: + request = exchange_query_pb.QueryDenomDecimalsRequest(denoms=denoms) + response = await self._execute_call(call=self._stub.DenomDecimals, request=request) + + return response + + async def fetch_spot_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySpotMarketsRequest( + status=status, + market_ids=market_ids, + ) + response = await self._execute_call(call=self._stub.SpotMarkets, request=request) + + return response + + async def fetch_spot_market(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySpotMarketRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.SpotMarket, request=request) + + return response + + async def fetch_full_spot_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryFullSpotMarketsRequest( + status=status, + market_ids=market_ids, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + response = await self._execute_call(call=self._stub.FullSpotMarkets, request=request) + + return response + + async def fetch_full_spot_market( + self, + market_id: str, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryFullSpotMarketRequest( + market_id=market_id, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + response = await self._execute_call(call=self._stub.FullSpotMarket, request=request) + + return response + + async def fetch_spot_orderbook( + self, + market_id: str, + order_side: Optional[str] = None, + limit_cumulative_notional: Optional[str] = None, + limit_cumulative_quantity: Optional[str] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + limit = None + if pagination is not None: + limit = pagination.limit + request = exchange_query_pb.QuerySpotOrderbookRequest( + market_id=market_id, + order_side=order_side, + limit=limit, + limit_cumulative_notional=limit_cumulative_notional, + limit_cumulative_quantity=limit_cumulative_quantity, + ) + response = await self._execute_call(call=self._stub.SpotOrderbook, request=request) + + return response + + async def fetch_trader_spot_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderSpotOrdersRequest( + market_id=market_id, + subaccount_id=subaccount_id, + ) + response = await self._execute_call(call=self._stub.TraderSpotOrders, request=request) + + return response + + async def fetch_account_address_spot_orders( + self, + market_id: str, + account_address: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryAccountAddressSpotOrdersRequest( + market_id=market_id, + account_address=account_address, + ) + response = await self._execute_call(call=self._stub.AccountAddressSpotOrders, request=request) + + return response + + async def fetch_spot_orders_by_hashes( + self, + market_id: str, + subaccount_id: str, + order_hashes: List[str], + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySpotOrdersByHashesRequest( + market_id=market_id, + subaccount_id=subaccount_id, + order_hashes=order_hashes, + ) + response = await self._execute_call(call=self._stub.SpotOrdersByHashes, request=request) + + return response + + async def fetch_subaccount_orders( + self, + subaccount_id: str, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountOrdersRequest( + subaccount_id=subaccount_id, + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.SubaccountOrders, request=request) + + return response + + async def fetch_trader_spot_transient_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderSpotOrdersRequest( + market_id=market_id, + subaccount_id=subaccount_id, + ) + response = await self._execute_call(call=self._stub.TraderSpotTransientOrders, request=request) + + return response + + async def fetch_spot_mid_price_and_tob( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QuerySpotMidPriceAndTOBRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.SpotMidPriceAndTOB, request=request) + + return response + + async def fetch_derivative_mid_price_and_tob( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeMidPriceAndTOBRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.DerivativeMidPriceAndTOB, request=request) + + return response + + async def fetch_derivative_orderbook( + self, + market_id: str, + limit_cumulative_notional: Optional[str] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + limit = None + if pagination is not None: + limit = pagination.limit + request = exchange_query_pb.QueryDerivativeOrderbookRequest( + market_id=market_id, + limit=limit, + limit_cumulative_notional=limit_cumulative_notional, + ) + response = await self._execute_call(call=self._stub.DerivativeOrderbook, request=request) + + return response + + async def fetch_trader_derivative_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderDerivativeOrdersRequest( + market_id=market_id, + subaccount_id=subaccount_id, + ) + response = await self._execute_call(call=self._stub.TraderDerivativeOrders, request=request) + + return response + + async def fetch_account_address_derivative_orders( + self, + market_id: str, + account_address: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryAccountAddressDerivativeOrdersRequest( + market_id=market_id, + account_address=account_address, + ) + response = await self._execute_call(call=self._stub.AccountAddressDerivativeOrders, request=request) + + return response + + async def fetch_derivative_orders_by_hashes( + self, + market_id: str, + subaccount_id: str, + order_hashes: List[str], + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeOrdersByHashesRequest( + market_id=market_id, + subaccount_id=subaccount_id, + order_hashes=order_hashes, + ) + response = await self._execute_call(call=self._stub.DerivativeOrdersByHashes, request=request) + + return response + + async def fetch_trader_derivative_transient_orders( + self, + market_id: str, + subaccount_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderDerivativeOrdersRequest( + market_id=market_id, + subaccount_id=subaccount_id, + ) + response = await self._execute_call(call=self._stub.TraderDerivativeTransientOrders, request=request) + + return response + + async def fetch_derivative_markets( + self, + status: Optional[str] = None, + market_ids: Optional[List[str]] = None, + with_mid_price_and_tob: Optional[bool] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeMarketsRequest( + status=status, + market_ids=market_ids, + with_mid_price_and_tob=with_mid_price_and_tob, + ) + response = await self._execute_call(call=self._stub.DerivativeMarkets, request=request) + + return response + + async def fetch_derivative_market( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeMarketRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.DerivativeMarket, request=request) + + return response + + async def fetch_derivative_market_address( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryDerivativeMarketAddressRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.DerivativeMarketAddress, request=request) + + return response + + async def fetch_subaccount_trade_nonce(self, subaccount_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountTradeNonceRequest(subaccount_id=subaccount_id) + response = await self._execute_call(call=self._stub.SubaccountTradeNonce, request=request) + + return response + + async def fetch_positions(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryPositionsRequest() + response = await self._execute_call(call=self._stub.Positions, request=request) + + return response + + async def fetch_subaccount_positions(self, subaccount_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountPositionsRequest(subaccount_id=subaccount_id) + response = await self._execute_call(call=self._stub.SubaccountPositions, request=request) + + return response + + async def fetch_subaccount_position_in_market(self, subaccount_id: str, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountPositionInMarketRequest( + subaccount_id=subaccount_id, + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.SubaccountPositionInMarket, request=request) + + return response + + async def fetch_subaccount_effective_position_in_market(self, subaccount_id: str, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountEffectivePositionInMarketRequest( + subaccount_id=subaccount_id, + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.SubaccountEffectivePositionInMarket, request=request) + + return response + + async def fetch_perpetual_market_info(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryPerpetualMarketInfoRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.PerpetualMarketInfo, request=request) + + return response + + async def fetch_expiry_futures_market_info(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryExpiryFuturesMarketInfoRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.ExpiryFuturesMarketInfo, request=request) + + return response + + async def fetch_perpetual_market_funding(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryPerpetualMarketFundingRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.PerpetualMarketFunding, request=request) + + return response + + async def fetch_subaccount_order_metadata(self, subaccount_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QuerySubaccountOrderMetadataRequest(subaccount_id=subaccount_id) + response = await self._execute_call(call=self._stub.SubaccountOrderMetadata, request=request) + + return response + + async def fetch_trade_reward_points( + self, + accounts: Optional[List[str]] = None, + pending_pool_timestamp: Optional[int] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTradeRewardPointsRequest( + accounts=accounts, + pending_pool_timestamp=pending_pool_timestamp, + ) + response = await self._execute_call(call=self._stub.TradeRewardPoints, request=request) + + return response + + async def fetch_pending_trade_reward_points( + self, + accounts: Optional[List[str]] = None, + pending_pool_timestamp: Optional[int] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTradeRewardPointsRequest( + accounts=accounts, + pending_pool_timestamp=pending_pool_timestamp, + ) + response = await self._execute_call(call=self._stub.PendingTradeRewardPoints, request=request) + + return response + + async def fetch_fee_discount_account_info( + self, + account: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryFeeDiscountAccountInfoRequest(account=account) + response = await self._execute_call(call=self._stub.FeeDiscountAccountInfo, request=request) + + return response + + async def fetch_fee_discount_schedule(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryFeeDiscountScheduleRequest() + response = await self._execute_call(call=self._stub.FeeDiscountSchedule, request=request) + + return response + + async def fetch_balance_mismatches(self, dust_factor: int) -> Dict[str, Any]: + request = exchange_query_pb.QueryBalanceMismatchesRequest(dust_factor=dust_factor) + response = await self._execute_call(call=self._stub.BalanceMismatches, request=request) + + return response + + async def fetch_balance_with_balance_holds(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryBalanceWithBalanceHoldsRequest() + response = await self._execute_call(call=self._stub.BalanceWithBalanceHolds, request=request) + + return response + + async def fetch_fee_discount_tier_statistics(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryFeeDiscountTierStatisticsRequest() + response = await self._execute_call(call=self._stub.FeeDiscountTierStatistics, request=request) + + return response + + async def fetch_mito_vault_infos(self) -> Dict[str, Any]: + request = exchange_query_pb.MitoVaultInfosRequest() + response = await self._execute_call(call=self._stub.MitoVaultInfos, request=request) + + return response + + async def fetch_market_id_from_vault(self, vault_address: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryMarketIDFromVaultRequest(vault_address=vault_address) + response = await self._execute_call(call=self._stub.QueryMarketIDFromVault, request=request) + + return response + + async def fetch_historical_trade_records(self, market_id: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryHistoricalTradeRecordsRequest(market_id=market_id) + response = await self._execute_call(call=self._stub.HistoricalTradeRecords, request=request) + + return response + + async def fetch_is_opted_out_of_rewards(self, account: str) -> Dict[str, Any]: + request = exchange_query_pb.QueryIsOptedOutOfRewardsRequest(account=account) + response = await self._execute_call(call=self._stub.IsOptedOutOfRewards, request=request) + + return response + + async def fetch_opted_out_of_rewards_accounts(self) -> Dict[str, Any]: + request = exchange_query_pb.QueryOptedOutOfRewardsAccountsRequest() + response = await self._execute_call(call=self._stub.OptedOutOfRewardsAccounts, request=request) + + return response + + async def fetch_market_volatility( + self, + market_id: str, + trade_grouping_sec: Optional[int] = None, + max_age: Optional[int] = None, + include_raw_history: Optional[bool] = None, + include_metadata: Optional[bool] = None, + ) -> Dict[str, Any]: + trade_history_options = exchange_query_pb.TradeHistoryOptions() + if trade_grouping_sec is not None: + trade_history_options.trade_grouping_sec = trade_grouping_sec + if max_age is not None: + trade_history_options.max_age = max_age + if include_raw_history is not None: + trade_history_options.include_raw_history = include_raw_history + if include_metadata is not None: + trade_history_options.include_metadata = include_metadata + request = exchange_query_pb.QueryMarketVolatilityRequest( + market_id=market_id, trade_history_options=trade_history_options + ) + response = await self._execute_call(call=self._stub.MarketVolatility, request=request) + + return response + + async def fetch_binary_options_markets(self, status: Optional[str] = None) -> Dict[str, Any]: + request = exchange_query_pb.QueryBinaryMarketsRequest(status=status) + response = await self._execute_call(call=self._stub.BinaryOptionsMarkets, request=request) + + return response + + async def fetch_trader_derivative_conditional_orders( + self, + subaccount_id: Optional[str] = None, + market_id: Optional[str] = None, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryTraderDerivativeConditionalOrdersRequest( + subaccount_id=subaccount_id, + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.TraderDerivativeConditionalOrders, request=request) + + return response + + async def fetch_market_atomic_execution_fee_multiplier( + self, + market_id: str, + ) -> Dict[str, Any]: + request = exchange_query_pb.QueryMarketAtomicExecutionFeeMultiplierRequest( + market_id=market_id, + ) + response = await self._execute_call(call=self._stub.MarketAtomicExecutionFeeMultiplier, request=request) + + return response + + async def _execute_call(self, call: Callable, request) -> Dict[str, Any]: + return await self._assistant.execute_call(call=call, request=request) diff --git a/tests/client/chain/grpc/configurable_exchange_query_servicer.py b/tests/client/chain/grpc/configurable_exchange_query_servicer.py new file mode 100644 index 00000000..267b08ce --- /dev/null +++ b/tests/client/chain/grpc/configurable_exchange_query_servicer.py @@ -0,0 +1,325 @@ +from collections import deque + +from pyinjective.proto.injective.exchange.v1beta1 import ( + query_pb2 as exchange_query_pb, + query_pb2_grpc as exchange_query_grpc, +) + + +class ConfigurableExchangeQueryServicer(exchange_query_grpc.QueryServicer): + def __init__(self): + super().__init__() + self.exchange_params = deque() + self.subaccount_deposits_responses = deque() + self.subaccount_deposit_responses = deque() + self.exchange_balances_responses = deque() + self.aggregate_volume_responses = deque() + self.aggregate_volumes_responses = deque() + self.aggregate_market_volume_responses = deque() + self.aggregate_market_volumes_responses = deque() + self.denom_decimal_responses = deque() + self.denom_decimals_responses = deque() + self.spot_markets_responses = deque() + self.spot_market_responses = deque() + self.full_spot_markets_responses = deque() + self.full_spot_market_responses = deque() + self.spot_orderbook_responses = deque() + self.trader_spot_orders_responses = deque() + self.account_address_spot_orders_responses = deque() + self.spot_orders_by_hashes_responses = deque() + self.subaccount_orders_responses = deque() + self.trader_spot_transient_orders_responses = deque() + self.spot_mid_price_and_tob_responses = deque() + self.derivative_mid_price_and_tob_responses = deque() + self.derivative_orderbook_responses = deque() + self.trader_derivative_orders_responses = deque() + self.account_address_derivative_orders_responses = deque() + self.derivative_orders_by_hashes_responses = deque() + self.trader_derivative_transient_orders_responses = deque() + self.derivative_markets_responses = deque() + self.derivative_market_responses = deque() + self.derivative_market_address_responses = deque() + self.subaccount_trade_nonce_responses = deque() + self.positions_responses = deque() + self.subaccount_positions_responses = deque() + self.subaccount_position_in_market_responses = deque() + self.subaccount_effective_position_in_market_responses = deque() + self.perpetual_market_info_responses = deque() + self.expiry_futures_market_info_responses = deque() + self.perpetual_market_funding_responses = deque() + self.subaccount_order_metadata_responses = deque() + self.trade_reward_points_responses = deque() + self.pending_trade_reward_points_responses = deque() + self.fee_discount_account_info_responses = deque() + self.fee_discount_schedule_responses = deque() + self.balance_mismatches_responses = deque() + self.balance_with_balance_holds_responses = deque() + self.fee_discount_tier_statistics_responses = deque() + self.mito_vault_infos_responses = deque() + self.market_id_from_vault_responses = deque() + self.historical_trade_records_responses = deque() + self.is_opted_out_of_rewards_responses = deque() + self.opted_out_of_rewards_accounts_responses = deque() + self.market_volatility_responses = deque() + self.binary_options_markets_responses = deque() + self.trader_derivative_conditional_orders_responses = deque() + self.market_atomic_execution_fee_multiplier_responses = deque() + + async def QueryExchangeParams( + self, request: exchange_query_pb.QueryExchangeParamsRequest, context=None, metadata=None + ): + return self.exchange_params.pop() + + async def SubaccountDeposits( + self, request: exchange_query_pb.QuerySubaccountDepositsRequest, context=None, metadata=None + ): + return self.subaccount_deposits_responses.pop() + + async def SubaccountDeposit( + self, request: exchange_query_pb.QuerySubaccountDepositRequest, context=None, metadata=None + ): + return self.subaccount_deposit_responses.pop() + + async def ExchangeBalances( + self, request: exchange_query_pb.QueryExchangeBalancesRequest, context=None, metadata=None + ): + return self.exchange_balances_responses.pop() + + async def AggregateVolume( + self, request: exchange_query_pb.QueryAggregateVolumeRequest, context=None, metadata=None + ): + return self.aggregate_volume_responses.pop() + + async def AggregateVolumes( + self, request: exchange_query_pb.QueryAggregateVolumesRequest, context=None, metadata=None + ): + return self.aggregate_volumes_responses.pop() + + async def AggregateMarketVolume( + self, request: exchange_query_pb.QueryAggregateMarketVolumeRequest, context=None, metadata=None + ): + return self.aggregate_market_volume_responses.pop() + + async def AggregateMarketVolumes( + self, request: exchange_query_pb.QueryAggregateMarketVolumesRequest, context=None, metadata=None + ): + return self.aggregate_market_volumes_responses.pop() + + async def DenomDecimal(self, request: exchange_query_pb.QueryDenomDecimalRequest, context=None, metadata=None): + return self.denom_decimal_responses.pop() + + async def DenomDecimals(self, request: exchange_query_pb.QueryDenomDecimalsRequest, context=None, metadata=None): + return self.denom_decimals_responses.pop() + + async def SpotMarkets(self, request: exchange_query_pb.QuerySpotMarketsRequest, context=None, metadata=None): + return self.spot_markets_responses.pop() + + async def SpotMarket(self, request: exchange_query_pb.QuerySpotMarketRequest, context=None, metadata=None): + return self.spot_market_responses.pop() + + async def FullSpotMarkets( + self, request: exchange_query_pb.QueryFullSpotMarketsRequest, context=None, metadata=None + ): + return self.full_spot_markets_responses.pop() + + async def FullSpotMarket(self, request: exchange_query_pb.QueryFullSpotMarketRequest, context=None, metadata=None): + return self.full_spot_market_responses.pop() + + async def SpotOrderbook(self, request: exchange_query_pb.QuerySpotOrderbookRequest, context=None, metadata=None): + return self.spot_orderbook_responses.pop() + + async def TraderSpotOrders( + self, request: exchange_query_pb.QueryTraderSpotOrdersRequest, context=None, metadata=None + ): + return self.trader_spot_orders_responses.pop() + + async def AccountAddressSpotOrders( + self, request: exchange_query_pb.QueryAccountAddressSpotOrdersRequest, context=None, metadata=None + ): + return self.account_address_spot_orders_responses.pop() + + async def SpotOrdersByHashes( + self, request: exchange_query_pb.QuerySpotOrdersByHashesRequest, context=None, metadata=None + ): + return self.spot_orders_by_hashes_responses.pop() + + async def SubaccountOrders( + self, request: exchange_query_pb.QuerySubaccountOrdersRequest, context=None, metadata=None + ): + return self.subaccount_orders_responses.pop() + + async def TraderSpotTransientOrders( + self, request: exchange_query_pb.QueryTraderSpotOrdersRequest, context=None, metadata=None + ): + return self.trader_spot_transient_orders_responses.pop() + + async def SpotMidPriceAndTOB( + self, request: exchange_query_pb.QuerySpotMidPriceAndTOBRequest, context=None, metadata=None + ): + return self.spot_mid_price_and_tob_responses.pop() + + async def DerivativeMidPriceAndTOB( + self, request: exchange_query_pb.QueryDerivativeMidPriceAndTOBRequest, context=None, metadata=None + ): + return self.derivative_mid_price_and_tob_responses.pop() + + async def DerivativeOrderbook( + self, request: exchange_query_pb.QueryDerivativeOrderbookRequest, context=None, metadata=None + ): + return self.derivative_orderbook_responses.pop() + + async def TraderDerivativeOrders( + self, request: exchange_query_pb.QueryTraderDerivativeOrdersRequest, context=None, metadata=None + ): + return self.trader_derivative_orders_responses.pop() + + async def AccountAddressDerivativeOrders( + self, request: exchange_query_pb.QueryAccountAddressDerivativeOrdersRequest, context=None, metadata=None + ): + return self.account_address_derivative_orders_responses.pop() + + async def DerivativeOrdersByHashes( + self, request: exchange_query_pb.QueryDerivativeOrdersByHashesRequest, context=None, metadata=None + ): + return self.derivative_orders_by_hashes_responses.pop() + + async def TraderDerivativeTransientOrders( + self, request: exchange_query_pb.QueryTraderDerivativeOrdersRequest, context=None, metadata=None + ): + return self.trader_derivative_transient_orders_responses.pop() + + async def DerivativeMarkets( + self, request: exchange_query_pb.QueryDerivativeMarketsRequest, context=None, metadata=None + ): + return self.derivative_markets_responses.pop() + + async def DerivativeMarket( + self, request: exchange_query_pb.QueryDerivativeMarketRequest, context=None, metadata=None + ): + return self.derivative_market_responses.pop() + + async def DerivativeMarketAddress( + self, request: exchange_query_pb.QueryDerivativeMarketAddressRequest, context=None, metadata=None + ): + return self.derivative_market_address_responses.pop() + + async def SubaccountTradeNonce( + self, request: exchange_query_pb.QuerySubaccountTradeNonceRequest, context=None, metadata=None + ): + return self.subaccount_trade_nonce_responses.pop() + + async def Positions(self, request: exchange_query_pb.QueryPositionsRequest, context=None, metadata=None): + return self.positions_responses.pop() + + async def SubaccountPositions( + self, request: exchange_query_pb.QuerySubaccountPositionsRequest, context=None, metadata=None + ): + return self.subaccount_positions_responses.pop() + + async def SubaccountPositionInMarket( + self, request: exchange_query_pb.QuerySubaccountPositionInMarketRequest, context=None, metadata=None + ): + return self.subaccount_position_in_market_responses.pop() + + async def SubaccountEffectivePositionInMarket( + self, request: exchange_query_pb.QuerySubaccountEffectivePositionInMarketRequest, context=None, metadata=None + ): + return self.subaccount_effective_position_in_market_responses.pop() + + async def PerpetualMarketInfo( + self, request: exchange_query_pb.QueryPerpetualMarketInfoRequest, context=None, metadata=None + ): + return self.perpetual_market_info_responses.pop() + + async def ExpiryFuturesMarketInfo( + self, request: exchange_query_pb.QueryExpiryFuturesMarketInfoRequest, context=None, metadata=None + ): + return self.expiry_futures_market_info_responses.pop() + + async def PerpetualMarketFunding( + self, request: exchange_query_pb.QueryPerpetualMarketFundingRequest, context=None, metadata=None + ): + return self.perpetual_market_funding_responses.pop() + + async def SubaccountOrderMetadata( + self, request: exchange_query_pb.QuerySubaccountOrderMetadataRequest, context=None, metadata=None + ): + return self.subaccount_order_metadata_responses.pop() + + async def TradeRewardPoints( + self, request: exchange_query_pb.QueryTradeRewardPointsRequest, context=None, metadata=None + ): + return self.trade_reward_points_responses.pop() + + async def PendingTradeRewardPoints( + self, request: exchange_query_pb.QueryTradeRewardPointsRequest, context=None, metadata=None + ): + return self.pending_trade_reward_points_responses.pop() + + async def FeeDiscountAccountInfo( + self, request: exchange_query_pb.QueryFeeDiscountAccountInfoRequest, context=None, metadata=None + ): + return self.fee_discount_account_info_responses.pop() + + async def FeeDiscountSchedule( + self, request: exchange_query_pb.QueryFeeDiscountScheduleRequest, context=None, metadata=None + ): + return self.fee_discount_schedule_responses.pop() + + async def BalanceMismatches( + self, request: exchange_query_pb.QueryBalanceMismatchesRequest, context=None, metadata=None + ): + return self.balance_mismatches_responses.pop() + + async def BalanceWithBalanceHolds( + self, request: exchange_query_pb.QueryBalanceWithBalanceHoldsRequest, context=None, metadata=None + ): + return self.balance_with_balance_holds_responses.pop() + + async def FeeDiscountTierStatistics( + self, request: exchange_query_pb.QueryFeeDiscountTierStatisticsRequest, context=None, metadata=None + ): + return self.fee_discount_tier_statistics_responses.pop() + + async def MitoVaultInfos(self, request: exchange_query_pb.MitoVaultInfosRequest, context=None, metadata=None): + return self.mito_vault_infos_responses.pop() + + async def QueryMarketIDFromVault( + self, request: exchange_query_pb.QueryMarketIDFromVaultRequest, context=None, metadata=None + ): + return self.market_id_from_vault_responses.pop() + + async def HistoricalTradeRecords( + self, request: exchange_query_pb.QueryHistoricalTradeRecordsRequest, context=None, metadata=None + ): + return self.historical_trade_records_responses.pop() + + async def IsOptedOutOfRewards( + self, request: exchange_query_pb.QueryIsOptedOutOfRewardsRequest, context=None, metadata=None + ): + return self.is_opted_out_of_rewards_responses.pop() + + async def OptedOutOfRewardsAccounts( + self, request: exchange_query_pb.QueryOptedOutOfRewardsAccountsRequest, context=None, metadata=None + ): + return self.opted_out_of_rewards_accounts_responses.pop() + + async def MarketVolatility( + self, request: exchange_query_pb.QueryMarketVolatilityRequest, context=None, metadata=None + ): + return self.market_volatility_responses.pop() + + async def BinaryOptionsMarkets( + self, request: exchange_query_pb.QueryBinaryMarketsRequest, context=None, metadata=None + ): + return self.binary_options_markets_responses.pop() + + async def TraderDerivativeConditionalOrders( + self, request: exchange_query_pb.QueryTraderDerivativeConditionalOrdersRequest, context=None, metadata=None + ): + return self.trader_derivative_conditional_orders_responses.pop() + + async def MarketAtomicExecutionFeeMultiplier( + self, request: exchange_query_pb.QueryMarketAtomicExecutionFeeMultiplierRequest, context=None, metadata=None + ): + return self.market_atomic_execution_fee_multiplier_responses.pop() diff --git a/tests/client/chain/grpc/test_chain_grpc_exchange_api.py b/tests/client/chain/grpc/test_chain_grpc_exchange_api.py new file mode 100644 index 00000000..54393a94 --- /dev/null +++ b/tests/client/chain/grpc/test_chain_grpc_exchange_api.py @@ -0,0 +1,2466 @@ +import base64 + +import grpc +import pytest + +from pyinjective.client.chain.grpc.chain_grpc_exchange_api import ChainGrpcExchangeApi +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.core.network import Network +from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as coin_pb +from pyinjective.proto.injective.exchange.v1beta1 import ( + exchange_pb2 as exchange_pb, + genesis_pb2 as genesis_pb, + query_pb2 as exchange_query_pb, +) +from pyinjective.proto.injective.oracle.v1beta1 import oracle_pb2 as oracle_pb +from tests.client.chain.grpc.configurable_exchange_query_servicer import ConfigurableExchangeQueryServicer + + +@pytest.fixture +def exchange_servicer(): + return ConfigurableExchangeQueryServicer() + + +class TestChainGrpcBankApi: + @pytest.mark.asyncio + async def test_fetch_exchange_params( + self, + exchange_servicer, + ): + spot_market_instant_listing_fee = coin_pb.Coin(denom="inj", amount="10000000000000000000") + derivative_market_instant_listing_fee = coin_pb.Coin(denom="inj", amount="2000000000000000000000") + binary_options_market_instant_listing_fee = coin_pb.Coin(denom="inj", amount="30000000000000000000") + params = exchange_pb.Params( + spot_market_instant_listing_fee=spot_market_instant_listing_fee, + derivative_market_instant_listing_fee=derivative_market_instant_listing_fee, + default_spot_maker_fee_rate="-0.000100000000000000", + default_spot_taker_fee_rate="0.001000000000000000", + default_derivative_maker_fee_rate="-0.000100000000000000", + default_derivative_taker_fee_rate="0.001000000000000000", + default_initial_margin_ratio="0.050000000000000000", + default_maintenance_margin_ratio="0.020000000000000000", + default_funding_interval=3600, + funding_multiple=4600, + relayer_fee_share_rate="0.400000000000000000", + default_hourly_funding_rate_cap="0.000625000000000000", + default_hourly_interest_rate="0.000004166660000000", + max_derivative_order_side_count=20, + inj_reward_staked_requirement_threshold="25000000000000000000", + trading_rewards_vesting_duration=1209600, + liquidator_reward_share_rate="0.050000000000000000", + binary_options_market_instant_listing_fee=binary_options_market_instant_listing_fee, + atomic_market_order_access_level=2, + spot_atomic_market_order_fee_multiplier="2.000000000000000000", + derivative_atomic_market_order_fee_multiplier="2.000000000000000000", + binary_options_atomic_market_order_fee_multiplier="2.000000000000000000", + minimal_protocol_fee_rate="0.000010000000000000", + is_instant_derivative_market_launch_enabled=False, + post_only_mode_height_threshold=57078000, + ) + exchange_servicer.exchange_params.append(exchange_query_pb.QueryExchangeParamsResponse(params=params)) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + module_params = await api.fetch_exchange_params() + expected_params = { + "params": { + "spotMarketInstantListingFee": { + "amount": spot_market_instant_listing_fee.amount, + "denom": spot_market_instant_listing_fee.denom, + }, + "derivativeMarketInstantListingFee": { + "amount": derivative_market_instant_listing_fee.amount, + "denom": derivative_market_instant_listing_fee.denom, + }, + "defaultSpotMakerFeeRate": params.default_spot_maker_fee_rate, + "defaultSpotTakerFeeRate": params.default_spot_taker_fee_rate, + "defaultDerivativeMakerFeeRate": params.default_derivative_maker_fee_rate, + "defaultDerivativeTakerFeeRate": params.default_derivative_taker_fee_rate, + "defaultInitialMarginRatio": params.default_initial_margin_ratio, + "defaultMaintenanceMarginRatio": params.default_maintenance_margin_ratio, + "defaultFundingInterval": str(params.default_funding_interval), + "fundingMultiple": str(params.funding_multiple), + "relayerFeeShareRate": params.relayer_fee_share_rate, + "defaultHourlyFundingRateCap": params.default_hourly_funding_rate_cap, + "defaultHourlyInterestRate": params.default_hourly_interest_rate, + "maxDerivativeOrderSideCount": params.max_derivative_order_side_count, + "injRewardStakedRequirementThreshold": params.inj_reward_staked_requirement_threshold, + "tradingRewardsVestingDuration": str(params.trading_rewards_vesting_duration), + "liquidatorRewardShareRate": "0.050000000000000000", + "binaryOptionsMarketInstantListingFee": { + "amount": binary_options_market_instant_listing_fee.amount, + "denom": binary_options_market_instant_listing_fee.denom, + }, + "atomicMarketOrderAccessLevel": exchange_pb.AtomicMarketOrderAccessLevel.Name( + params.atomic_market_order_access_level + ), + "spotAtomicMarketOrderFeeMultiplier": params.spot_atomic_market_order_fee_multiplier, + "derivativeAtomicMarketOrderFeeMultiplier": params.derivative_atomic_market_order_fee_multiplier, + "binaryOptionsAtomicMarketOrderFeeMultiplier": params.binary_options_atomic_market_order_fee_multiplier, + "minimalProtocolFeeRate": params.minimal_protocol_fee_rate, + "isInstantDerivativeMarketLaunchEnabled": params.is_instant_derivative_market_launch_enabled, + "postOnlyModeHeightThreshold": str(params.post_only_mode_height_threshold), + } + } + + assert module_params == expected_params + + @pytest.mark.asyncio + async def test_fetch_subaccount_deposits( + self, + exchange_servicer, + ): + deposit_denom = "inj" + deposit = exchange_pb.Deposit( + available_balance="1000000000000000000", + total_balance="2000000000000000000", + ) + exchange_servicer.subaccount_deposits_responses.append( + exchange_query_pb.QuerySubaccountDepositsResponse(deposits={deposit_denom: deposit}) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + deposits = await api.fetch_subaccount_deposits( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + subaccount_trader="inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7", + subaccount_nonce=1, + ) + expected_deposits = { + "deposits": { + deposit_denom: { + "availableBalance": deposit.available_balance, + "totalBalance": deposit.total_balance, + }, + } + } + + assert deposits == expected_deposits + + @pytest.mark.asyncio + async def test_fetch_subaccount_deposit( + self, + exchange_servicer, + ): + deposit = exchange_pb.Deposit( + available_balance="1000000000000000000", + total_balance="2000000000000000000", + ) + exchange_servicer.subaccount_deposit_responses.append( + exchange_query_pb.QuerySubaccountDepositResponse(deposits=deposit) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + deposit_response = await api.fetch_subaccount_deposit( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + denom="inj", + ) + expected_deposit = { + "deposits": { + "availableBalance": deposit.available_balance, + "totalBalance": deposit.total_balance, + } + } + + assert deposit_response == expected_deposit + + @pytest.mark.asyncio + async def test_fetch_exchange_balances( + self, + exchange_servicer, + ): + deposit = exchange_pb.Deposit( + available_balance="1000000000000000000", + total_balance="2000000000000000000", + ) + balance = genesis_pb.Balance( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + denom="inj", + deposits=deposit, + ) + exchange_servicer.exchange_balances_responses.append( + exchange_query_pb.QueryExchangeBalancesResponse(balances=[balance]) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + balances_response = await api.fetch_exchange_balances() + expected_balances = { + "balances": [ + { + "subaccountId": balance.subaccount_id, + "denom": balance.denom, + "deposits": { + "availableBalance": deposit.available_balance, + "totalBalance": deposit.total_balance, + }, + }, + ] + } + + assert balances_response == expected_balances + + @pytest.mark.asyncio + async def test_fetch_aggregate_volume( + self, + exchange_servicer, + ): + volume = exchange_pb.VolumeRecord( + maker_volume="1000000000000000000", + taker_volume="2000000000000000000", + ) + market_volume = exchange_pb.MarketVolume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + volume=volume, + ) + exchange_servicer.aggregate_volume_responses.append( + exchange_query_pb.QueryAggregateVolumeResponse( + aggregate_volumes=[market_volume], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volume_response = await api.fetch_aggregate_volume(account="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r") + expected_volume = { + "aggregateVolumes": [ + { + "marketId": market_volume.market_id, + "volume": { + "makerVolume": volume.maker_volume, + "takerVolume": volume.taker_volume, + }, + }, + ] + } + + assert volume_response == expected_volume + + @pytest.mark.asyncio + async def test_fetch_aggregate_volumes( + self, + exchange_servicer, + ): + acc_volume = exchange_pb.VolumeRecord( + maker_volume="1000000000000000000", + taker_volume="2000000000000000000", + ) + account_market_volume = exchange_pb.MarketVolume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + volume=acc_volume, + ) + account_volume = exchange_pb.AggregateAccountVolumeRecord( + account="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + market_volumes=[account_market_volume], + ) + volume = exchange_pb.VolumeRecord( + maker_volume="3000000000000000000", + taker_volume="4000000000000000000", + ) + market_volume = exchange_pb.MarketVolume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + volume=volume, + ) + exchange_servicer.aggregate_volumes_responses.append( + exchange_query_pb.QueryAggregateVolumesResponse( + aggregate_account_volumes=[account_volume], + aggregate_market_volumes=[market_volume], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volume_response = await api.fetch_aggregate_volumes( + accounts=[account_volume.account], + market_ids=[account_market_volume.market_id], + ) + expected_volume = { + "aggregateAccountVolumes": [ + { + "account": account_volume.account, + "marketVolumes": [ + { + "marketId": account_market_volume.market_id, + "volume": { + "makerVolume": acc_volume.maker_volume, + "takerVolume": acc_volume.taker_volume, + }, + }, + ], + }, + ], + "aggregateMarketVolumes": [ + { + "marketId": market_volume.market_id, + "volume": { + "makerVolume": volume.maker_volume, + "takerVolume": volume.taker_volume, + }, + }, + ], + } + + assert volume_response == expected_volume + + @pytest.mark.asyncio + async def test_fetch_aggregate_market_volume( + self, + exchange_servicer, + ): + volume = exchange_pb.VolumeRecord( + maker_volume="1000000000000000000", + taker_volume="2000000000000000000", + ) + exchange_servicer.aggregate_market_volume_responses.append( + exchange_query_pb.QueryAggregateMarketVolumeResponse( + volume=volume, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volume_response = await api.fetch_aggregate_market_volume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" + ) + expected_volume = { + "volume": { + "makerVolume": volume.maker_volume, + "takerVolume": volume.taker_volume, + } + } + + assert volume_response == expected_volume + + @pytest.mark.asyncio + async def test_fetch_aggregate_market_volumes( + self, + exchange_servicer, + ): + volume = exchange_pb.VolumeRecord( + maker_volume="3000000000000000000", + taker_volume="4000000000000000000", + ) + market_volume = exchange_pb.MarketVolume( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + volume=volume, + ) + exchange_servicer.aggregate_market_volumes_responses.append( + exchange_query_pb.QueryAggregateMarketVolumesResponse( + volumes=[market_volume], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volume_response = await api.fetch_aggregate_market_volumes( + market_ids=[market_volume.market_id], + ) + expected_volume = { + "volumes": [ + { + "marketId": market_volume.market_id, + "volume": { + "makerVolume": volume.maker_volume, + "takerVolume": volume.taker_volume, + }, + }, + ], + } + + assert volume_response == expected_volume + + @pytest.mark.asyncio + async def test_fetch_denom_decimal( + self, + exchange_servicer, + ): + decimal = 18 + exchange_servicer.denom_decimal_responses.append( + exchange_query_pb.QueryDenomDecimalResponse( + decimal=decimal, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + denom_decimal = await api.fetch_denom_decimal(denom="inj") + expected_decimal = {"decimal": str(decimal)} + + assert denom_decimal == expected_decimal + + @pytest.mark.asyncio + async def test_fetch_denom_decimals( + self, + exchange_servicer, + ): + denom_decimal = exchange_pb.DenomDecimals( + denom="inj", + decimals=18, + ) + exchange_servicer.denom_decimals_responses.append( + exchange_query_pb.QueryDenomDecimalsResponse( + denom_decimals=[denom_decimal], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + denom_decimals = await api.fetch_denom_decimals(denoms=[denom_decimal.denom]) + expected_decimals = { + "denomDecimals": [ + { + "denom": denom_decimal.denom, + "decimals": str(denom_decimal.decimals), + } + ] + } + + assert denom_decimals == expected_decimals + + @pytest.mark.asyncio + async def test_fetch_spot_markets( + self, + exchange_servicer, + ): + market = exchange_pb.SpotMarket( + ticker="INJ/USDT", + base_denom="inj", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="0.4", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + status=1, + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + exchange_servicer.spot_markets_responses.append( + exchange_query_pb.QuerySpotMarketsResponse( + markets=[market], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + markets = await api.fetch_spot_markets( + status=status_string, + market_ids=[market.market_id], + ) + expected_markets = { + "markets": [ + { + "ticker": market.ticker, + "baseDenom": market.base_denom, + "quoteDenom": market.quote_denom, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "marketId": market.market_id, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + } + ] + } + + assert markets == expected_markets + + @pytest.mark.asyncio + async def test_fetch_spot_market( + self, + exchange_servicer, + ): + market = exchange_pb.SpotMarket( + ticker="INJ/USDT", + base_denom="inj", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="0.4", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + status=1, + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + exchange_servicer.spot_market_responses.append( + exchange_query_pb.QuerySpotMarketResponse( + market=market, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + response_market = await api.fetch_spot_market( + market_id=market.market_id, + ) + expected_market = { + "market": { + "ticker": market.ticker, + "baseDenom": market.base_denom, + "quoteDenom": market.quote_denom, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "marketId": market.market_id, + "status": exchange_pb.MarketStatus.Name(market.status), + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + } + } + + assert response_market == expected_market + + @pytest.mark.asyncio + async def test_fetch_full_spot_markets( + self, + exchange_servicer, + ): + market = exchange_pb.SpotMarket( + ticker="INJ/USDT", + base_denom="inj", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="0.4", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + status=1, + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + mid_price_and_tob = exchange_pb.MidPriceAndTOB( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + full_market = exchange_query_pb.FullSpotMarket( + market=market, + mid_price_and_tob=mid_price_and_tob, + ) + exchange_servicer.full_spot_markets_responses.append( + exchange_query_pb.QueryFullSpotMarketsResponse( + markets=[full_market], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + markets = await api.fetch_full_spot_markets( + status=status_string, + market_ids=[market.market_id], + with_mid_price_and_tob=True, + ) + expected_markets = { + "markets": [ + { + "market": { + "ticker": market.ticker, + "baseDenom": market.base_denom, + "quoteDenom": market.quote_denom, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "marketId": market.market_id, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + }, + "midPriceAndTob": { + "midPrice": mid_price_and_tob.mid_price, + "bestBuyPrice": mid_price_and_tob.best_buy_price, + "bestSellPrice": mid_price_and_tob.best_sell_price, + }, + } + ] + } + + assert markets == expected_markets + + @pytest.mark.asyncio + async def test_fetch_full_spot_market( + self, + exchange_servicer, + ): + market = exchange_pb.SpotMarket( + ticker="INJ/USDT", + base_denom="inj", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="0.4", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + status=1, + min_price_tick_size="0.000000000000001", + min_quantity_tick_size="1000000000000000", + ) + mid_price_and_tob = exchange_pb.MidPriceAndTOB( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + full_market = exchange_query_pb.FullSpotMarket( + market=market, + mid_price_and_tob=mid_price_and_tob, + ) + exchange_servicer.full_spot_market_responses.append( + exchange_query_pb.QueryFullSpotMarketResponse( + market=full_market, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + market_response = await api.fetch_full_spot_market( + market_id=market.market_id, + with_mid_price_and_tob=True, + ) + expected_market = { + "market": { + "market": { + "ticker": market.ticker, + "baseDenom": market.base_denom, + "quoteDenom": market.quote_denom, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "marketId": market.market_id, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + }, + "midPriceAndTob": { + "midPrice": mid_price_and_tob.mid_price, + "bestBuyPrice": mid_price_and_tob.best_buy_price, + "bestSellPrice": mid_price_and_tob.best_sell_price, + }, + } + } + + assert market_response == expected_market + + @pytest.mark.asyncio + async def test_fetch_spot_orderbook( + self, + exchange_servicer, + ): + buy_price_level = exchange_pb.Level( + p="1000000000000000000", + q="1000000000000000", + ) + sell_price_level = exchange_pb.Level( + p="2000000000000000000", + q="2000000000000000", + ) + exchange_servicer.spot_orderbook_responses.append( + exchange_query_pb.QuerySpotOrderbookResponse( + buys_price_level=[buy_price_level], + sells_price_level=[sell_price_level], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orderbook = await api.fetch_spot_orderbook( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + order_side="Side_Unspecified", + limit_cumulative_notional="1000000000000000000", + limit_cumulative_quantity="1000000000000000", + pagination=PaginationOption(limit=100), + ) + expected_orderbook = { + "buysPriceLevel": [ + { + "p": buy_price_level.p, + "q": buy_price_level.q, + } + ], + "sellsPriceLevel": [ + { + "p": sell_price_level.p, + "q": sell_price_level.q, + } + ], + } + + assert orderbook == expected_orderbook + + @pytest.mark.asyncio + async def test_fetch_trader_spot_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedSpotLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.trader_spot_orders_responses.append( + exchange_query_pb.QueryTraderSpotOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_spot_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_account_address_spot_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedSpotLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.account_address_spot_orders_responses.append( + exchange_query_pb.QueryAccountAddressSpotOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_account_address_spot_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + account_address="inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_spot_orders_by_hashes( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedSpotLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.spot_orders_by_hashes_responses.append( + exchange_query_pb.QuerySpotOrdersByHashesResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_spot_orders_by_hashes( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + order_hashes=[order.order_hash], + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_subaccount_orders( + self, + exchange_servicer, + ): + buy_subaccount_order = exchange_pb.SubaccountOrder( + price="1000000000000000000", + quantity="1000000000000000", + isReduceOnly=False, + ) + buy_order = exchange_pb.SubaccountOrderData( + order=buy_subaccount_order, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849".encode(), + ) + sell_subaccount_order = exchange_pb.SubaccountOrder( + price="2000000000000000000", + quantity="2000000000000000", + isReduceOnly=False, + ) + sell_order = exchange_pb.SubaccountOrderData( + order=sell_subaccount_order, + order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2".encode(), + ) + exchange_servicer.subaccount_orders_responses.append( + exchange_query_pb.QuerySubaccountOrdersResponse( + buy_orders=[buy_order], + sell_orders=[sell_order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_subaccount_orders( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + expected_orders = { + "buyOrders": [ + { + "order": { + "price": buy_subaccount_order.price, + "quantity": buy_subaccount_order.quantity, + "isReduceOnly": buy_subaccount_order.isReduceOnly, + }, + "orderHash": base64.b64encode(buy_order.order_hash).decode(), + } + ], + "sellOrders": [ + { + "order": { + "price": sell_subaccount_order.price, + "quantity": sell_subaccount_order.quantity, + "isReduceOnly": sell_subaccount_order.isReduceOnly, + }, + "orderHash": base64.b64encode(sell_order.order_hash).decode(), + } + ], + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_trader_spot_transient_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedSpotLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.trader_spot_transient_orders_responses.append( + exchange_query_pb.QueryTraderSpotOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_spot_transient_orders( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_spot_mid_price_and_tob( + self, + exchange_servicer, + ): + response = exchange_query_pb.QuerySpotMidPriceAndTOBResponse( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + exchange_servicer.spot_mid_price_and_tob_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + prices = await api.fetch_spot_mid_price_and_tob( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + expected_prices = { + "midPrice": response.mid_price, + "bestBuyPrice": response.best_buy_price, + "bestSellPrice": response.best_sell_price, + } + + assert prices == expected_prices + + @pytest.mark.asyncio + async def test_fetch_derivative_mid_price_and_tob( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryDerivativeMidPriceAndTOBResponse( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + exchange_servicer.derivative_mid_price_and_tob_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + prices = await api.fetch_derivative_mid_price_and_tob( + market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe", + ) + expected_prices = { + "midPrice": response.mid_price, + "bestBuyPrice": response.best_buy_price, + "bestSellPrice": response.best_sell_price, + } + + assert prices == expected_prices + + @pytest.mark.asyncio + async def test_fetch_derivative_orderbook( + self, + exchange_servicer, + ): + buy_price_level = exchange_pb.Level( + p="1000000000000000000", + q="1000000000000000", + ) + sell_price_level = exchange_pb.Level( + p="2000000000000000000", + q="2000000000000000", + ) + exchange_servicer.derivative_orderbook_responses.append( + exchange_query_pb.QueryDerivativeOrderbookResponse( + buys_price_level=[buy_price_level], + sells_price_level=[sell_price_level], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orderbook = await api.fetch_derivative_orderbook( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + limit_cumulative_notional="1000000000000000000", + pagination=PaginationOption(limit=100), + ) + expected_orderbook = { + "buysPriceLevel": [ + { + "p": buy_price_level.p, + "q": buy_price_level.q, + } + ], + "sellsPriceLevel": [ + { + "p": sell_price_level.p, + "q": sell_price_level.q, + } + ], + } + + assert orderbook == expected_orderbook + + @pytest.mark.asyncio + async def test_fetch_trader_derivative_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + margin="1000000000000000000000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.trader_derivative_orders_responses.append( + exchange_query_pb.QueryTraderDerivativeOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_derivative_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_account_address_derivative_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + margin="1000000000000000000000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.account_address_derivative_orders_responses.append( + exchange_query_pb.QueryAccountAddressDerivativeOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_account_address_derivative_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + account_address="inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_derivative_orders_by_hashes( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + margin="1000000000000000000000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.derivative_orders_by_hashes_responses.append( + exchange_query_pb.QueryDerivativeOrdersByHashesResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_derivative_orders_by_hashes( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + order_hashes=[order.order_hash], + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_trader_derivative_transient_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeLimitOrder( + price="1000000000000000000", + quantity="1000000000000000", + margin="1000000000000000000000000000000000", + fillable="1000000000000000", + isBuy=True, + order_hash="0x14e43adbb3302db28bcd0619068227ebca880cdd66cdfc8b4a662bcac0777849", + ) + exchange_servicer.trader_derivative_transient_orders_responses.append( + exchange_query_pb.QueryTraderDerivativeOrdersResponse( + orders=[order], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_derivative_transient_orders( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "fillable": order.fillable, + "isBuy": order.isBuy, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_derivative_markets( + self, + exchange_servicer, + ): + market = exchange_pb.DerivativeMarket( + ticker="20250608/USDT", + oracle_base="0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3", + oracle_quote="0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588", + oracle_type=9, + oracle_scale_factor=6, + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + initial_margin_ratio="50000000000000000", + maintenance_margin_ratio="20000000000000000", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="400000000000000000", + isPerpetual=True, + status=1, + min_price_tick_size="100000000000000000000", + min_quantity_tick_size="1000000000000000", + ) + market_info = exchange_pb.PerpetualMarketInfo( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + hourly_funding_rate_cap="625000000000000", + hourly_interest_rate="4166660000000", + next_funding_timestamp=1708099200, + funding_interval=3600, + ) + funding_info = exchange_pb.PerpetualMarketFunding( + cumulative_funding="-107853477278881692857461", + cumulative_price="0", + last_timestamp=1708099200, + ) + perpetual_info = exchange_query_pb.PerpetualMarketState( + market_info=market_info, + funding_info=funding_info, + ) + mid_price_and_tob = exchange_pb.MidPriceAndTOB( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + full_market = exchange_query_pb.FullDerivativeMarket( + market=market, + perpetual_info=perpetual_info, + mark_price="33803835513327368963000000", + mid_price_and_tob=mid_price_and_tob, + ) + exchange_servicer.derivative_markets_responses.append( + exchange_query_pb.QueryDerivativeMarketsResponse( + markets=[full_market], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + markets = await api.fetch_derivative_markets( + status=status_string, + market_ids=[market.market_id], + ) + expected_markets = { + "markets": [ + { + "market": { + "ticker": market.ticker, + "oracleBase": market.oracle_base, + "oracleQuote": market.oracle_quote, + "oracleType": oracle_pb.OracleType.Name(market.oracle_type), + "oracleScaleFactor": market.oracle_scale_factor, + "quoteDenom": market.quote_denom, + "marketId": market.market_id, + "initialMarginRatio": market.initial_margin_ratio, + "maintenanceMarginRatio": market.maintenance_margin_ratio, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "isPerpetual": market.isPerpetual, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + }, + "perpetualInfo": { + "marketInfo": { + "marketId": market_info.market_id, + "hourlyFundingRateCap": market_info.hourly_funding_rate_cap, + "hourlyInterestRate": market_info.hourly_interest_rate, + "nextFundingTimestamp": str(market_info.next_funding_timestamp), + "fundingInterval": str(market_info.funding_interval), + }, + "fundingInfo": { + "cumulativeFunding": funding_info.cumulative_funding, + "cumulativePrice": funding_info.cumulative_price, + "lastTimestamp": str(funding_info.last_timestamp), + }, + }, + "markPrice": full_market.mark_price, + "midPriceAndTob": { + "midPrice": mid_price_and_tob.mid_price, + "bestBuyPrice": mid_price_and_tob.best_buy_price, + "bestSellPrice": mid_price_and_tob.best_sell_price, + }, + } + ] + } + + assert markets == expected_markets + + @pytest.mark.asyncio + async def test_fetch_derivative_market( + self, + exchange_servicer, + ): + market = exchange_pb.DerivativeMarket( + ticker="INJ/USDT PERP", + oracle_base="0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3", + oracle_quote="0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588", + oracle_type=9, + oracle_scale_factor=6, + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + initial_margin_ratio="50000000000000000", + maintenance_margin_ratio="20000000000000000", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="400000000000000000", + isPerpetual=True, + status=1, + min_price_tick_size="100000000000000000000", + min_quantity_tick_size="1000000000000000", + ) + market_info = exchange_pb.PerpetualMarketInfo( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + hourly_funding_rate_cap="625000000000000", + hourly_interest_rate="4166660000000", + next_funding_timestamp=1708099200, + funding_interval=3600, + ) + funding_info = exchange_pb.PerpetualMarketFunding( + cumulative_funding="-107853477278881692857461", + cumulative_price="0", + last_timestamp=1708099200, + ) + perpetual_info = exchange_query_pb.PerpetualMarketState( + market_info=market_info, + funding_info=funding_info, + ) + mid_price_and_tob = exchange_pb.MidPriceAndTOB( + mid_price="2000000000000000000", + best_buy_price="1000000000000000000", + best_sell_price="3000000000000000000", + ) + full_market = exchange_query_pb.FullDerivativeMarket( + market=market, + perpetual_info=perpetual_info, + mark_price="33803835513327368963000000", + mid_price_and_tob=mid_price_and_tob, + ) + exchange_servicer.derivative_market_responses.append( + exchange_query_pb.QueryDerivativeMarketResponse( + market=full_market, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + status_string = exchange_pb.MarketStatus.Name(market.status) + market_response = await api.fetch_derivative_market( + market_id=market.market_id, + ) + expected_market = { + "market": { + "market": { + "ticker": market.ticker, + "oracleBase": market.oracle_base, + "oracleQuote": market.oracle_quote, + "oracleType": oracle_pb.OracleType.Name(market.oracle_type), + "oracleScaleFactor": market.oracle_scale_factor, + "quoteDenom": market.quote_denom, + "marketId": market.market_id, + "initialMarginRatio": market.initial_margin_ratio, + "maintenanceMarginRatio": market.maintenance_margin_ratio, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "isPerpetual": market.isPerpetual, + "status": status_string, + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + }, + "perpetualInfo": { + "marketInfo": { + "marketId": market_info.market_id, + "hourlyFundingRateCap": market_info.hourly_funding_rate_cap, + "hourlyInterestRate": market_info.hourly_interest_rate, + "nextFundingTimestamp": str(market_info.next_funding_timestamp), + "fundingInterval": str(market_info.funding_interval), + }, + "fundingInfo": { + "cumulativeFunding": funding_info.cumulative_funding, + "cumulativePrice": funding_info.cumulative_price, + "lastTimestamp": str(funding_info.last_timestamp), + }, + }, + "markPrice": full_market.mark_price, + "midPriceAndTob": { + "midPrice": mid_price_and_tob.mid_price, + "bestBuyPrice": mid_price_and_tob.best_buy_price, + "bestSellPrice": mid_price_and_tob.best_sell_price, + }, + } + } + + assert market_response == expected_market + + @pytest.mark.asyncio + async def test_fetch_derivative_market_address( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryDerivativeMarketAddressResponse( + address="inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9", + subaccount_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000", + ) + exchange_servicer.derivative_market_address_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + address = await api.fetch_derivative_market_address( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + expected_address = { + "address": response.address, + "subaccountId": response.subaccount_id, + } + + assert address == expected_address + + @pytest.mark.asyncio + async def test_fetch_subaccount_trade_nonce( + self, + exchange_servicer, + ): + response = exchange_query_pb.QuerySubaccountTradeNonceResponse(nonce=1234567879) + exchange_servicer.subaccount_trade_nonce_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + nonce = await api.fetch_subaccount_trade_nonce( + subaccount_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000", + ) + expected_nonce = { + "nonce": response.nonce, + } + + assert nonce == expected_nonce + + @pytest.mark.asyncio + async def test_fetch_positions( + self, + exchange_servicer, + ): + position = exchange_pb.Position( + isLong=True, + quantity="1000000000000000", + entry_price="2000000000000000000", + margin="2000000000000000000000000000000000", + cumulative_funding_entry="4000000", + ) + derivative_position = genesis_pb.DerivativePosition( + subaccount_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + position=position, + ) + exchange_servicer.positions_responses.append( + exchange_query_pb.QueryPositionsResponse(state=[derivative_position]) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + positions = await api.fetch_positions() + expected_positions = { + "state": [ + { + "subaccountId": derivative_position.subaccount_id, + "marketId": derivative_position.market_id, + "position": { + "isLong": position.isLong, + "quantity": position.quantity, + "entryPrice": position.entry_price, + "margin": position.margin, + "cumulativeFundingEntry": position.cumulative_funding_entry, + }, + }, + ], + } + + assert positions == expected_positions + + @pytest.mark.asyncio + async def test_fetch_subaccount_positions( + self, + exchange_servicer, + ): + position = exchange_pb.Position( + isLong=True, + quantity="1000000000000000", + entry_price="2000000000000000000", + margin="2000000000000000000000000000000000", + cumulative_funding_entry="4000000", + ) + derivative_position = genesis_pb.DerivativePosition( + subaccount_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + position=position, + ) + exchange_servicer.subaccount_positions_responses.append( + exchange_query_pb.QuerySubaccountPositionsResponse(state=[derivative_position]) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + positions = await api.fetch_subaccount_positions(subaccount_id=derivative_position.subaccount_id) + expected_positions = { + "state": [ + { + "subaccountId": derivative_position.subaccount_id, + "marketId": derivative_position.market_id, + "position": { + "isLong": position.isLong, + "quantity": position.quantity, + "entryPrice": position.entry_price, + "margin": position.margin, + "cumulativeFundingEntry": position.cumulative_funding_entry, + }, + }, + ], + } + + assert positions == expected_positions + + @pytest.mark.asyncio + async def test_fetch_subaccount_position_in_market( + self, + exchange_servicer, + ): + subaccount_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000" + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + position = exchange_pb.Position( + isLong=True, + quantity="1000000000000000", + entry_price="2000000000000000000", + margin="2000000000000000000000000000000000", + cumulative_funding_entry="4000000", + ) + exchange_servicer.subaccount_position_in_market_responses.append( + exchange_query_pb.QuerySubaccountPositionInMarketResponse(state=position) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + position_response = await api.fetch_subaccount_position_in_market( + subaccount_id=subaccount_id, + market_id=market_id, + ) + expected_position = { + "state": { + "isLong": position.isLong, + "quantity": position.quantity, + "entryPrice": position.entry_price, + "margin": position.margin, + "cumulativeFundingEntry": position.cumulative_funding_entry, + }, + } + + assert position_response == expected_position + + @pytest.mark.asyncio + async def test_fetch_subaccount_effective_position_in_market( + self, + exchange_servicer, + ): + subaccount_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000" + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + + effective_position = exchange_query_pb.EffectivePosition( + is_long=True, + quantity="1000000000000000", + entry_price="2000000000000000000", + effective_margin="2000000000000000000000000000000000", + ) + exchange_servicer.subaccount_effective_position_in_market_responses.append( + exchange_query_pb.QuerySubaccountEffectivePositionInMarketResponse(state=effective_position) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + position_response = await api.fetch_subaccount_effective_position_in_market( + subaccount_id=subaccount_id, + market_id=market_id, + ) + expected_position = { + "state": { + "isLong": effective_position.is_long, + "quantity": effective_position.quantity, + "entryPrice": effective_position.entry_price, + "effectiveMargin": effective_position.effective_margin, + }, + } + + assert position_response == expected_position + + @pytest.mark.asyncio + async def test_fetch_perpetual_market_info( + self, + exchange_servicer, + ): + perpetual_market_info = exchange_pb.PerpetualMarketInfo( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + hourly_funding_rate_cap="625000000000000", + hourly_interest_rate="4166660000000", + next_funding_timestamp=1708099200, + funding_interval=3600, + ) + exchange_servicer.perpetual_market_info_responses.append( + exchange_query_pb.QueryPerpetualMarketInfoResponse(info=perpetual_market_info) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + market_info = await api.fetch_perpetual_market_info(market_id=perpetual_market_info.market_id) + expected_market_info = { + "info": { + "marketId": perpetual_market_info.market_id, + "hourlyFundingRateCap": perpetual_market_info.hourly_funding_rate_cap, + "hourlyInterestRate": perpetual_market_info.hourly_interest_rate, + "nextFundingTimestamp": str(perpetual_market_info.next_funding_timestamp), + "fundingInterval": str(perpetual_market_info.funding_interval), + } + } + + assert market_info == expected_market_info + + @pytest.mark.asyncio + async def test_fetch_expiry_futures_market_info( + self, + exchange_servicer, + ): + expiry_futures_market_info = exchange_pb.ExpiryFuturesMarketInfo( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + expiration_timestamp=1708099200, + twap_start_timestamp=1705566200, + expiration_twap_start_price_cumulative="1000000000000000000", + settlement_price="2000000000000000000", + ) + exchange_servicer.expiry_futures_market_info_responses.append( + exchange_query_pb.QueryExpiryFuturesMarketInfoResponse(info=expiry_futures_market_info) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + market_info = await api.fetch_expiry_futures_market_info(market_id=expiry_futures_market_info.market_id) + expected_market_info = { + "info": { + "marketId": expiry_futures_market_info.market_id, + "expirationTimestamp": str(expiry_futures_market_info.expiration_timestamp), + "twapStartTimestamp": str(expiry_futures_market_info.twap_start_timestamp), + "expirationTwapStartPriceCumulative": expiry_futures_market_info.expiration_twap_start_price_cumulative, + "settlementPrice": expiry_futures_market_info.settlement_price, + } + } + + assert market_info == expected_market_info + + @pytest.mark.asyncio + async def test_fetch_perpetual_market_funding( + self, + exchange_servicer, + ): + perpetual_market_funding = exchange_pb.PerpetualMarketFunding( + cumulative_funding="-107853477278881692857461", + cumulative_price="0", + last_timestamp=1708099200, + ) + exchange_servicer.perpetual_market_funding_responses.append( + exchange_query_pb.QueryPerpetualMarketFundingResponse(state=perpetual_market_funding) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + funding = await api.fetch_perpetual_market_funding( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + ) + expected_funding = { + "state": { + "cumulativeFunding": perpetual_market_funding.cumulative_funding, + "cumulativePrice": perpetual_market_funding.cumulative_price, + "lastTimestamp": str(perpetual_market_funding.last_timestamp), + } + } + + assert funding == expected_funding + + @pytest.mark.asyncio + async def test_fetch_subaccount_order_metadata( + self, + exchange_servicer, + ): + metadata = exchange_pb.SubaccountOrderbookMetadata( + vanilla_limit_order_count=1, + reduce_only_limit_order_count=2, + aggregate_reduce_only_quantity="1000000000000000", + aggregate_vanilla_quantity="2000000000000000", + vanilla_conditional_order_count=3, + reduce_only_conditional_order_count=4, + ) + subaccount_order_metadata = exchange_query_pb.SubaccountOrderbookMetadataWithMarket( + metadata=metadata, + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + isBuy=True, + ) + exchange_servicer.subaccount_order_metadata_responses.append( + exchange_query_pb.QuerySubaccountOrderMetadataResponse(metadata=[subaccount_order_metadata]) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + metadata_response = await api.fetch_subaccount_order_metadata( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001" + ) + expected_metadata = { + "metadata": [ + { + "metadata": { + "vanillaLimitOrderCount": metadata.vanilla_limit_order_count, + "reduceOnlyLimitOrderCount": metadata.reduce_only_limit_order_count, + "aggregateReduceOnlyQuantity": metadata.aggregate_reduce_only_quantity, + "aggregateVanillaQuantity": metadata.aggregate_vanilla_quantity, + "vanillaConditionalOrderCount": metadata.vanilla_conditional_order_count, + "reduceOnlyConditionalOrderCount": metadata.reduce_only_conditional_order_count, + }, + "marketId": subaccount_order_metadata.market_id, + "isBuy": subaccount_order_metadata.isBuy, + }, + ] + } + + assert metadata_response == expected_metadata + + @pytest.mark.asyncio + async def test_fetch_trade_reward_points( + self, + exchange_servicer, + ): + points = "40" + response = exchange_query_pb.QueryTradeRewardPointsResponse(account_trade_reward_points=[points]) + exchange_servicer.trade_reward_points_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + trade_reward_points = await api.fetch_trade_reward_points( + accounts=["inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"], + pending_pool_timestamp=1708099200, + ) + expected_trade_reward_points = {"accountTradeRewardPoints": [points]} + + assert trade_reward_points == expected_trade_reward_points + + @pytest.mark.asyncio + async def test_fetch_pending_trade_reward_points( + self, + exchange_servicer, + ): + points = "40" + response = exchange_query_pb.QueryTradeRewardPointsResponse(account_trade_reward_points=[points]) + exchange_servicer.pending_trade_reward_points_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + trade_reward_points = await api.fetch_pending_trade_reward_points( + accounts=["inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"], + pending_pool_timestamp=1708099200, + ) + expected_trade_reward_points = {"accountTradeRewardPoints": [points]} + + assert trade_reward_points == expected_trade_reward_points + + @pytest.mark.asyncio + async def test_fetch_fee_discount_account_info( + self, + exchange_servicer, + ): + account_info = exchange_pb.FeeDiscountTierInfo( + maker_discount_rate="0.0001", + taker_discount_rate="0.0002", + staked_amount="1000000000", + volume="1000000000000000000", + ) + account_ttl = exchange_pb.FeeDiscountTierTTL( + tier=3, + ttl_timestamp=1708099200, + ) + response = exchange_query_pb.QueryFeeDiscountAccountInfoResponse( + tier_level=3, + account_info=account_info, + account_ttl=account_ttl, + ) + exchange_servicer.fee_discount_account_info_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + fee_discount = await api.fetch_fee_discount_account_info(account="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r") + expected_fee_discount = { + "tierLevel": str(response.tier_level), + "accountInfo": { + "makerDiscountRate": account_info.maker_discount_rate, + "takerDiscountRate": account_info.taker_discount_rate, + "stakedAmount": account_info.staked_amount, + "volume": account_info.volume, + }, + "accountTtl": { + "tier": str(account_ttl.tier), + "ttlTimestamp": str(account_ttl.ttl_timestamp), + }, + } + + assert fee_discount == expected_fee_discount + + @pytest.mark.asyncio + async def test_fetch_fee_discount_schedule( + self, + exchange_servicer, + ): + fee_discount_tier_info = exchange_pb.FeeDiscountTierInfo( + maker_discount_rate="0.0001", + taker_discount_rate="0.0002", + staked_amount="1000000000", + volume="1000000000000000000", + ) + fee_discount_schedule = exchange_pb.FeeDiscountSchedule( + bucket_count=3, + bucket_duration=3600, + quote_denoms=["peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"], + tier_infos=[fee_discount_tier_info], + disqualified_market_ids=["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"], + ) + exchange_servicer.fee_discount_schedule_responses.append( + exchange_query_pb.QueryFeeDiscountScheduleResponse( + fee_discount_schedule=fee_discount_schedule, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + schedule = await api.fetch_fee_discount_schedule() + expected_schedule = { + "feeDiscountSchedule": { + "bucketCount": str(fee_discount_schedule.bucket_count), + "bucketDuration": str(fee_discount_schedule.bucket_duration), + "quoteDenoms": fee_discount_schedule.quote_denoms, + "tierInfos": [ + { + "makerDiscountRate": fee_discount_tier_info.maker_discount_rate, + "takerDiscountRate": fee_discount_tier_info.taker_discount_rate, + "stakedAmount": fee_discount_tier_info.staked_amount, + "volume": fee_discount_tier_info.volume, + } + ], + "disqualifiedMarketIds": fee_discount_schedule.disqualified_market_ids, + }, + } + + assert schedule == expected_schedule + + @pytest.mark.asyncio + async def test_fetch_balance_mismatches( + self, + exchange_servicer, + ): + balance_mismatch = exchange_query_pb.BalanceMismatch( + subaccountId="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + available="1000000000000000", + total="2000000000000000", + balance_hold="3000000000000000", + expected_total="4000000000000000", + difference="500000000000000", + ) + exchange_servicer.balance_mismatches_responses.append( + exchange_query_pb.QueryBalanceMismatchesResponse( + balance_mismatches=[balance_mismatch], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + mismatches = await api.fetch_balance_mismatches(dust_factor=20) + expected_mismatches = { + "balanceMismatches": [ + { + "subaccountId": balance_mismatch.subaccountId, + "denom": balance_mismatch.denom, + "available": balance_mismatch.available, + "total": balance_mismatch.total, + "balanceHold": balance_mismatch.balance_hold, + "expectedTotal": balance_mismatch.expected_total, + "difference": balance_mismatch.difference, + } + ], + } + + assert mismatches == expected_mismatches + + @pytest.mark.asyncio + async def test_fetch_balance_with_balance_holds( + self, + exchange_servicer, + ): + balance_with_balance_hold = exchange_query_pb.BalanceWithMarginHold( + subaccountId="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + available="1000000000000000", + total="2000000000000000", + balance_hold="3000000000000000", + ) + exchange_servicer.balance_with_balance_holds_responses.append( + exchange_query_pb.QueryBalanceWithBalanceHoldsResponse( + balance_with_balance_holds=[balance_with_balance_hold], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + balance = await api.fetch_balance_with_balance_holds() + expected_balance = { + "balanceWithBalanceHolds": [ + { + "subaccountId": balance_with_balance_hold.subaccountId, + "denom": balance_with_balance_hold.denom, + "available": balance_with_balance_hold.available, + "total": balance_with_balance_hold.total, + "balanceHold": balance_with_balance_hold.balance_hold, + } + ], + } + + assert balance == expected_balance + + @pytest.mark.asyncio + async def test_fetch_fee_discount_tier_statistics( + self, + exchange_servicer, + ): + tier_statistics = exchange_query_pb.TierStatistic( + tier=3, + count=30, + ) + exchange_servicer.fee_discount_tier_statistics_responses.append( + exchange_query_pb.QueryFeeDiscountTierStatisticsResponse( + statistics=[tier_statistics], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + statistics = await api.fetch_fee_discount_tier_statistics() + expected_statistics = { + "statistics": [ + { + "tier": str(tier_statistics.tier), + "count": str(tier_statistics.count), + } + ], + } + + assert statistics == expected_statistics + + @pytest.mark.asyncio + async def test_fetch_mito_vault_infos( + self, + exchange_servicer, + ): + master_address = "inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9" + derivative_address = "inj1zlh5" + spot_address = "inj1zlh6" + cw20_address = "inj1zlh7" + response = exchange_query_pb.MitoVaultInfosResponse( + master_addresses=[master_address], + derivative_addresses=[derivative_address], + spot_addresses=[spot_address], + cw20_addresses=[cw20_address], + ) + exchange_servicer.mito_vault_infos_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + mito_vaults = await api.fetch_mito_vault_infos() + expected_mito_vaults = { + "masterAddresses": [master_address], + "derivativeAddresses": [derivative_address], + "spotAddresses": [spot_address], + "cw20Addresses": [cw20_address], + } + + assert mito_vaults == expected_mito_vaults + + @pytest.mark.asyncio + async def test_fetch_market_id_from_vault( + self, + exchange_servicer, + ): + market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" + exchange_servicer.market_id_from_vault_responses.append( + exchange_query_pb.QueryMarketIDFromVaultResponse( + market_id=market_id, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + market_id_response = await api.fetch_market_id_from_vault( + vault_address="inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9" + ) + expected_market_id = { + "marketId": market_id, + } + + assert market_id_response == expected_market_id + + @pytest.mark.asyncio + async def test_fetch_historical_trade_records( + self, + exchange_servicer, + ): + latest_trade_record = exchange_pb.TradeRecord( + timestamp=1708099200, + price="2000000000000000000", + quantity="1000000000000000", + ) + trade_record = exchange_pb.TradeRecords( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + latest_trade_records=[latest_trade_record], + ) + exchange_servicer.historical_trade_records_responses.append( + exchange_query_pb.QueryHistoricalTradeRecordsResponse( + trade_records=[trade_record], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + records = await api.fetch_historical_trade_records(market_id=trade_record.market_id) + expected_records = { + "tradeRecords": [ + { + "marketId": trade_record.market_id, + "latestTradeRecords": [ + { + "timestamp": str(latest_trade_record.timestamp), + "price": latest_trade_record.price, + "quantity": latest_trade_record.quantity, + } + ], + }, + ], + } + + assert records == expected_records + + @pytest.mark.asyncio + async def test_fetch_is_opted_out_of_rewards( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryIsOptedOutOfRewardsResponse( + is_opted_out=False, + ) + exchange_servicer.is_opted_out_of_rewards_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + is_opted_out = await api.fetch_is_opted_out_of_rewards(account="inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9") + expected_is_opted_out = { + "isOptedOut": response.is_opted_out, + } + + assert is_opted_out == expected_is_opted_out + + @pytest.mark.asyncio + async def test_fetch_opted_out_of_rewards_accounts( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryOptedOutOfRewardsAccountsResponse( + accounts=["inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9"], + ) + exchange_servicer.opted_out_of_rewards_accounts_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + opted_out = await api.fetch_opted_out_of_rewards_accounts() + expected_opted_out = { + "accounts": response.accounts, + } + + assert opted_out == expected_opted_out + + @pytest.mark.asyncio + async def test_fetch_market_volatility( + self, + exchange_servicer, + ): + history_metadata = oracle_pb.MetadataStatistics( + group_count=2, + records_sample_size=10, + mean="0.0001", + twap="0.0005", + first_timestamp=1702399200, + last_timestamp=1708099200, + min_price="1000000000000", + max_price="3000000000000", + median_price="2000000000000", + ) + trade_record = exchange_pb.TradeRecord( + timestamp=1708099200, + price="2000000000000000000", + quantity="1000000000000000", + ) + response = exchange_query_pb.QueryMarketVolatilityResponse( + volatility="0.0001", history_metadata=history_metadata, raw_history=[trade_record] + ) + exchange_servicer.market_volatility_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + volatility = await api.fetch_market_volatility( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + trade_grouping_sec=0, + max_age=28000000, + include_raw_history=True, + include_metadata=True, + ) + expected_volatility = { + "volatility": response.volatility, + "historyMetadata": { + "groupCount": history_metadata.group_count, + "recordsSampleSize": history_metadata.records_sample_size, + "mean": history_metadata.mean, + "twap": history_metadata.twap, + "firstTimestamp": str(history_metadata.first_timestamp), + "lastTimestamp": str(history_metadata.last_timestamp), + "minPrice": history_metadata.min_price, + "maxPrice": history_metadata.max_price, + "medianPrice": history_metadata.median_price, + }, + "rawHistory": [ + { + "timestamp": str(trade_record.timestamp), + "price": trade_record.price, + "quantity": trade_record.quantity, + } + ], + } + + assert volatility == expected_volatility + + @pytest.mark.asyncio + async def test_fetch_binary_options_markets( + self, + exchange_servicer, + ): + market = exchange_pb.BinaryOptionsMarket( + ticker="20250608/USDT", + oracle_symbol="0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3", + oracle_provider="Pyth", + oracle_type=9, + oracle_scale_factor=6, + expiration_timestamp=1708099200, + settlement_timestamp=1707099200, + admin="inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9", + quote_denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + maker_fee_rate="-0.0001", + taker_fee_rate="0.001", + relayer_fee_share_rate="400000000000000000", + status=1, + min_price_tick_size="100000000000000000000", + min_quantity_tick_size="1000000000000000", + settlement_price="2000000000000000000", + ) + response = exchange_query_pb.QueryBinaryMarketsResponse( + markets=[market], + ) + exchange_servicer.binary_options_markets_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + markets = await api.fetch_binary_options_markets(status="Active") + expected_markets = { + "markets": [ + { + "ticker": market.ticker, + "oracleSymbol": market.oracle_symbol, + "oracleProvider": market.oracle_provider, + "oracleType": oracle_pb.OracleType.Name(market.oracle_type), + "oracleScaleFactor": market.oracle_scale_factor, + "expirationTimestamp": str(market.expiration_timestamp), + "settlementTimestamp": str(market.settlement_timestamp), + "admin": market.admin, + "quoteDenom": market.quote_denom, + "marketId": market.market_id, + "makerFeeRate": market.maker_fee_rate, + "takerFeeRate": market.taker_fee_rate, + "relayerFeeShareRate": market.relayer_fee_share_rate, + "status": exchange_pb.MarketStatus.Name(market.status), + "minPriceTickSize": market.min_price_tick_size, + "minQuantityTickSize": market.min_quantity_tick_size, + "settlementPrice": market.settlement_price, + }, + ] + } + + assert markets == expected_markets + + @pytest.mark.asyncio + async def test_fetch_trader_derivative_conditional_orders( + self, + exchange_servicer, + ): + order = exchange_query_pb.TrimmedDerivativeConditionalOrder( + price="2000000000000000000", + quantity="1000000000000000", + margin="2000000000000000000000000000000000", + triggerPrice="3000000000000000000", + isBuy=True, + isLimit=True, + order_hash="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + response = exchange_query_pb.QueryTraderDerivativeConditionalOrdersResponse(orders=[order]) + exchange_servicer.trader_derivative_conditional_orders_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + orders = await api.fetch_trader_derivative_conditional_orders( + subaccount_id="0x5303d92e49a619bb29de8fb6f59c0e7589213cc8000000000000000000000001", + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + expected_orders = { + "orders": [ + { + "price": order.price, + "quantity": order.quantity, + "margin": order.margin, + "triggerPrice": order.triggerPrice, + "isBuy": order.isBuy, + "isLimit": order.isLimit, + "orderHash": order.order_hash, + } + ] + } + + assert orders == expected_orders + + @pytest.mark.asyncio + async def test_fetch_market_atomic_execution_fee_multiplier( + self, + exchange_servicer, + ): + response = exchange_query_pb.QueryMarketAtomicExecutionFeeMultiplierResponse( + multiplier="100", + ) + exchange_servicer.market_atomic_execution_fee_multiplier_responses.append(response) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcExchangeApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = exchange_servicer + + multiplier = await api.fetch_market_atomic_execution_fee_multiplier( + market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6", + ) + expected_multiplier = { + "multiplier": response.multiplier, + } + + assert multiplier == expected_multiplier + + async def _dummy_metadata_provider(self): + return None From c5cb600d9eae68f16d7180d0065230d5c98793e8 Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 27 Feb 2024 10:03:11 -0300 Subject: [PATCH 5/7] (feat) Added support for all chain exchange module messages in Composer. Added unit tests for new messages. Refactored example scripts to move them into separated subfolders for each module. --- ..._LocalOrderHash.py => 1_LocalOrderHash.py} | 101 +- ...OrderFail.py => 2_StreamEventOrderFail.py} | 0 .../35_MsgInstantBinaryOptionsMarketLaunch.py | 98 - ...Broadcaster.py => 3_MessageBroadcaster.py} | 21 +- ...4_MessageBroadcasterWithGranteeAccount.py} | 12 +- ... 5_MessageBroadcasterWithoutSimulation.py} | 19 +- ...terWithGranteeAccountWithoutSimulation.py} | 12 +- .../{49_ChainStream.py => 7_ChainStream.py} | 0 .../{18_MsgBid.py => auction/1_MsgBid.py} | 0 .../query/1_Account.py} | 0 .../{19_MsgGrant.py => authz/1_MsgGrant.py} | 0 .../{20_MsgExec.py => authz/2_MsgExec.py} | 10 +- .../{21_MsgRevoke.py => authz/3_MsgRevoke.py} | 0 .../4_MsgExecuteContractCompat.py} | 0 .../{27_Grants.py => authz/query/1_Grants.py} | 0 examples/chain_client/{ => bank}/1_MsgSend.py | 0 .../query/10_SendEnabled.py} | 0 .../query/1_BankBalance.py} | 0 .../query/2_BankBalances.py} | 0 .../query/3_SpendableBalances.py} | 0 .../query/4_SpendableBalancesByDenom.py} | 0 .../query/5_TotalSupply.py} | 0 .../query/6_SupplyOf.py} | 0 .../query/7_DenomMetadata.py} | 0 .../query/8_DenomsMetadata.py} | 0 .../query/9_DenomOwners.py} | 0 ...py => 10_MsgCreateDerivativeLimitOrder.py} | 14 +- ...y => 11_MsgCreateDerivativeMarketOrder.py} | 12 +- ...rder.py => 12_MsgCancelDerivativeOrder.py} | 2 +- .../13_MsgInstantBinaryOptionsMarketLaunch.py | 61 + ...=> 14_MsgCreateBinaryOptionsLimitOrder.py} | 13 +- ...> 15_MsgCreateBinaryOptionsMarketOrder.py} | 12 +- ...r.py => 16_MsgCancelBinaryOptionsOrder.py} | 2 +- ...ransfer.py => 17_MsgSubaccountTransfer.py} | 5 +- ...lTransfer.py => 18_MsgExternalTransfer.py} | 5 +- .../exchange/19_MsgLiquidatePosition.py | 15 +- .../chain_client/exchange/1_MsgDeposit.py | 4 +- .../20_MsgIncreasePositionMargin.py} | 5 +- ...ewardsOptOut.py => 21_MsgRewardsOptOut.py} | 2 +- .../22_MsgAdminUpdateBinaryOptionsMarket.py} | 5 +- .../{9_MsgWithdraw.py => 2_MsgWithdraw.py} | 2 +- .../exchange/3_MsgInstantSpotMarketLaunch.py | 54 + .../4_MsgInstantPerpetualMarketLaunch.py | 61 + .../5_MsgInstantExpiryFuturesMarketLaunch.py | 62 + ...tOrder.py => 6_MsgCreateSpotLimitOrder.py} | 10 +- ...Order.py => 7_MsgCreateSpotMarketOrder.py} | 11 +- ...elSpotOrder.py => 8_MsgCancelSpotOrder.py} | 0 ...ateOrders.py => 9_MsgBatchUpdateOrders.py} | 53 +- .../1_MsgCreateInsuranceFund.py} | 0 .../2_MsgUnderwrite.py} | 0 .../3_MsgRequestRedemption.py} | 0 .../1_MsgRelayPriceFeedPrice.py} | 0 .../2_MsgRelayProviderPrices.py} | 0 .../1_MsgSendToEth.py} | 0 .../1_MsgDelegate.py} | 0 .../1_CreateDenom.py} | 0 .../2_MsgMint.py} | 0 .../3_MsgBurn.py} | 0 .../4_MsgChangeAdmin.py} | 0 .../5_MsgSetDenomMetadata.py} | 0 .../query/1_DenomAuthorityMetadata.py} | 0 .../query/2_DenomsFromCreator.py} | 0 .../query/3_TokenfactoryModuleState.py} | 0 .../{37_GetTx.py => tx/query/1_GetTx.py} | 0 .../1_MsgExecuteContract.py} | 0 .../query/10_ContractsByCreator.py} | 0 .../query/1_ContractInfo.py} | 0 .../query/2_ContractHistory.py} | 0 .../query/3_ContractsByCode.py} | 0 .../query/4_AllContractsState.py} | 0 .../query/5_RawContractState.py} | 0 .../query/6_SmartContractState.py} | 0 .../query/7_SmartContractCode.py} | 0 .../query/8_SmartContractCodes.py} | 0 .../query/9_SmartContractPinnedCodes.py} | 0 pyinjective/composer.py | 1751 +++++++++++++---- pyinjective/core/market.py | 11 + tests/core/test_gas_limit_estimator.py | 158 +- tests/core/test_market.py | 36 + ...essage_based_transaction_fee_calculator.py | 27 +- tests/test_composer.py | 1466 ++++++++++++-- tests/test_composer_deprecation_warnings.py | 522 +++++ tests/test_orderhash.py | 20 +- 83 files changed, 3740 insertions(+), 934 deletions(-) rename examples/chain_client/{0_LocalOrderHash.py => 1_LocalOrderHash.py} (75%) rename examples/chain_client/{38_StreamEventOrderFail.py => 2_StreamEventOrderFail.py} (100%) delete mode 100644 examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py rename examples/chain_client/{44_MessageBroadcaster.py => 3_MessageBroadcaster.py} (84%) rename examples/chain_client/{45_MessageBroadcasterWithGranteeAccount.py => 4_MessageBroadcasterWithGranteeAccount.py} (91%) rename examples/chain_client/{46_MessageBroadcasterWithoutSimulation.py => 5_MessageBroadcasterWithoutSimulation.py} (86%) rename examples/chain_client/{47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py => 6_MessageBroadcasterWithGranteeAccountWithoutSimulation.py} (91%) rename examples/chain_client/{49_ChainStream.py => 7_ChainStream.py} (100%) rename examples/chain_client/{18_MsgBid.py => auction/1_MsgBid.py} (100%) rename examples/chain_client/{39_Account.py => auth/query/1_Account.py} (100%) rename examples/chain_client/{19_MsgGrant.py => authz/1_MsgGrant.py} (100%) rename examples/chain_client/{20_MsgExec.py => authz/2_MsgExec.py} (95%) rename examples/chain_client/{21_MsgRevoke.py => authz/3_MsgRevoke.py} (100%) rename examples/chain_client/{76_MsgExecuteContractCompat.py => authz/4_MsgExecuteContractCompat.py} (100%) rename examples/chain_client/{27_Grants.py => authz/query/1_Grants.py} (100%) rename examples/chain_client/{ => bank}/1_MsgSend.py (100%) rename examples/chain_client/{57_SendEnabled.py => bank/query/10_SendEnabled.py} (100%) rename examples/chain_client/{29_BankBalance.py => bank/query/1_BankBalance.py} (100%) rename examples/chain_client/{28_BankBalances.py => bank/query/2_BankBalances.py} (100%) rename examples/chain_client/{50_SpendableBalances.py => bank/query/3_SpendableBalances.py} (100%) rename examples/chain_client/{51_SpendableBalancesByDenom.py => bank/query/4_SpendableBalancesByDenom.py} (100%) rename examples/chain_client/{52_TotalSupply.py => bank/query/5_TotalSupply.py} (100%) rename examples/chain_client/{53_SupplyOf.py => bank/query/6_SupplyOf.py} (100%) rename examples/chain_client/{54_DenomMetadata.py => bank/query/7_DenomMetadata.py} (100%) rename examples/chain_client/{55_DenomsMetadata.py => bank/query/8_DenomsMetadata.py} (100%) rename examples/chain_client/{56_DenomOwners.py => bank/query/9_DenomOwners.py} (100%) rename examples/chain_client/exchange/{6_MsgCreateDerivativeLimitOrder.py => 10_MsgCreateDerivativeLimitOrder.py} (90%) rename examples/chain_client/exchange/{7_MsgCreateDerivativeMarketOrder.py => 11_MsgCreateDerivativeMarketOrder.py} (90%) rename examples/chain_client/exchange/{8_MsgCancelDerivativeOrder.py => 12_MsgCancelDerivativeOrder.py} (98%) create mode 100644 examples/chain_client/exchange/13_MsgInstantBinaryOptionsMarketLaunch.py rename examples/chain_client/exchange/{16_MsgCreateBinaryOptionsLimitOrder.py => 14_MsgCreateBinaryOptionsLimitOrder.py} (93%) rename examples/chain_client/exchange/{17_MsgCreateBinaryOptionsMarketOrder.py => 15_MsgCreateBinaryOptionsMarketOrder.py} (90%) rename examples/chain_client/exchange/{18_MsgCancelBinaryOptionsOrder.py => 16_MsgCancelBinaryOptionsOrder.py} (98%) rename examples/chain_client/exchange/{10_MsgSubaccountTransfer.py => 17_MsgSubaccountTransfer.py} (96%) rename examples/chain_client/exchange/{15_ExternalTransfer.py => 18_MsgExternalTransfer.py} (96%) rename examples/chain_client/{13_MsgIncreasePositionMargin.py => exchange/20_MsgIncreasePositionMargin.py} (96%) rename examples/chain_client/exchange/{12_MsgRewardsOptOut.py => 21_MsgRewardsOptOut.py} (97%) rename examples/chain_client/{34_MsgAdminUpdateBinaryOptionsMarket.py => exchange/22_MsgAdminUpdateBinaryOptionsMarket.py} (96%) rename examples/chain_client/exchange/{9_MsgWithdraw.py => 2_MsgWithdraw.py} (95%) create mode 100644 examples/chain_client/exchange/3_MsgInstantSpotMarketLaunch.py create mode 100644 examples/chain_client/exchange/4_MsgInstantPerpetualMarketLaunch.py create mode 100644 examples/chain_client/exchange/5_MsgInstantExpiryFuturesMarketLaunch.py rename examples/chain_client/exchange/{3_MsgCreateSpotLimitOrder.py => 6_MsgCreateSpotLimitOrder.py} (94%) rename examples/chain_client/exchange/{4_MsgCreateSpotMarketOrder.py => 7_MsgCreateSpotMarketOrder.py} (94%) rename examples/chain_client/exchange/{5_MsgCancelSpotOrder.py => 8_MsgCancelSpotOrder.py} (100%) rename examples/chain_client/exchange/{11_MsgBatchUpdateOrders.py => 9_MsgBatchUpdateOrders.py} (83%) rename examples/chain_client/{41_MsgCreateInsuranceFund.py => insurance/1_MsgCreateInsuranceFund.py} (100%) rename examples/chain_client/{42_MsgUnderwrite.py => insurance/2_MsgUnderwrite.py} (100%) rename examples/chain_client/{43_MsgRequestRedemption.py => insurance/3_MsgRequestRedemption.py} (100%) rename examples/chain_client/{23_MsgRelayPriceFeedPrice.py => oracle/1_MsgRelayPriceFeedPrice.py} (100%) rename examples/chain_client/{36_MsgRelayProviderPrices.py => oracle/2_MsgRelayProviderPrices.py} (100%) rename examples/chain_client/{22_MsgSendToEth.py => peggy/1_MsgSendToEth.py} (100%) rename examples/chain_client/{25_MsgDelegate.py => staking/1_MsgDelegate.py} (100%) rename examples/chain_client/{71_CreateDenom.py => tokenfactory/1_CreateDenom.py} (100%) rename examples/chain_client/{72_MsgMint.py => tokenfactory/2_MsgMint.py} (100%) rename examples/chain_client/{73_MsgBurn.py => tokenfactory/3_MsgBurn.py} (100%) rename examples/chain_client/{75_MsgChangeAdmin.py => tokenfactory/4_MsgChangeAdmin.py} (100%) rename examples/chain_client/{74_MsgSetDenomMetadata.py => tokenfactory/5_MsgSetDenomMetadata.py} (100%) rename examples/chain_client/{68_DenomAuthorityMetadata.py => tokenfactory/query/1_DenomAuthorityMetadata.py} (100%) rename examples/chain_client/{69_DenomsFromCreator.py => tokenfactory/query/2_DenomsFromCreator.py} (100%) rename examples/chain_client/{70_TokenfactoryModuleState.py => tokenfactory/query/3_TokenfactoryModuleState.py} (100%) rename examples/chain_client/{37_GetTx.py => tx/query/1_GetTx.py} (100%) rename examples/chain_client/{40_MsgExecuteContract.py => wasm/1_MsgExecuteContract.py} (100%) rename examples/chain_client/{67_ContractsByCreator.py => wasm/query/10_ContractsByCreator.py} (100%) rename examples/chain_client/{58_ContractInfo.py => wasm/query/1_ContractInfo.py} (100%) rename examples/chain_client/{59_ContractHistory.py => wasm/query/2_ContractHistory.py} (100%) rename examples/chain_client/{60_ContractsByCode.py => wasm/query/3_ContractsByCode.py} (100%) rename examples/chain_client/{61_AllContractsState.py => wasm/query/4_AllContractsState.py} (100%) rename examples/chain_client/{62_RawContractState.py => wasm/query/5_RawContractState.py} (100%) rename examples/chain_client/{63_SmartContractState.py => wasm/query/6_SmartContractState.py} (100%) rename examples/chain_client/{64_SmartContractCode.py => wasm/query/7_SmartContractCode.py} (100%) rename examples/chain_client/{65_SmartContractCodes.py => wasm/query/8_SmartContractCodes.py} (100%) rename examples/chain_client/{66_SmartContractPinnedCodes.py => wasm/query/9_SmartContractPinnedCodes.py} (100%) create mode 100644 tests/test_composer_deprecation_warnings.py diff --git a/examples/chain_client/0_LocalOrderHash.py b/examples/chain_client/1_LocalOrderHash.py similarity index 75% rename from examples/chain_client/0_LocalOrderHash.py rename to examples/chain_client/1_LocalOrderHash.py index 770ad5bf..fbec8988 100644 --- a/examples/chain_client/0_LocalOrderHash.py +++ b/examples/chain_client/1_LocalOrderHash.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -40,57 +41,59 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" spot_orders = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=0.524, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("0.524"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=27.92, - quantity=0.01, - is_buy=False, - is_po=False, + price=Decimal("27.92"), + quantity=Decimal("0.01"), + order_type="SELL", cid=str(uuid.uuid4()), ), ] derivative_orders = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=deriv_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=10500, - quantity=0.01, - leverage=1.5, - is_buy=True, - is_po=False, + price=Decimal(10500), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(10500), leverage=Decimal(2), is_reduce_only=False + ), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.DerivativeOrder( + composer.derivative_order( market_id=deriv_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=65111, - quantity=0.01, - leverage=2, - is_buy=False, - is_reduce_only=False, + price=Decimal(65111), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(65111), leverage=Decimal(2), is_reduce_only=False + ), + order_type="SELL", cid=str(uuid.uuid4()), ), ] # prepare tx msg - spot_msg = composer.MsgBatchCreateSpotLimitOrders(sender=address.to_acc_bech32(), orders=spot_orders) + spot_msg = composer.msg_batch_create_spot_limit_orders(sender=address.to_acc_bech32(), orders=spot_orders) - deriv_msg = composer.MsgBatchCreateDerivativeLimitOrders(sender=address.to_acc_bech32(), orders=derivative_orders) + deriv_msg = composer.msg_batch_create_derivative_limit_orders( + sender=address.to_acc_bech32(), orders=derivative_orders + ) # compute order hashes order_hashes = order_hash_manager.compute_order_hashes( @@ -167,57 +170,59 @@ async def main() -> None: print("gas fee: {} INJ".format(gas_fee)) spot_orders = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id_2, fee_recipient=fee_recipient, - price=1.524, - quantity=0.01, - is_buy=True, - is_po=True, + price=Decimal("1.524"), + quantity=Decimal("0.01"), + order_type="BUY_PO", cid=str(uuid.uuid4()), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id_2, fee_recipient=fee_recipient, - price=27.92, - quantity=0.01, - is_buy=False, - is_po=False, + price=Decimal("27.92"), + quantity=Decimal("0.01"), + order_type="SELL_PO", cid=str(uuid.uuid4()), ), ] derivative_orders = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=deriv_market_id, subaccount_id=subaccount_id_2, fee_recipient=fee_recipient, - price=25111, - quantity=0.01, - leverage=1.5, - is_buy=True, - is_po=False, + price=Decimal(25111), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(25111), leverage=Decimal("1.5"), is_reduce_only=False + ), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.DerivativeOrder( + composer.derivative_order( market_id=deriv_market_id, subaccount_id=subaccount_id_2, fee_recipient=fee_recipient, - price=65111, - quantity=0.01, - leverage=2, - is_buy=False, - is_reduce_only=False, + price=Decimal(65111), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(25111), leverage=Decimal(2), is_reduce_only=False + ), + order_type="SELL", cid=str(uuid.uuid4()), ), ] # prepare tx msg - spot_msg = composer.MsgBatchCreateSpotLimitOrders(sender=address.to_acc_bech32(), orders=spot_orders) + spot_msg = composer.msg_batch_create_spot_limit_orders(sender=address.to_acc_bech32(), orders=spot_orders) - deriv_msg = composer.MsgBatchCreateDerivativeLimitOrders(sender=address.to_acc_bech32(), orders=derivative_orders) + deriv_msg = composer.msg_batch_create_derivative_limit_orders( + sender=address.to_acc_bech32(), orders=derivative_orders + ) # compute order hashes order_hashes = order_hash_manager.compute_order_hashes( diff --git a/examples/chain_client/38_StreamEventOrderFail.py b/examples/chain_client/2_StreamEventOrderFail.py similarity index 100% rename from examples/chain_client/38_StreamEventOrderFail.py rename to examples/chain_client/2_StreamEventOrderFail.py diff --git a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py deleted file mode 100644 index 7b8a6567..00000000 --- a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py +++ /dev/null @@ -1,98 +0,0 @@ -import asyncio -import os - -import dotenv -from grpc import RpcError - -from pyinjective.async_client import AsyncClient -from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE -from pyinjective.core.network import Network -from pyinjective.transaction import Transaction -from pyinjective.wallet import PrivateKey - - -async def main() -> None: - dotenv.load_dotenv() - configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") - - # select network: local, testnet, mainnet - network = Network.testnet() - - # initialize grpc client - client = AsyncClient(network) - composer = await client.composer() - await client.sync_timeout_height() - - # load account - priv_key = PrivateKey.from_hex(configured_private_key) - pub_key = priv_key.to_public_key() - address = pub_key.to_address() - await client.fetch_account(address.to_acc_bech32()) - - # prepare tx msg - msg = composer.MsgInstantBinaryOptionsMarketLaunch( - sender=address.to_acc_bech32(), - admin=address.to_acc_bech32(), - ticker="UFC-KHABIB-TKO-05/30/2023", - oracle_symbol="UFC-KHABIB-TKO-05/30/2023", - oracle_provider="UFC", - oracle_type="Provider", - quote_denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7", - quote_decimals=6, - oracle_scale_factor=6, - maker_fee_rate=0.0005, # 0.05% - taker_fee_rate=0.0010, # 0.10% - expiration_timestamp=1680730982, - settlement_timestamp=1690730982, - min_price_tick_size=0.01, - min_quantity_tick_size=0.01, - ) - - # build sim tx - tx = ( - Transaction() - .with_messages(msg) - .with_sequence(client.get_sequence()) - .with_account_num(client.get_number()) - .with_chain_id(network.chain_id) - ) - sim_sign_doc = tx.get_sign_doc(pub_key) - sim_sig = priv_key.sign(sim_sign_doc.SerializeToString()) - sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key) - - # simulate tx - try: - sim_res = await client.simulate(sim_tx_raw_bytes) - except RpcError as ex: - print(ex) - return - - sim_res_msg = sim_res["result"]["msgResponses"] - print("---Simulation Response---") - print(sim_res_msg) - - # build tx - gas_price = GAS_PRICE - gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation - gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0") - fee = [ - composer.coin( - amount=gas_price * gas_limit, - denom=network.fee_denom, - ) - ] - tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height) - sign_doc = tx.get_sign_doc(pub_key) - sig = priv_key.sign(sign_doc.SerializeToString()) - tx_raw_bytes = tx.get_tx_data(sig, pub_key) - - # broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode - res = await client.broadcast_tx_sync_mode(tx_raw_bytes) - print("---Transaction Response---") - print(res) - print("gas wanted: {}".format(gas_limit)) - print("gas fee: {} INJ".format(gas_fee)) - - -if __name__ == "__main__": - asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/44_MessageBroadcaster.py b/examples/chain_client/3_MessageBroadcaster.py similarity index 84% rename from examples/chain_client/44_MessageBroadcaster.py rename to examples/chain_client/3_MessageBroadcaster.py index 114a8700..6bd67033 100644 --- a/examples/chain_client/44_MessageBroadcaster.py +++ b/examples/chain_client/3_MessageBroadcaster.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -34,24 +35,22 @@ async def main() -> None: spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" spot_orders_to_create = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=3, - quantity=55, - is_buy=True, - is_po=False, - cid=str(uuid.uuid4()), + price=Decimal("3"), + quantity=Decimal("55"), + order_type="BUY", + cid=(str(uuid.uuid4())), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=300, - quantity=55, - is_buy=False, - is_po=False, + price=Decimal("300"), + quantity=Decimal("55"), + order_type="SELL", cid=str(uuid.uuid4()), ), ] diff --git a/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py b/examples/chain_client/4_MessageBroadcasterWithGranteeAccount.py similarity index 91% rename from examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py rename to examples/chain_client/4_MessageBroadcasterWithGranteeAccount.py index 8c0166e2..4e08397b 100644 --- a/examples/chain_client/45_MessageBroadcasterWithGranteeAccount.py +++ b/examples/chain_client/4_MessageBroadcasterWithGranteeAccount.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -40,15 +41,14 @@ async def main() -> None: 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, + msg = composer.msg_create_spot_limit_order( market_id=market_id, + sender=granter_inj_address, subaccount_id=granter_subaccount_id, fee_recipient=address.to_acc_bech32(), - price=7.523, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py b/examples/chain_client/5_MessageBroadcasterWithoutSimulation.py similarity index 86% rename from examples/chain_client/46_MessageBroadcasterWithoutSimulation.py rename to examples/chain_client/5_MessageBroadcasterWithoutSimulation.py index e6e87c5a..54a79bf8 100644 --- a/examples/chain_client/46_MessageBroadcasterWithoutSimulation.py +++ b/examples/chain_client/5_MessageBroadcasterWithoutSimulation.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -34,24 +35,22 @@ async def main() -> None: spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" spot_orders_to_create = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=3, - quantity=55, - is_buy=True, - is_po=False, + price=Decimal("3"), + quantity=Decimal("55"), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=300, - quantity=55, - is_buy=False, - is_po=False, + price=Decimal("300"), + quantity=Decimal("55"), + order_type="SELL", cid=str(uuid.uuid4()), ), ] diff --git a/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py b/examples/chain_client/6_MessageBroadcasterWithGranteeAccountWithoutSimulation.py similarity index 91% rename from examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py rename to examples/chain_client/6_MessageBroadcasterWithGranteeAccountWithoutSimulation.py index b95114b7..4b7fbd2e 100644 --- a/examples/chain_client/47_MessageBroadcasterWithGranteeAccountWithoutSimulation.py +++ b/examples/chain_client/6_MessageBroadcasterWithGranteeAccountWithoutSimulation.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv @@ -39,15 +40,14 @@ async def main() -> None: 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, + msg = composer.msg_create_spot_limit_order( market_id=market_id, + sender=granter_inj_address, subaccount_id=granter_subaccount_id, fee_recipient=address.to_acc_bech32(), - price=7.523, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/49_ChainStream.py b/examples/chain_client/7_ChainStream.py similarity index 100% rename from examples/chain_client/49_ChainStream.py rename to examples/chain_client/7_ChainStream.py diff --git a/examples/chain_client/18_MsgBid.py b/examples/chain_client/auction/1_MsgBid.py similarity index 100% rename from examples/chain_client/18_MsgBid.py rename to examples/chain_client/auction/1_MsgBid.py diff --git a/examples/chain_client/39_Account.py b/examples/chain_client/auth/query/1_Account.py similarity index 100% rename from examples/chain_client/39_Account.py rename to examples/chain_client/auth/query/1_Account.py diff --git a/examples/chain_client/19_MsgGrant.py b/examples/chain_client/authz/1_MsgGrant.py similarity index 100% rename from examples/chain_client/19_MsgGrant.py rename to examples/chain_client/authz/1_MsgGrant.py diff --git a/examples/chain_client/20_MsgExec.py b/examples/chain_client/authz/2_MsgExec.py similarity index 95% rename from examples/chain_client/20_MsgExec.py rename to examples/chain_client/authz/2_MsgExec.py index 1203ff90..8d9891a5 100644 --- a/examples/chain_client/20_MsgExec.py +++ b/examples/chain_client/authz/2_MsgExec.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -37,15 +38,14 @@ async def main() -> None: granter_address = Address.from_acc_bech32(granter_inj_address) granter_subaccount_id = granter_address.get_subaccount_id(index=0) - msg0 = composer.MsgCreateSpotLimitOrder( + msg0 = composer.msg_create_spot_limit_order( sender=granter_inj_address, market_id=market_id, subaccount_id=granter_subaccount_id, fee_recipient=grantee, - price=7.523, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/21_MsgRevoke.py b/examples/chain_client/authz/3_MsgRevoke.py similarity index 100% rename from examples/chain_client/21_MsgRevoke.py rename to examples/chain_client/authz/3_MsgRevoke.py diff --git a/examples/chain_client/76_MsgExecuteContractCompat.py b/examples/chain_client/authz/4_MsgExecuteContractCompat.py similarity index 100% rename from examples/chain_client/76_MsgExecuteContractCompat.py rename to examples/chain_client/authz/4_MsgExecuteContractCompat.py diff --git a/examples/chain_client/27_Grants.py b/examples/chain_client/authz/query/1_Grants.py similarity index 100% rename from examples/chain_client/27_Grants.py rename to examples/chain_client/authz/query/1_Grants.py diff --git a/examples/chain_client/1_MsgSend.py b/examples/chain_client/bank/1_MsgSend.py similarity index 100% rename from examples/chain_client/1_MsgSend.py rename to examples/chain_client/bank/1_MsgSend.py diff --git a/examples/chain_client/57_SendEnabled.py b/examples/chain_client/bank/query/10_SendEnabled.py similarity index 100% rename from examples/chain_client/57_SendEnabled.py rename to examples/chain_client/bank/query/10_SendEnabled.py diff --git a/examples/chain_client/29_BankBalance.py b/examples/chain_client/bank/query/1_BankBalance.py similarity index 100% rename from examples/chain_client/29_BankBalance.py rename to examples/chain_client/bank/query/1_BankBalance.py diff --git a/examples/chain_client/28_BankBalances.py b/examples/chain_client/bank/query/2_BankBalances.py similarity index 100% rename from examples/chain_client/28_BankBalances.py rename to examples/chain_client/bank/query/2_BankBalances.py diff --git a/examples/chain_client/50_SpendableBalances.py b/examples/chain_client/bank/query/3_SpendableBalances.py similarity index 100% rename from examples/chain_client/50_SpendableBalances.py rename to examples/chain_client/bank/query/3_SpendableBalances.py diff --git a/examples/chain_client/51_SpendableBalancesByDenom.py b/examples/chain_client/bank/query/4_SpendableBalancesByDenom.py similarity index 100% rename from examples/chain_client/51_SpendableBalancesByDenom.py rename to examples/chain_client/bank/query/4_SpendableBalancesByDenom.py diff --git a/examples/chain_client/52_TotalSupply.py b/examples/chain_client/bank/query/5_TotalSupply.py similarity index 100% rename from examples/chain_client/52_TotalSupply.py rename to examples/chain_client/bank/query/5_TotalSupply.py diff --git a/examples/chain_client/53_SupplyOf.py b/examples/chain_client/bank/query/6_SupplyOf.py similarity index 100% rename from examples/chain_client/53_SupplyOf.py rename to examples/chain_client/bank/query/6_SupplyOf.py diff --git a/examples/chain_client/54_DenomMetadata.py b/examples/chain_client/bank/query/7_DenomMetadata.py similarity index 100% rename from examples/chain_client/54_DenomMetadata.py rename to examples/chain_client/bank/query/7_DenomMetadata.py diff --git a/examples/chain_client/55_DenomsMetadata.py b/examples/chain_client/bank/query/8_DenomsMetadata.py similarity index 100% rename from examples/chain_client/55_DenomsMetadata.py rename to examples/chain_client/bank/query/8_DenomsMetadata.py diff --git a/examples/chain_client/56_DenomOwners.py b/examples/chain_client/bank/query/9_DenomOwners.py similarity index 100% rename from examples/chain_client/56_DenomOwners.py rename to examples/chain_client/bank/query/9_DenomOwners.py diff --git a/examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/exchange/10_MsgCreateDerivativeLimitOrder.py similarity index 90% rename from examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py rename to examples/chain_client/exchange/10_MsgCreateDerivativeLimitOrder.py index 41a19307..4e0ff327 100644 --- a/examples/chain_client/exchange/6_MsgCreateDerivativeLimitOrder.py +++ b/examples/chain_client/exchange/10_MsgCreateDerivativeLimitOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,16 +37,17 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg - msg = composer.MsgCreateDerivativeLimitOrder( + msg = composer.msg_create_derivative_limit_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=50000, - quantity=0.1, - leverage=1, - is_buy=False, - is_reduce_only=False, + price=Decimal(50000), + quantity=Decimal(0.1), + margin=composer.calculate_margin( + quantity=Decimal(0.1), price=Decimal(50000), leverage=Decimal(1), is_reduce_only=False + ), + order_type="SELL", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py b/examples/chain_client/exchange/11_MsgCreateDerivativeMarketOrder.py similarity index 90% rename from examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py rename to examples/chain_client/exchange/11_MsgCreateDerivativeMarketOrder.py index 37b305ed..dfedf6d6 100644 --- a/examples/chain_client/exchange/7_MsgCreateDerivativeMarketOrder.py +++ b/examples/chain_client/exchange/11_MsgCreateDerivativeMarketOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,15 +37,16 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg - msg = composer.MsgCreateDerivativeMarketOrder( + msg = composer.msg_create_derivative_market_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=50000, - quantity=0.01, - leverage=3, - is_buy=True, + price=Decimal(50000), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(50000), leverage=Decimal(3), is_reduce_only=False + ), cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py b/examples/chain_client/exchange/12_MsgCancelDerivativeOrder.py similarity index 98% rename from examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py rename to examples/chain_client/exchange/12_MsgCancelDerivativeOrder.py index 43180b1f..20be2bd0 100644 --- a/examples/chain_client/exchange/8_MsgCancelDerivativeOrder.py +++ b/examples/chain_client/exchange/12_MsgCancelDerivativeOrder.py @@ -35,7 +35,7 @@ async def main() -> None: order_hash = "0x667ee6f37f6d06bf473f4e1434e92ac98ff43c785405e2a511a0843daeca2de9" # prepare tx msg - msg = composer.MsgCancelDerivativeOrder( + msg = composer.msg_cancel_derivative_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, order_hash=order_hash ) diff --git a/examples/chain_client/exchange/13_MsgInstantBinaryOptionsMarketLaunch.py b/examples/chain_client/exchange/13_MsgInstantBinaryOptionsMarketLaunch.py new file mode 100644 index 00000000..a1ebde82 --- /dev/null +++ b/examples/chain_client/exchange/13_MsgInstantBinaryOptionsMarketLaunch.py @@ -0,0 +1,61 @@ +import asyncio +import os + +import dotenv + +from pyinjective.async_client import AsyncClient +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.core.network import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + composer = await client.composer() + await client.sync_timeout_height() + + message_broadcaster = MsgBroadcasterWithPk.new_using_simulation( + network=network, + private_key=configured_private_key, + ) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + # prepare tx msg + message = composer.msg_instant_binary_options_market_launch( + sender=address.to_acc_bech32(), + ticker="UFC-KHABIB-TKO-05/30/2023", + oracle_symbol="UFC-KHABIB-TKO-05/30/2023", + oracle_provider="UFC", + oracle_type="Provider", + quote_decimals=6, + oracle_scale_factor=6, + maker_fee_rate=0.0005, # 0.05% + taker_fee_rate=0.0010, # 0.10% + expiration_timestamp=1680730982, + settlement_timestamp=1690730982, + admin=address.to_acc_bech32(), + quote_denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7", + min_price_tick_size=0.01, + min_quantity_tick_size=0.01, + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([message]) + print("---Transaction Response---") + print(result) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py b/examples/chain_client/exchange/14_MsgCreateBinaryOptionsLimitOrder.py similarity index 93% rename from examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py rename to examples/chain_client/exchange/14_MsgCreateBinaryOptionsLimitOrder.py index 2a58e173..5ad8c59e 100644 --- a/examples/chain_client/exchange/16_MsgCreateBinaryOptionsLimitOrder.py +++ b/examples/chain_client/exchange/14_MsgCreateBinaryOptionsLimitOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -40,17 +41,17 @@ async def main() -> None: denom = Denom(description="desc", base=0, quote=6, min_price_tick_size=1000, min_quantity_tick_size=0.0001) # prepare tx msg - msg = composer.MsgCreateBinaryOptionsLimitOrder( + msg = composer.msg_create_binary_options_limit_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=0.5, - quantity=1, - is_buy=False, - is_reduce_only=False, - denom=denom, + price=Decimal("0.5"), + quantity=Decimal("1"), + margin=Decimal("0.5"), + order_type="BUY", cid=str(uuid.uuid4()), + denom=denom, ) # build sim tx diff --git a/examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py b/examples/chain_client/exchange/15_MsgCreateBinaryOptionsMarketOrder.py similarity index 90% rename from examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py rename to examples/chain_client/exchange/15_MsgCreateBinaryOptionsMarketOrder.py index 2d07658f..9b68bc85 100644 --- a/examples/chain_client/exchange/17_MsgCreateBinaryOptionsMarketOrder.py +++ b/examples/chain_client/exchange/15_MsgCreateBinaryOptionsMarketOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,15 +37,16 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg - msg = composer.MsgCreateBinaryOptionsMarketOrder( + msg = composer.msg_create_binary_options_market_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=0.5, - quantity=1, - is_buy=True, - is_reduce_only=False, + price=Decimal("0.5"), + quantity=Decimal(1), + margin=composer.calculate_margin( + quantity=Decimal(1), price=Decimal("0.5"), leverage=Decimal(1), is_reduce_only=False + ), cid=str(uuid.uuid4()), ) # build sim tx diff --git a/examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py b/examples/chain_client/exchange/16_MsgCancelBinaryOptionsOrder.py similarity index 98% rename from examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py rename to examples/chain_client/exchange/16_MsgCancelBinaryOptionsOrder.py index 82107f3c..582c6dc6 100644 --- a/examples/chain_client/exchange/18_MsgCancelBinaryOptionsOrder.py +++ b/examples/chain_client/exchange/16_MsgCancelBinaryOptionsOrder.py @@ -35,7 +35,7 @@ async def main() -> None: order_hash = "a975fbd72b874bdbf5caf5e1e8e2653937f33ce6dd14d241c06c8b1f7b56be46" # prepare tx msg - msg = composer.MsgCancelBinaryOptionsOrder( + msg = composer.msg_cancel_binary_options_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, order_hash=order_hash ) # build sim tx diff --git a/examples/chain_client/exchange/10_MsgSubaccountTransfer.py b/examples/chain_client/exchange/17_MsgSubaccountTransfer.py similarity index 96% rename from examples/chain_client/exchange/10_MsgSubaccountTransfer.py rename to examples/chain_client/exchange/17_MsgSubaccountTransfer.py index b68717b2..a50fc0cf 100644 --- a/examples/chain_client/exchange/10_MsgSubaccountTransfer.py +++ b/examples/chain_client/exchange/17_MsgSubaccountTransfer.py @@ -1,5 +1,6 @@ import asyncio import os +from decimal import Decimal import dotenv from grpc import RpcError @@ -32,11 +33,11 @@ async def main() -> None: dest_subaccount_id = address.get_subaccount_id(index=1) # prepare tx msg - msg = composer.MsgSubaccountTransfer( + msg = composer.msg_subaccount_transfer( sender=address.to_acc_bech32(), source_subaccount_id=subaccount_id, destination_subaccount_id=dest_subaccount_id, - amount=100, + amount=Decimal(100), denom="INJ", ) diff --git a/examples/chain_client/exchange/15_ExternalTransfer.py b/examples/chain_client/exchange/18_MsgExternalTransfer.py similarity index 96% rename from examples/chain_client/exchange/15_ExternalTransfer.py rename to examples/chain_client/exchange/18_MsgExternalTransfer.py index 3200be34..2bcc86a1 100644 --- a/examples/chain_client/exchange/15_ExternalTransfer.py +++ b/examples/chain_client/exchange/18_MsgExternalTransfer.py @@ -1,5 +1,6 @@ import asyncio import os +from decimal import Decimal import dotenv from grpc import RpcError @@ -32,11 +33,11 @@ async def main() -> None: dest_subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000" # prepare tx msg - msg = composer.MsgExternalTransfer( + msg = composer.msg_external_transfer( sender=address.to_acc_bech32(), source_subaccount_id=subaccount_id, destination_subaccount_id=dest_subaccount_id, - amount=100, + amount=Decimal(100), denom="INJ", ) diff --git a/examples/chain_client/exchange/19_MsgLiquidatePosition.py b/examples/chain_client/exchange/19_MsgLiquidatePosition.py index d80ba385..9788b865 100644 --- a/examples/chain_client/exchange/19_MsgLiquidatePosition.py +++ b/examples/chain_client/exchange/19_MsgLiquidatePosition.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,19 +37,21 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" cid = str(uuid.uuid4()) - order = composer.DerivativeOrder( + order = composer.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=39.01, # This should be the liquidation price - quantity=0.147, - leverage=1, + price=Decimal(39.01), # This should be the liquidation price + quantity=Decimal(0.147), + margin=composer.calculate_margin( + quantity=Decimal(0.147), price=Decimal(39.01), leverage=Decimal(1), is_reduce_only=False + ), + order_type="SELL", cid=cid, - is_buy=False, ) # prepare tx msg - msg = composer.MsgLiquidatePosition( + msg = composer.msg_liquidate_position( sender=address.to_acc_bech32(), subaccount_id="0x156df4d5bc8e7dd9191433e54bd6a11eeb390921000000000000000000000000", market_id=market_id, diff --git a/examples/chain_client/exchange/1_MsgDeposit.py b/examples/chain_client/exchange/1_MsgDeposit.py index 80b9f652..bbf64710 100644 --- a/examples/chain_client/exchange/1_MsgDeposit.py +++ b/examples/chain_client/exchange/1_MsgDeposit.py @@ -31,7 +31,9 @@ async def main() -> None: subaccount_id = address.get_subaccount_id(index=0) # prepare tx msg - msg = composer.MsgDeposit(sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=0.000001, denom="INJ") + msg = composer.msg_deposit( + sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=0.000001, denom="INJ" + ) # build sim tx tx = ( diff --git a/examples/chain_client/13_MsgIncreasePositionMargin.py b/examples/chain_client/exchange/20_MsgIncreasePositionMargin.py similarity index 96% rename from examples/chain_client/13_MsgIncreasePositionMargin.py rename to examples/chain_client/exchange/20_MsgIncreasePositionMargin.py index 775a41e5..276276e7 100644 --- a/examples/chain_client/13_MsgIncreasePositionMargin.py +++ b/examples/chain_client/exchange/20_MsgIncreasePositionMargin.py @@ -1,5 +1,6 @@ import asyncio import os +from decimal import Decimal import dotenv from grpc import RpcError @@ -34,12 +35,12 @@ async def main() -> None: market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" # prepare tx msg - msg = composer.MsgIncreasePositionMargin( + msg = composer.msg_increase_position_margin( sender=address.to_acc_bech32(), market_id=market_id, source_subaccount_id=subaccount_id, destination_subaccount_id=subaccount_id, - amount=2, + amount=Decimal(2), ) # build sim tx diff --git a/examples/chain_client/exchange/12_MsgRewardsOptOut.py b/examples/chain_client/exchange/21_MsgRewardsOptOut.py similarity index 97% rename from examples/chain_client/exchange/12_MsgRewardsOptOut.py rename to examples/chain_client/exchange/21_MsgRewardsOptOut.py index 8beaa1f4..2306b541 100644 --- a/examples/chain_client/exchange/12_MsgRewardsOptOut.py +++ b/examples/chain_client/exchange/21_MsgRewardsOptOut.py @@ -30,7 +30,7 @@ async def main() -> None: await client.fetch_account(address.to_acc_bech32()) # prepare tx msg - msg = composer.MsgRewardsOptOut(sender=address.to_acc_bech32()) + msg = composer.msg_rewards_opt_out(sender=address.to_acc_bech32()) # build sim tx tx = ( diff --git a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py b/examples/chain_client/exchange/22_MsgAdminUpdateBinaryOptionsMarket.py similarity index 96% rename from examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py rename to examples/chain_client/exchange/22_MsgAdminUpdateBinaryOptionsMarket.py index 0f39dcdb..b638b28a 100644 --- a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py +++ b/examples/chain_client/exchange/22_MsgAdminUpdateBinaryOptionsMarket.py @@ -1,5 +1,6 @@ import asyncio import os +from decimal import Decimal import dotenv from grpc import RpcError @@ -32,12 +33,12 @@ async def main() -> None: # prepare trade info market_id = "0xfafec40a7b93331c1fc89c23f66d11fbb48f38dfdd78f7f4fc4031fad90f6896" status = "Demolished" - settlement_price = 1 + settlement_price = Decimal(1) expiration_timestamp = 1685460582 settlement_timestamp = 1690730982 # prepare tx msg - msg = composer.MsgAdminUpdateBinaryOptionsMarket( + msg = composer.msg_admin_update_binary_options_market( sender=address.to_acc_bech32(), market_id=market_id, settlement_price=settlement_price, diff --git a/examples/chain_client/exchange/9_MsgWithdraw.py b/examples/chain_client/exchange/2_MsgWithdraw.py similarity index 95% rename from examples/chain_client/exchange/9_MsgWithdraw.py rename to examples/chain_client/exchange/2_MsgWithdraw.py index b198c0aa..1070d28c 100644 --- a/examples/chain_client/exchange/9_MsgWithdraw.py +++ b/examples/chain_client/exchange/2_MsgWithdraw.py @@ -31,7 +31,7 @@ async def main() -> None: subaccount_id = address.get_subaccount_id(index=0) # prepare tx msg - msg = composer.MsgWithdraw(sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=1, denom="USDT") + msg = composer.msg_withdraw(sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=1, denom="USDT") # build sim tx tx = ( diff --git a/examples/chain_client/exchange/3_MsgInstantSpotMarketLaunch.py b/examples/chain_client/exchange/3_MsgInstantSpotMarketLaunch.py new file mode 100644 index 00000000..90a177ec --- /dev/null +++ b/examples/chain_client/exchange/3_MsgInstantSpotMarketLaunch.py @@ -0,0 +1,54 @@ +import asyncio +import os +from decimal import Decimal + +import dotenv + +from pyinjective.async_client import AsyncClient +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.core.network import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + await client.initialize_tokens_from_chain_denoms() + composer = await client.composer() + await client.sync_timeout_height() + + message_broadcaster = MsgBroadcasterWithPk.new_using_simulation( + network=network, + private_key=configured_private_key, + ) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + # prepare tx msg + message = composer.msg_instant_spot_market_launch( + sender=address.to_acc_bech32(), + ticker="INJ/USDC", + base_denom="INJ", + quote_denom="USDC", + min_price_tick_size=Decimal("0.001"), + min_quantity_tick_size=Decimal("0.01"), + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([message]) + print("---Transaction Response---") + print(result) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/4_MsgInstantPerpetualMarketLaunch.py b/examples/chain_client/exchange/4_MsgInstantPerpetualMarketLaunch.py new file mode 100644 index 00000000..b2b5dff4 --- /dev/null +++ b/examples/chain_client/exchange/4_MsgInstantPerpetualMarketLaunch.py @@ -0,0 +1,61 @@ +import asyncio +import os +from decimal import Decimal + +import dotenv + +from pyinjective.async_client import AsyncClient +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.core.network import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + await client.initialize_tokens_from_chain_denoms() + composer = await client.composer() + await client.sync_timeout_height() + + message_broadcaster = MsgBroadcasterWithPk.new_using_simulation( + network=network, + private_key=configured_private_key, + ) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + # prepare tx msg + message = composer.msg_instant_perpetual_market_launch( + sender=address.to_acc_bech32(), + ticker="INJ/USDC PERP", + quote_denom="USDC", + oracle_base="INJ", + oracle_quote="USDC", + oracle_scale_factor=6, + oracle_type="Band", + maker_fee_rate=Decimal("-0.0001"), + taker_fee_rate=Decimal("0.001"), + initial_margin_ratio=Decimal("0.33"), + maintenance_margin_ratio=Decimal("0.095"), + min_price_tick_size=Decimal("0.001"), + min_quantity_tick_size=Decimal("0.01"), + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([message]) + print("---Transaction Response---") + print(result) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/5_MsgInstantExpiryFuturesMarketLaunch.py b/examples/chain_client/exchange/5_MsgInstantExpiryFuturesMarketLaunch.py new file mode 100644 index 00000000..d451fd15 --- /dev/null +++ b/examples/chain_client/exchange/5_MsgInstantExpiryFuturesMarketLaunch.py @@ -0,0 +1,62 @@ +import asyncio +import os +from decimal import Decimal + +import dotenv + +from pyinjective.async_client import AsyncClient +from pyinjective.core.broadcaster import MsgBroadcasterWithPk +from pyinjective.core.network import Network +from pyinjective.wallet import PrivateKey + + +async def main() -> None: + dotenv.load_dotenv() + configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + # select network: local, testnet, mainnet + network = Network.testnet() + + # initialize grpc client + client = AsyncClient(network) + await client.initialize_tokens_from_chain_denoms() + composer = await client.composer() + await client.sync_timeout_height() + + message_broadcaster = MsgBroadcasterWithPk.new_using_simulation( + network=network, + private_key=configured_private_key, + ) + + # load account + priv_key = PrivateKey.from_hex(configured_private_key) + pub_key = priv_key.to_public_key() + address = pub_key.to_address() + await client.fetch_account(address.to_acc_bech32()) + + # prepare tx msg + message = composer.msg_instant_expiry_futures_market_launch( + sender=address.to_acc_bech32(), + ticker="INJ/USDC FUT", + quote_denom="USDC", + oracle_base="INJ", + oracle_quote="USDC", + oracle_scale_factor=6, + oracle_type="Band", + expiry=2000000000, + maker_fee_rate=Decimal("-0.0001"), + taker_fee_rate=Decimal("0.001"), + initial_margin_ratio=Decimal("0.33"), + maintenance_margin_ratio=Decimal("0.095"), + min_price_tick_size=Decimal("0.001"), + min_quantity_tick_size=Decimal("0.01"), + ) + + # broadcast the transaction + result = await message_broadcaster.broadcast([message]) + print("---Transaction Response---") + print(result) + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete(main()) diff --git a/examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py b/examples/chain_client/exchange/6_MsgCreateSpotLimitOrder.py similarity index 94% rename from examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py rename to examples/chain_client/exchange/6_MsgCreateSpotLimitOrder.py index d3ca5f16..5b3b966a 100644 --- a/examples/chain_client/exchange/3_MsgCreateSpotLimitOrder.py +++ b/examples/chain_client/exchange/6_MsgCreateSpotLimitOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -37,15 +38,14 @@ async def main() -> None: cid = str(uuid.uuid4()) # prepare tx msg - msg = composer.MsgCreateSpotLimitOrder( + msg = composer.msg_create_spot_limit_order( sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=7.523, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", cid=cid, ) diff --git a/examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py b/examples/chain_client/exchange/7_MsgCreateSpotMarketOrder.py similarity index 94% rename from examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py rename to examples/chain_client/exchange/7_MsgCreateSpotMarketOrder.py index 5229632f..36ea27de 100644 --- a/examples/chain_client/exchange/4_MsgCreateSpotMarketOrder.py +++ b/examples/chain_client/exchange/7_MsgCreateSpotMarketOrder.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -36,14 +37,14 @@ async def main() -> None: fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" # prepare tx msg - msg = composer.MsgCreateSpotMarketOrder( - sender=address.to_acc_bech32(), + msg = composer.msg_create_spot_market_order( market_id=market_id, + sender=address.to_acc_bech32(), subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=10.522, - quantity=0.01, - is_buy=True, + price=Decimal("10.522"), + quantity=Decimal("0.01"), + order_type="BUY", cid=str(uuid.uuid4()), ) diff --git a/examples/chain_client/exchange/5_MsgCancelSpotOrder.py b/examples/chain_client/exchange/8_MsgCancelSpotOrder.py similarity index 100% rename from examples/chain_client/exchange/5_MsgCancelSpotOrder.py rename to examples/chain_client/exchange/8_MsgCancelSpotOrder.py diff --git a/examples/chain_client/exchange/11_MsgBatchUpdateOrders.py b/examples/chain_client/exchange/9_MsgBatchUpdateOrders.py similarity index 83% rename from examples/chain_client/exchange/11_MsgBatchUpdateOrders.py rename to examples/chain_client/exchange/9_MsgBatchUpdateOrders.py index 9efdc0a0..04e41058 100644 --- a/examples/chain_client/exchange/11_MsgBatchUpdateOrders.py +++ b/examples/chain_client/exchange/9_MsgBatchUpdateOrders.py @@ -1,6 +1,7 @@ import asyncio import os import uuid +from decimal import Decimal import dotenv from grpc import RpcError @@ -43,12 +44,12 @@ async def main() -> None: spot_market_id_cancel_2 = "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0" derivative_orders_to_cancel = [ - composer.OrderData( + composer.order_data( market_id=derivative_market_id_cancel, subaccount_id=subaccount_id, order_hash="0x48690013c382d5dbaff9989db04629a16a5818d7524e027d517ccc89fd068103", ), - composer.OrderData( + composer.order_data( market_id=derivative_market_id_cancel_2, subaccount_id=subaccount_id, order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", @@ -56,12 +57,12 @@ async def main() -> None: ] spot_orders_to_cancel = [ - composer.OrderData( + composer.order_data( market_id=spot_market_id_cancel, subaccount_id=subaccount_id, cid="0e5c3ad5-2cc4-4a2a-bbe5-b12697739163", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id_cancel_2, subaccount_id=subaccount_id, order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", @@ -69,49 +70,49 @@ async def main() -> None: ] derivative_orders_to_create = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=derivative_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=25000, - quantity=0.1, - leverage=1, - is_buy=True, - is_po=False, + price=Decimal(25000), + quantity=Decimal(0.1), + margin=composer.calculate_margin( + quantity=Decimal(0.1), price=Decimal(25000), leverage=Decimal(1), is_reduce_only=False + ), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.DerivativeOrder( + composer.derivative_order( market_id=derivative_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=50000, - quantity=0.01, - leverage=1, - is_buy=False, - is_po=False, + price=Decimal(50000), + quantity=Decimal(0.01), + margin=composer.calculate_margin( + quantity=Decimal(0.01), price=Decimal(50000), leverage=Decimal(1), is_reduce_only=False + ), + order_type="SELL", cid=str(uuid.uuid4()), ), ] spot_orders_to_create = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=3, - quantity=55, - is_buy=True, - is_po=False, + price=Decimal("3"), + quantity=Decimal("55"), + order_type="BUY", cid=str(uuid.uuid4()), ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id_create, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=300, - quantity=55, - is_buy=False, - is_po=False, + price=Decimal("300"), + quantity=Decimal("55"), + order_type="SELL", cid=str(uuid.uuid4()), ), ] diff --git a/examples/chain_client/41_MsgCreateInsuranceFund.py b/examples/chain_client/insurance/1_MsgCreateInsuranceFund.py similarity index 100% rename from examples/chain_client/41_MsgCreateInsuranceFund.py rename to examples/chain_client/insurance/1_MsgCreateInsuranceFund.py diff --git a/examples/chain_client/42_MsgUnderwrite.py b/examples/chain_client/insurance/2_MsgUnderwrite.py similarity index 100% rename from examples/chain_client/42_MsgUnderwrite.py rename to examples/chain_client/insurance/2_MsgUnderwrite.py diff --git a/examples/chain_client/43_MsgRequestRedemption.py b/examples/chain_client/insurance/3_MsgRequestRedemption.py similarity index 100% rename from examples/chain_client/43_MsgRequestRedemption.py rename to examples/chain_client/insurance/3_MsgRequestRedemption.py diff --git a/examples/chain_client/23_MsgRelayPriceFeedPrice.py b/examples/chain_client/oracle/1_MsgRelayPriceFeedPrice.py similarity index 100% rename from examples/chain_client/23_MsgRelayPriceFeedPrice.py rename to examples/chain_client/oracle/1_MsgRelayPriceFeedPrice.py diff --git a/examples/chain_client/36_MsgRelayProviderPrices.py b/examples/chain_client/oracle/2_MsgRelayProviderPrices.py similarity index 100% rename from examples/chain_client/36_MsgRelayProviderPrices.py rename to examples/chain_client/oracle/2_MsgRelayProviderPrices.py diff --git a/examples/chain_client/22_MsgSendToEth.py b/examples/chain_client/peggy/1_MsgSendToEth.py similarity index 100% rename from examples/chain_client/22_MsgSendToEth.py rename to examples/chain_client/peggy/1_MsgSendToEth.py diff --git a/examples/chain_client/25_MsgDelegate.py b/examples/chain_client/staking/1_MsgDelegate.py similarity index 100% rename from examples/chain_client/25_MsgDelegate.py rename to examples/chain_client/staking/1_MsgDelegate.py diff --git a/examples/chain_client/71_CreateDenom.py b/examples/chain_client/tokenfactory/1_CreateDenom.py similarity index 100% rename from examples/chain_client/71_CreateDenom.py rename to examples/chain_client/tokenfactory/1_CreateDenom.py diff --git a/examples/chain_client/72_MsgMint.py b/examples/chain_client/tokenfactory/2_MsgMint.py similarity index 100% rename from examples/chain_client/72_MsgMint.py rename to examples/chain_client/tokenfactory/2_MsgMint.py diff --git a/examples/chain_client/73_MsgBurn.py b/examples/chain_client/tokenfactory/3_MsgBurn.py similarity index 100% rename from examples/chain_client/73_MsgBurn.py rename to examples/chain_client/tokenfactory/3_MsgBurn.py diff --git a/examples/chain_client/75_MsgChangeAdmin.py b/examples/chain_client/tokenfactory/4_MsgChangeAdmin.py similarity index 100% rename from examples/chain_client/75_MsgChangeAdmin.py rename to examples/chain_client/tokenfactory/4_MsgChangeAdmin.py diff --git a/examples/chain_client/74_MsgSetDenomMetadata.py b/examples/chain_client/tokenfactory/5_MsgSetDenomMetadata.py similarity index 100% rename from examples/chain_client/74_MsgSetDenomMetadata.py rename to examples/chain_client/tokenfactory/5_MsgSetDenomMetadata.py diff --git a/examples/chain_client/68_DenomAuthorityMetadata.py b/examples/chain_client/tokenfactory/query/1_DenomAuthorityMetadata.py similarity index 100% rename from examples/chain_client/68_DenomAuthorityMetadata.py rename to examples/chain_client/tokenfactory/query/1_DenomAuthorityMetadata.py diff --git a/examples/chain_client/69_DenomsFromCreator.py b/examples/chain_client/tokenfactory/query/2_DenomsFromCreator.py similarity index 100% rename from examples/chain_client/69_DenomsFromCreator.py rename to examples/chain_client/tokenfactory/query/2_DenomsFromCreator.py diff --git a/examples/chain_client/70_TokenfactoryModuleState.py b/examples/chain_client/tokenfactory/query/3_TokenfactoryModuleState.py similarity index 100% rename from examples/chain_client/70_TokenfactoryModuleState.py rename to examples/chain_client/tokenfactory/query/3_TokenfactoryModuleState.py diff --git a/examples/chain_client/37_GetTx.py b/examples/chain_client/tx/query/1_GetTx.py similarity index 100% rename from examples/chain_client/37_GetTx.py rename to examples/chain_client/tx/query/1_GetTx.py diff --git a/examples/chain_client/40_MsgExecuteContract.py b/examples/chain_client/wasm/1_MsgExecuteContract.py similarity index 100% rename from examples/chain_client/40_MsgExecuteContract.py rename to examples/chain_client/wasm/1_MsgExecuteContract.py diff --git a/examples/chain_client/67_ContractsByCreator.py b/examples/chain_client/wasm/query/10_ContractsByCreator.py similarity index 100% rename from examples/chain_client/67_ContractsByCreator.py rename to examples/chain_client/wasm/query/10_ContractsByCreator.py diff --git a/examples/chain_client/58_ContractInfo.py b/examples/chain_client/wasm/query/1_ContractInfo.py similarity index 100% rename from examples/chain_client/58_ContractInfo.py rename to examples/chain_client/wasm/query/1_ContractInfo.py diff --git a/examples/chain_client/59_ContractHistory.py b/examples/chain_client/wasm/query/2_ContractHistory.py similarity index 100% rename from examples/chain_client/59_ContractHistory.py rename to examples/chain_client/wasm/query/2_ContractHistory.py diff --git a/examples/chain_client/60_ContractsByCode.py b/examples/chain_client/wasm/query/3_ContractsByCode.py similarity index 100% rename from examples/chain_client/60_ContractsByCode.py rename to examples/chain_client/wasm/query/3_ContractsByCode.py diff --git a/examples/chain_client/61_AllContractsState.py b/examples/chain_client/wasm/query/4_AllContractsState.py similarity index 100% rename from examples/chain_client/61_AllContractsState.py rename to examples/chain_client/wasm/query/4_AllContractsState.py diff --git a/examples/chain_client/62_RawContractState.py b/examples/chain_client/wasm/query/5_RawContractState.py similarity index 100% rename from examples/chain_client/62_RawContractState.py rename to examples/chain_client/wasm/query/5_RawContractState.py diff --git a/examples/chain_client/63_SmartContractState.py b/examples/chain_client/wasm/query/6_SmartContractState.py similarity index 100% rename from examples/chain_client/63_SmartContractState.py rename to examples/chain_client/wasm/query/6_SmartContractState.py diff --git a/examples/chain_client/64_SmartContractCode.py b/examples/chain_client/wasm/query/7_SmartContractCode.py similarity index 100% rename from examples/chain_client/64_SmartContractCode.py rename to examples/chain_client/wasm/query/7_SmartContractCode.py diff --git a/examples/chain_client/65_SmartContractCodes.py b/examples/chain_client/wasm/query/8_SmartContractCodes.py similarity index 100% rename from examples/chain_client/65_SmartContractCodes.py rename to examples/chain_client/wasm/query/8_SmartContractCodes.py diff --git a/examples/chain_client/66_SmartContractPinnedCodes.py b/examples/chain_client/wasm/query/9_SmartContractPinnedCodes.py similarity index 100% rename from examples/chain_client/66_SmartContractPinnedCodes.py rename to examples/chain_client/wasm/query/9_SmartContractPinnedCodes.py diff --git a/pyinjective/composer.py b/pyinjective/composer.py index df353d6b..9a0807c9 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -13,7 +13,7 @@ from pyinjective.core.token import Token from pyinjective.proto.cosmos.authz.v1beta1 import authz_pb2 as cosmos_authz_pb, tx_pb2 as cosmos_authz_tx_pb from pyinjective.proto.cosmos.bank.v1beta1 import bank_pb2 as bank_pb, tx_pb2 as cosmos_bank_tx_pb -from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as cosmos_dot_base_dot_v1beta1_dot_coin__pb2 +from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as base_coin_pb from pyinjective.proto.cosmos.distribution.v1beta1 import ( distribution_pb2 as cosmos_distribution_pb2, tx_pb2 as cosmos_distribution_tx_pb, @@ -25,15 +25,19 @@ from pyinjective.proto.injective.auction.v1beta1 import tx_pb2 as injective_auction_tx_pb from pyinjective.proto.injective.exchange.v1beta1 import ( authz_pb2 as injective_authz_pb, - exchange_pb2 as injective_dot_exchange_dot_v1beta1_dot_exchange__pb2, + exchange_pb2 as injective_exchange_pb, tx_pb2 as injective_exchange_tx_pb, ) from pyinjective.proto.injective.insurance.v1beta1 import tx_pb2 as injective_insurance_tx_pb -from pyinjective.proto.injective.oracle.v1beta1 import tx_pb2 as injective_oracle_tx_pb +from pyinjective.proto.injective.oracle.v1beta1 import ( + oracle_pb2 as injective_oracle_pb, + tx_pb2 as injective_oracle_tx_pb, +) from pyinjective.proto.injective.peggy.v1 import msgs_pb2 as injective_peggy_tx_pb from pyinjective.proto.injective.stream.v1beta1 import query_pb2 as chain_stream_query from pyinjective.proto.injective.tokenfactory.v1beta1 import tx_pb2 as token_factory_tx_pb from pyinjective.proto.injective.wasmx.v1 import tx_pb2 as wasmx_tx_pb +from pyinjective.utils.denom import Denom REQUEST_TO_RESPONSE_TYPE_MAP = { "MsgCreateSpotLimitOrder": injective_exchange_tx_pb.MsgCreateSpotLimitOrderResponse, @@ -137,14 +141,14 @@ def Coin(self, amount: int, denom: str): This method is deprecated and will be removed soon. Please use `coin` instead """ warn("This method is deprecated. Use coin instead", DeprecationWarning, stacklevel=2) - return cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin(amount=str(amount), denom=denom) + return base_coin_pb.Coin(amount=str(amount), denom=denom) def coin(self, amount: int, denom: str): """ This method create an instance of Coin gRPC type, considering the amount is already expressed in chain format """ formatted_amount_string = str(int(amount)) - return cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin(amount=formatted_amount_string, denom=denom) + return base_coin_pb.Coin(amount=formatted_amount_string, denom=denom) def create_coin_amount(self, amount: Decimal, token_name: str): """ @@ -154,35 +158,38 @@ def create_coin_amount(self, amount: Decimal, token_name: str): chain_amount = token.chain_formatted_value(human_readable_value=amount) return self.coin(amount=int(chain_amount), denom=token.denom) - def get_order_mask(self, **kwargs): - order_mask = 0 - - if kwargs.get("is_conditional"): - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.CONDITIONAL - else: - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.REGULAR - - if kwargs.get("order_direction") == "buy": - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.DIRECTION_BUY_OR_HIGHER - - elif kwargs.get("order_direction") == "sell": - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.DIRECTION_SELL_OR_LOWER - - if kwargs.get("order_type") == "market": - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.TYPE_MARKET - - elif kwargs.get("order_type") == "limit": - order_mask += injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderMask.TYPE_LIMIT - - if order_mask == 0: - order_mask = 1 - - return order_mask - def OrderData( self, market_id: str, subaccount_id: str, order_hash: Optional[str] = None, cid: Optional[str] = None, **kwargs ): - order_mask = self.get_order_mask(**kwargs) + """ + This method is deprecated and will be removed soon. Please use `order_data` instead + """ + warn("This method is deprecated. Use order_data instead", DeprecationWarning, stacklevel=2) + + is_conditional = kwargs.get("is_conditional", False) + is_buy = kwargs.get("order_direction", "buy") == "buy" + is_market_order = kwargs.get("order_type", "limit") == "market" + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) + + return injective_exchange_tx_pb.OrderData( + market_id=market_id, + subaccount_id=subaccount_id, + order_hash=order_hash, + order_mask=order_mask, + cid=cid, + ) + + def order_data( + self, + market_id: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + is_conditional: Optional[bool] = False, + is_buy: Optional[bool] = False, + is_market_order: Optional[bool] = False, + ) -> injective_exchange_tx_pb.OrderData: + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) return injective_exchange_tx_pb.OrderData( market_id=market_id, @@ -202,6 +209,11 @@ def SpotOrder( cid: Optional[str] = None, **kwargs, ): + """ + This method is deprecated and will be removed soon. Please use `spot_order` instead + """ + warn("This method is deprecated. Use spot_order instead", DeprecationWarning, stacklevel=2) + market = self.spot_markets[market_id] # prepare values @@ -210,20 +222,20 @@ def SpotOrder( trigger_price = market.price_to_chain_format(human_readable_value=Decimal(0)) if kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY + order_type = injective_exchange_pb.OrderType.BUY elif not kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL + order_type = injective_exchange_pb.OrderType.SELL elif kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY_PO + order_type = injective_exchange_pb.OrderType.BUY_PO elif not kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL_PO + order_type = injective_exchange_pb.OrderType.SELL_PO - return injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.SpotOrder( + return injective_exchange_pb.SpotOrder( market_id=market_id, - order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( + order_info=injective_exchange_pb.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=str(int(price)), @@ -234,6 +246,50 @@ def SpotOrder( trigger_price=str(int(trigger_price)), ) + def spot_order( + self, + market_id: str, + subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_pb.SpotOrder: + market = self.spot_markets[market_id] + + chain_quantity = f"{market.quantity_to_chain_format(human_readable_value=quantity).normalize():f}" + chain_price = f"{market.price_to_chain_format(human_readable_value=price).normalize():f}" + + trigger_price = trigger_price or Decimal(0) + chain_trigger_price = f"{market.price_to_chain_format(human_readable_value=trigger_price).normalize():f}" + + chain_order_type = injective_exchange_pb.OrderType.Value(order_type) + + return injective_exchange_pb.SpotOrder( + market_id=market_id, + order_info=injective_exchange_pb.OrderInfo( + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=chain_price, + quantity=chain_quantity, + cid=cid, + ), + order_type=chain_order_type, + trigger_price=chain_trigger_price, + ) + + def calculate_margin( + self, quantity: Decimal, price: Decimal, leverage: Decimal, is_reduce_only: bool = False + ) -> Decimal: + if is_reduce_only: + margin = Decimal(0) + else: + margin = quantity * price / leverage + + return margin + def DerivativeOrder( self, market_id: str, @@ -245,6 +301,10 @@ def DerivativeOrder( cid: Optional[str] = None, **kwargs, ): + """ + This method is deprecated and will be removed soon. Please use `derivative_order` instead + """ + warn("This method is deprecated. Use derivative_order instead", DeprecationWarning, stacklevel=2) market = self.derivative_markets[market_id] if kwargs.get("is_reduce_only", False): @@ -262,32 +322,32 @@ def DerivativeOrder( trigger_price = market.price_to_chain_format(human_readable_value=Decimal(str(trigger_price))) if kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY + order_type = injective_exchange_pb.OrderType.BUY elif not kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL + order_type = injective_exchange_pb.OrderType.SELL elif kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY_PO + order_type = injective_exchange_pb.OrderType.BUY_PO elif not kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL_PO + order_type = injective_exchange_pb.OrderType.SELL_PO elif kwargs.get("stop_buy"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.STOP_BUY + order_type = injective_exchange_pb.OrderType.STOP_BUY elif kwargs.get("stop_sell"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.STOP_SEll + order_type = injective_exchange_pb.OrderType.STOP_SEll elif kwargs.get("take_buy"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.TAKE_BUY + order_type = injective_exchange_pb.OrderType.TAKE_BUY elif kwargs.get("take_sell"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.TAKE_SELL + order_type = injective_exchange_pb.OrderType.TAKE_SELL - return injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.DerivativeOrder( + return injective_exchange_pb.DerivativeOrder( market_id=market_id, - order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( + order_info=injective_exchange_pb.OrderInfo( subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=str(int(price)), @@ -299,60 +359,121 @@ def DerivativeOrder( trigger_price=str(int(trigger_price)), ) - def BinaryOptionsOrder( + def derivative_order( self, market_id: str, subaccount_id: str, fee_recipient: str, - price: float, - quantity: float, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, cid: Optional[str] = None, - **kwargs, - ): - market = self.binary_option_markets[market_id] - denom = kwargs.get("denom", None) + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_pb.DerivativeOrder: + market = self.derivative_markets[market_id] - if kwargs.get("is_reduce_only", False): - margin = 0 - else: - margin = market.calculate_margin_in_chain_format( - human_readable_quantity=Decimal(str(quantity)), - human_readable_price=Decimal(str(price)), - is_buy=kwargs["is_buy"], - special_denom=denom, - ) + chain_quantity = market.quantity_to_chain_format(human_readable_value=quantity) + chain_price = market.price_to_chain_format(human_readable_value=price) + chain_margin = market.margin_to_chain_format(human_readable_value=margin) - # prepare values - price = market.price_to_chain_format(human_readable_value=Decimal(str(price)), special_denom=denom) - trigger_price = market.price_to_chain_format(human_readable_value=Decimal(str(0)), special_denom=denom) - quantity = market.quantity_to_chain_format(human_readable_value=Decimal(str(quantity)), special_denom=denom) + trigger_price = trigger_price or Decimal(0) + chain_trigger_price = market.price_to_chain_format(human_readable_value=trigger_price) - if kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY + return self._basic_derivative_order( + market_id=market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + chain_price=chain_price, + chain_quantity=chain_quantity, + chain_margin=chain_margin, + order_type=order_type, + cid=cid, + chain_trigger_price=chain_trigger_price, + ) - elif not kwargs.get("is_buy") and not kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL + def binary_options_order( + self, + market_id: str, + subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + denom: Optional[Denom] = None, + ) -> injective_exchange_pb.DerivativeOrder: + market = self.binary_option_markets[market_id] - elif kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.BUY_PO + chain_quantity = market.quantity_to_chain_format(human_readable_value=quantity, special_denom=denom) + chain_price = market.price_to_chain_format(human_readable_value=price, special_denom=denom) + chain_margin = market.margin_to_chain_format(human_readable_value=margin, special_denom=denom) - elif not kwargs.get("is_buy") and kwargs.get("is_po"): - order_type = injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderType.SELL_PO + trigger_price = trigger_price or Decimal(0) + chain_trigger_price = market.price_to_chain_format(human_readable_value=trigger_price, special_denom=denom) - return injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.DerivativeOrder( - market_id=market_id, - order_info=injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.OrderInfo( - subaccount_id=subaccount_id, - fee_recipient=fee_recipient, - price=str(int(price)), - quantity=str(int(quantity)), - cid=cid, - ), - margin=str(int(margin)), + return self._basic_derivative_order( + market_id=market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + chain_price=chain_price, + chain_quantity=chain_quantity, + chain_margin=chain_margin, order_type=order_type, - trigger_price=str(int(trigger_price)), + cid=cid, + chain_trigger_price=chain_trigger_price, + ) + + # region Auction module + def MsgBid(self, sender: str, bid_amount: float, round: float): + be_amount = Decimal(str(bid_amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return injective_auction_tx_pb.MsgBid( + sender=sender, + round=round, + bid_amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), + ) + + # endregion + + # region Authz module + def MsgGrantGeneric(self, granter: str, grantee: str, msg_type: str, expire_in: int): + auth = cosmos_authz_pb.GenericAuthorization(msg=msg_type) + any_auth = any_pb2.Any() + any_auth.Pack(auth, type_url_prefix="") + + grant = cosmos_authz_pb.Grant( + authorization=any_auth, + expiration=timestamp_pb2.Timestamp(seconds=(int(time()) + expire_in)), + ) + + return cosmos_authz_tx_pb.MsgGrant(granter=granter, grantee=grantee, grant=grant) + + def MsgExec(self, grantee: str, msgs: List): + any_msgs: List[any_pb2.Any] = [] + for msg in msgs: + any_msg = any_pb2.Any() + any_msg.Pack(msg, type_url_prefix="") + any_msgs.append(any_msg) + + return cosmos_authz_tx_pb.MsgExec(grantee=grantee, msgs=any_msgs) + + def MsgRevoke(self, granter: str, grantee: str, msg_type: str): + return cosmos_authz_tx_pb.MsgRevoke(granter=granter, grantee=grantee, msg_type_url=msg_type) + + def msg_execute_contract_compat(self, sender: str, contract: str, msg: str, funds: str): + return wasmx_tx_pb.MsgExecuteContractCompat( + sender=sender, + contract=contract, + msg=msg, + funds=funds, ) + # endregion + + # region Bank module def MsgSend(self, from_address: str, to_address: str, amount: float, denom: str): coin = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) @@ -362,16 +483,14 @@ def MsgSend(self, from_address: str, to_address: str, amount: float, denom: str) amount=[coin], ) - def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): - return wasm_tx_pb.MsgExecuteContract( - sender=sender, - contract=contract, - msg=bytes(msg, "utf-8"), - funds=kwargs.get("funds") # funds is a list of cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin. - # The coins in the list must be sorted in alphabetical order by denoms. - ) + # endregion + # region Chain Exchange module def MsgDeposit(self, sender: str, subaccount_id: str, amount: float, denom: str): + """ + This method is deprecated and will be removed soon. Please use `msg_deposit` instead + """ + warn("This method is deprecated. Use msg_deposit instead", DeprecationWarning, stacklevel=2) coin = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgDeposit( @@ -380,6 +499,153 @@ def MsgDeposit(self, sender: str, subaccount_id: str, amount: float, denom: str) amount=coin, ) + def msg_deposit(self, sender: str, subaccount_id: str, amount: Decimal, denom: str): + coin = self.create_coin_amount(amount=amount, token_name=denom) + + return injective_exchange_tx_pb.MsgDeposit( + sender=sender, + subaccount_id=subaccount_id, + amount=coin, + ) + + def MsgWithdraw(self, sender: str, subaccount_id: str, amount: float, denom: str): + """ + This method is deprecated and will be removed soon. Please use `msg_withdraw` instead + """ + warn("This method is deprecated. Use msg_withdraw instead", DeprecationWarning, stacklevel=2) + be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) + + return injective_exchange_tx_pb.MsgWithdraw( + sender=sender, + subaccount_id=subaccount_id, + amount=be_amount, + ) + + def msg_withdraw(self, sender: str, subaccount_id: str, amount: Decimal, denom: str): + be_amount = self.create_coin_amount(amount=amount, token_name=denom) + + return injective_exchange_tx_pb.MsgWithdraw( + sender=sender, + subaccount_id=subaccount_id, + amount=be_amount, + ) + + def msg_instant_spot_market_launch( + self, + sender: str, + ticker: str, + base_denom: str, + quote_denom: str, + min_price_tick_size: Decimal, + min_quantity_tick_size: Decimal, + ) -> injective_exchange_tx_pb.MsgInstantSpotMarketLaunch: + base_token = self.tokens[base_denom] + quote_token = self.tokens[quote_denom] + + chain_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals - base_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + chain_min_quantity_tick_size = min_quantity_tick_size * Decimal( + f"1e{base_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + + return injective_exchange_tx_pb.MsgInstantSpotMarketLaunch( + sender=sender, + ticker=ticker, + base_denom=base_token.denom, + quote_denom=quote_token.denom, + min_price_tick_size=f"{chain_min_price_tick_size.normalize():f}", + min_quantity_tick_size=f"{chain_min_quantity_tick_size.normalize():f}", + ) + + def msg_instant_perpetual_market_launch( + self, + sender: str, + ticker: str, + quote_denom: str, + oracle_base: str, + oracle_quote: str, + oracle_scale_factor: int, + oracle_type: str, + maker_fee_rate: Decimal, + taker_fee_rate: Decimal, + initial_margin_ratio: Decimal, + maintenance_margin_ratio: Decimal, + min_price_tick_size: Decimal, + min_quantity_tick_size: Decimal, + ) -> injective_exchange_tx_pb.MsgInstantPerpetualMarketLaunch: + quote_token = self.tokens[quote_denom] + + chain_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + chain_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_initial_margin_ratio = initial_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maintenance_margin_ratio = maintenance_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return injective_exchange_tx_pb.MsgInstantPerpetualMarketLaunch( + sender=sender, + ticker=ticker, + quote_denom=quote_token.denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_scale_factor=oracle_scale_factor, + oracle_type=injective_oracle_pb.OracleType.Value(oracle_type), + maker_fee_rate=f"{chain_maker_fee_rate.normalize():f}", + taker_fee_rate=f"{chain_taker_fee_rate.normalize():f}", + initial_margin_ratio=f"{chain_initial_margin_ratio.normalize():f}", + maintenance_margin_ratio=f"{chain_maintenance_margin_ratio.normalize():f}", + min_price_tick_size=f"{chain_min_price_tick_size.normalize():f}", + min_quantity_tick_size=f"{chain_min_quantity_tick_size.normalize():f}", + ) + + def msg_instant_expiry_futures_market_launch( + self, + sender: str, + ticker: str, + quote_denom: str, + oracle_base: str, + oracle_quote: str, + oracle_scale_factor: int, + oracle_type: str, + expiry: int, + maker_fee_rate: Decimal, + taker_fee_rate: Decimal, + initial_margin_ratio: Decimal, + maintenance_margin_ratio: Decimal, + min_price_tick_size: Decimal, + min_quantity_tick_size: Decimal, + ) -> injective_exchange_tx_pb.MsgInstantPerpetualMarketLaunch: + quote_token = self.tokens[quote_denom] + + chain_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + chain_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_initial_margin_ratio = initial_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maintenance_margin_ratio = maintenance_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return injective_exchange_tx_pb.MsgInstantExpiryFuturesMarketLaunch( + sender=sender, + ticker=ticker, + quote_denom=quote_token.denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_scale_factor=oracle_scale_factor, + oracle_type=injective_oracle_pb.OracleType.Value(oracle_type), + expiry=expiry, + maker_fee_rate=f"{chain_maker_fee_rate.normalize():f}", + taker_fee_rate=f"{chain_taker_fee_rate.normalize():f}", + initial_margin_ratio=f"{chain_initial_margin_ratio.normalize():f}", + maintenance_margin_ratio=f"{chain_maintenance_margin_ratio.normalize():f}", + min_price_tick_size=f"{chain_min_price_tick_size.normalize():f}", + min_quantity_tick_size=f"{chain_min_quantity_tick_size.normalize():f}", + ) + def MsgCreateSpotLimitOrder( self, market_id: str, @@ -391,52 +657,151 @@ def MsgCreateSpotLimitOrder( cid: Optional[str] = None, **kwargs, ): + """ + This method is deprecated and will be removed soon. Please use `msg_create_spot_limit_order` instead + """ + warn("This method is deprecated. Use msg_create_spot_limit_order instead", DeprecationWarning, stacklevel=2) + + order_type_name = "BUY" + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) + + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + return injective_exchange_tx_pb.MsgCreateSpotLimitOrder( sender=sender, - order=self.SpotOrder( + order=self.spot_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=price, - quantity=quantity, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + order_type=order_type_name, cid=cid, - **kwargs, ), ) - def MsgCreateSpotMarketOrder( + def msg_create_spot_limit_order( self, market_id: str, sender: str, subaccount_id: str, fee_recipient: str, - price: float, - quantity: float, - is_buy: bool, + price: Decimal, + quantity: Decimal, + order_type: str, cid: Optional[str] = None, - ): - return injective_exchange_tx_pb.MsgCreateSpotMarketOrder( + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_tx_pb.MsgCreateSpotLimitOrder: + return injective_exchange_tx_pb.MsgCreateSpotLimitOrder( sender=sender, - order=self.SpotOrder( + order=self.spot_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=price, quantity=quantity, - is_buy=is_buy, + order_type=order_type, cid=cid, + trigger_price=trigger_price, ), ) - def MsgCancelSpotOrder( + def MsgBatchCreateSpotLimitOrders(self, sender: str, orders: List): + """ + This method is deprecated and will be removed soon. Please use `msg_batch_create_spot_limit_orders` instead + """ + warn( + "This method is deprecated. Use msg_batch_create_spot_limit_orders instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders(sender=sender, orders=orders) + + def msg_batch_create_spot_limit_orders( + self, sender: str, orders: List[injective_exchange_pb.SpotOrder] + ) -> injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders: + return injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders(sender=sender, orders=orders) + + def MsgCreateSpotMarketOrder( self, market_id: str, sender: str, subaccount_id: str, - order_hash: Optional[str] = None, + fee_recipient: str, + price: float, + quantity: float, + is_buy: bool, cid: Optional[str] = None, ): - return injective_exchange_tx_pb.MsgCancelSpotOrder( + """ + This method is deprecated and will be removed soon. Please use `msg_create_spot_market_order` instead + """ + warn("This method is deprecated. Use msg_create_spot_market_order instead", DeprecationWarning, stacklevel=2) + + order_type_name = "BUY" + if not is_buy: + order_type_name = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + return injective_exchange_tx_pb.MsgCreateSpotMarketOrder( + sender=sender, + order=self.spot_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + order_type=order_type_name, + cid=cid, + ), + ) + + def msg_create_spot_market_order( + self, + market_id: str, + sender: str, + subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_tx_pb.MsgCreateSpotMarketOrder: + return injective_exchange_tx_pb.MsgCreateSpotMarketOrder( + sender=sender, + order=self.spot_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ), + ) + + def MsgCancelSpotOrder( + self, + market_id: str, + sender: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + ): + """ + This method is deprecated and will be removed soon. Please use `msg_cancel_spot_order` instead + """ + warn("This method is deprecated. Use msg_cancel_spot_order instead", DeprecationWarning, stacklevel=2) + return injective_exchange_tx_pb.MsgCancelSpotOrder( sender=sender, market_id=market_id, subaccount_id=subaccount_id, @@ -444,14 +809,111 @@ def MsgCancelSpotOrder( cid=cid, ) - def MsgBatchCreateSpotLimitOrders(self, sender: str, orders: List): - return injective_exchange_tx_pb.MsgBatchCreateSpotLimitOrders(sender=sender, orders=orders) + def msg_cancel_spot_order( + self, + market_id: str, + sender: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + ) -> injective_exchange_tx_pb.MsgCancelSpotOrder: + return injective_exchange_tx_pb.MsgCancelSpotOrder( + sender=sender, + market_id=market_id, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + ) def MsgBatchCancelSpotOrders(self, sender: str, data: List): + """ + This method is deprecated and will be removed soon. Please use `msg_batch_cancel_spot_orders` instead + """ + warn("This method is deprecated. Use msg_batch_cancel_spot_orders instead", DeprecationWarning, stacklevel=2) return injective_exchange_tx_pb.MsgBatchCancelSpotOrders(sender=sender, data=data) - def MsgRewardsOptOut(self, sender: str): - return injective_exchange_tx_pb.MsgRewardsOptOut(sender=sender) + def msg_batch_cancel_spot_orders( + self, sender: str, orders_data: List[injective_exchange_tx_pb.OrderData] + ) -> injective_exchange_tx_pb.MsgBatchCancelSpotOrders: + return injective_exchange_tx_pb.MsgBatchCancelSpotOrders(sender=sender, data=orders_data) + + def MsgBatchUpdateOrders(self, sender: str, **kwargs): + """ + This method is deprecated and will be removed soon. Please use `msg_batch_update_orders` instead + """ + warn("This method is deprecated. Use msg_batch_update_orders instead", DeprecationWarning, stacklevel=2) + return injective_exchange_tx_pb.MsgBatchUpdateOrders( + sender=sender, + subaccount_id=kwargs.get("subaccount_id"), + spot_market_ids_to_cancel_all=kwargs.get("spot_market_ids_to_cancel_all"), + derivative_market_ids_to_cancel_all=kwargs.get("derivative_market_ids_to_cancel_all"), + spot_orders_to_cancel=kwargs.get("spot_orders_to_cancel"), + derivative_orders_to_cancel=kwargs.get("derivative_orders_to_cancel"), + spot_orders_to_create=kwargs.get("spot_orders_to_create"), + derivative_orders_to_create=kwargs.get("derivative_orders_to_create"), + binary_options_orders_to_cancel=kwargs.get("binary_options_orders_to_cancel"), + binary_options_market_ids_to_cancel_all=kwargs.get("binary_options_market_ids_to_cancel_all"), + binary_options_orders_to_create=kwargs.get("binary_options_orders_to_create"), + ) + + def msg_batch_update_orders( + self, + sender: str, + subaccount_id: Optional[str] = None, + spot_market_ids_to_cancel_all: Optional[List[str]] = None, + derivative_market_ids_to_cancel_all: Optional[List[str]] = None, + spot_orders_to_cancel: Optional[List[injective_exchange_tx_pb.OrderData]] = None, + derivative_orders_to_cancel: Optional[List[injective_exchange_tx_pb.OrderData]] = None, + spot_orders_to_create: Optional[List[injective_exchange_pb.SpotOrder]] = None, + derivative_orders_to_create: Optional[List[injective_exchange_pb.DerivativeOrder]] = None, + binary_options_orders_to_cancel: Optional[List[injective_exchange_tx_pb.OrderData]] = None, + binary_options_market_ids_to_cancel_all: Optional[List[str]] = None, + binary_options_orders_to_create: Optional[List[injective_exchange_pb.DerivativeOrder]] = None, + ) -> injective_exchange_tx_pb.MsgBatchUpdateOrders: + return injective_exchange_tx_pb.MsgBatchUpdateOrders( + sender=sender, + subaccount_id=subaccount_id, + spot_market_ids_to_cancel_all=spot_market_ids_to_cancel_all, + derivative_market_ids_to_cancel_all=derivative_market_ids_to_cancel_all, + spot_orders_to_cancel=spot_orders_to_cancel, + derivative_orders_to_cancel=derivative_orders_to_cancel, + spot_orders_to_create=spot_orders_to_create, + derivative_orders_to_create=derivative_orders_to_create, + binary_options_orders_to_cancel=binary_options_orders_to_cancel, + binary_options_market_ids_to_cancel_all=binary_options_market_ids_to_cancel_all, + binary_options_orders_to_create=binary_options_orders_to_create, + ) + + def MsgPrivilegedExecuteContract( + self, sender: str, contract: str, msg: str, **kwargs + ) -> injective_exchange_tx_pb.MsgPrivilegedExecuteContract: + """ + This method is deprecated and will be removed soon. Please use `msg_privileged_execute_contract` instead + """ + warn("This method is deprecated. Use msg_privileged_execute_contract instead", DeprecationWarning, stacklevel=2) + + return injective_exchange_tx_pb.MsgPrivilegedExecuteContract( + sender=sender, + contract_address=contract, + data=msg, + funds=kwargs.get("funds") # funds is a string of Coin strings, comma separated, + # e.g. 100000inj,20000000000usdt + ) + + def msg_privileged_execute_contract( + self, + sender: str, + contract_address: str, + data: str, + funds: Optional[str] = None, + ) -> injective_exchange_tx_pb.MsgPrivilegedExecuteContract: + # funds is a string of Coin strings, comma separated, e.g. 100000inj,20000000000usdt + return injective_exchange_tx_pb.MsgPrivilegedExecuteContract( + sender=sender, + contract_address=contract_address, + data=data, + funds=funds, + ) def MsgCreateDerivativeLimitOrder( self, @@ -464,46 +926,105 @@ def MsgCreateDerivativeLimitOrder( cid: Optional[str] = None, **kwargs, ): + """ + This method is deprecated and will be removed soon. Please use `msg_create_derivative_limit_order` instead + """ + warn( + "This method is deprecated. Use msg_create_derivative_limit_order instead", DeprecationWarning, stacklevel=2 + ) + + if kwargs.get("is_reduce_only", False): + margin = Decimal(0) + else: + margin = Decimal(str(price)) * Decimal(str(quantity)) / Decimal(str(kwargs["leverage"])) + + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) + + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + + elif kwargs.get("stop_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_BUY) + + elif kwargs.get("stop_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_SEll) + + elif kwargs.get("take_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_BUY) + + elif kwargs.get("take_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_SELL) + return injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder( sender=sender, - order=self.DerivativeOrder( + order=self.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=price, - quantity=quantity, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + margin=margin, + order_type=order_type, cid=cid, - **kwargs, + trigger_price=Decimal(str(kwargs["trigger_price"])) if "trigger_price" in kwargs else None, ), ) - def MsgCreateDerivativeMarketOrder( + def msg_create_derivative_limit_order( self, market_id: str, sender: str, subaccount_id: str, fee_recipient: str, - price: float, - quantity: float, - is_buy: bool, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, cid: Optional[str] = None, - **kwargs, - ): - return injective_exchange_tx_pb.MsgCreateDerivativeMarketOrder( + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder: + return injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder( sender=sender, - order=self.DerivativeOrder( + order=self.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=price, quantity=quantity, - is_buy=is_buy, + margin=margin, + order_type=order_type, cid=cid, - **kwargs, + trigger_price=trigger_price, ), ) - def MsgCreateBinaryOptionsLimitOrder( + def MsgBatchCreateDerivativeLimitOrders(self, sender: str, orders: List): + """ + This method is deprecated and will be removed soon. + Please use `msg_batch_create_derivative_limit_orders` instead + """ + warn( + "This method is deprecated. Use msg_batch_create_derivative_limit_orders instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders(sender=sender, orders=orders) + + def msg_batch_create_derivative_limit_orders( + self, + sender: str, + orders: List[injective_exchange_pb.DerivativeOrder], + ) -> injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders: + return injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders(sender=sender, orders=orders) + + def MsgCreateDerivativeMarketOrder( self, market_id: str, sender: str, @@ -514,95 +1035,156 @@ def MsgCreateBinaryOptionsLimitOrder( cid: Optional[str] = None, **kwargs, ): - return injective_exchange_tx_pb.MsgCreateBinaryOptionsLimitOrder( + """ + This method is deprecated and will be removed soon. Please use `msg_create_derivative_market_order` instead + """ + warn( + "This method is deprecated. Use msg_create_derivative_market_order instead", + DeprecationWarning, + stacklevel=2, + ) + + if kwargs.get("is_reduce_only", False): + margin = Decimal(0) + else: + margin = Decimal(str(price)) * Decimal(str(quantity)) / Decimal(str(kwargs["leverage"])) + + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) + + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + + elif kwargs.get("stop_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_BUY) + + elif kwargs.get("stop_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_SEll) + + elif kwargs.get("take_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_BUY) + + elif kwargs.get("take_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_SELL) + + return injective_exchange_tx_pb.MsgCreateDerivativeMarketOrder( sender=sender, - order=self.BinaryOptionsOrder( + order=self.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=price, - quantity=quantity, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + margin=margin, + order_type=order_type, cid=cid, - **kwargs, + trigger_price=Decimal(str(kwargs["trigger_price"])) if "trigger_price" in kwargs else None, ), ) - def MsgCreateBinaryOptionsMarketOrder( + def msg_create_derivative_market_order( self, market_id: str, sender: str, subaccount_id: str, fee_recipient: str, - price: float, - quantity: float, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, cid: Optional[str] = None, - **kwargs, - ): - return injective_exchange_tx_pb.MsgCreateBinaryOptionsMarketOrder( + trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_tx_pb.MsgCreateDerivativeMarketOrder: + return injective_exchange_tx_pb.MsgCreateDerivativeMarketOrder( sender=sender, - order=self.BinaryOptionsOrder( + order=self.derivative_order( market_id=market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, price=price, quantity=quantity, + margin=margin, + order_type=order_type, cid=cid, - **kwargs, + trigger_price=trigger_price, ), ) - def MsgCancelBinaryOptionsOrder( + def MsgCancelDerivativeOrder( self, - sender: str, market_id: str, + sender: str, subaccount_id: str, order_hash: Optional[str] = None, cid: Optional[str] = None, + **kwargs, ): - return injective_exchange_tx_pb.MsgCancelBinaryOptionsOrder( + """ + This method is deprecated and will be removed soon. Please use `msg_cancel_derivative_order` instead + """ + warn( + "This method is deprecated. Use msg_cancel_derivative_order instead", + DeprecationWarning, + stacklevel=2, + ) + + is_conditional = kwargs.get("is_conditional", False) + is_buy = kwargs.get("order_direction", "buy") == "buy" + is_market_order = kwargs.get("order_type", "limit") == "market" + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) + + return injective_exchange_tx_pb.MsgCancelDerivativeOrder( sender=sender, market_id=market_id, subaccount_id=subaccount_id, order_hash=order_hash, + order_mask=order_mask, cid=cid, ) - def MsgAdminUpdateBinaryOptionsMarket( + def msg_cancel_derivative_order( self, - sender: str, market_id: str, - status: str, - **kwargs, - ): - price_to_bytes = None - - if kwargs.get("settlement_price") is not None: - scale_price = Decimal((kwargs.get("settlement_price") * pow(10, 18))) - price_to_bytes = bytes(str(scale_price), "utf-8") - - else: - price_to_bytes = "" + sender: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + is_conditional: Optional[bool] = False, + is_buy: Optional[bool] = False, + is_market_order: Optional[bool] = False, + ) -> injective_exchange_tx_pb.MsgCancelDerivativeOrder: + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) - return injective_exchange_tx_pb.MsgAdminUpdateBinaryOptionsMarket( + return injective_exchange_tx_pb.MsgCancelDerivativeOrder( sender=sender, market_id=market_id, - settlement_price=price_to_bytes, - expiration_timestamp=kwargs.get("expiration_timestamp"), - settlement_timestamp=kwargs.get("settlement_timestamp"), - status=status, + subaccount_id=subaccount_id, + order_hash=order_hash, + order_mask=order_mask, + cid=cid, ) - def MsgRelayProviderPrices(self, sender: str, provider: str, symbols: list, prices: list): - oracle_prices = [] - - for price in prices: - scale_price = Decimal((price) * pow(10, 18)) - price_to_bytes = bytes(str(scale_price), "utf-8") - oracle_prices.append(price_to_bytes) - - return injective_oracle_tx_pb.MsgRelayProviderPrices( - sender=sender, provider=provider, symbols=symbols, prices=oracle_prices + def MsgBatchCancelDerivativeOrders(self, sender: str, data: List): + """ + This method is deprecated and will be removed soon. Please use `msg_batch_cancel_derivative_orders` instead + """ + warn( + "This method is deprecated. Use msg_batch_cancel_derivative_orders instead", + DeprecationWarning, + stacklevel=2, ) + return injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders(sender=sender, data=data) + + def msg_batch_cancel_derivative_orders( + self, sender: str, orders_data: List[injective_exchange_tx_pb.OrderData] + ) -> injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders: + return injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders(sender=sender, data=orders_data) def MsgInstantBinaryOptionsMarketLaunch( self, @@ -622,6 +1204,15 @@ def MsgInstantBinaryOptionsMarketLaunch( min_quantity_tick_size: float, **kwargs, ): + """ + This method is deprecated and will be removed soon. + Please use `msg_instant_binary_options_market_launch` instead + """ + warn( + "This method is deprecated. Use msg_instant_binary_options_market_launch instead", + DeprecationWarning, + stacklevel=2, + ) scaled_maker_fee_rate = Decimal((maker_fee_rate * pow(10, 18))) maker_fee_to_bytes = bytes(str(scaled_maker_fee_rate), "utf-8") @@ -651,75 +1242,281 @@ def MsgInstantBinaryOptionsMarketLaunch( admin=kwargs.get("admin"), ) - def MsgCancelDerivativeOrder( + def msg_instant_binary_options_market_launch( self, - market_id: str, sender: str, - subaccount_id: str, - order_hash: Optional[str] = None, - cid: Optional[str] = None, - **kwargs, - ): - order_mask = self.get_order_mask(**kwargs) - - return injective_exchange_tx_pb.MsgCancelDerivativeOrder( + ticker: str, + oracle_symbol: str, + oracle_provider: str, + oracle_type: str, + oracle_scale_factor: int, + maker_fee_rate: Decimal, + taker_fee_rate: Decimal, + expiration_timestamp: int, + settlement_timestamp: int, + admin: str, + quote_denom: str, + min_price_tick_size: Decimal, + min_quantity_tick_size: Decimal, + ) -> injective_exchange_tx_pb.MsgInstantPerpetualMarketLaunch: + quote_token = self.tokens[quote_denom] + + chain_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + chain_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + chain_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return injective_exchange_tx_pb.MsgInstantBinaryOptionsMarketLaunch( sender=sender, - market_id=market_id, - subaccount_id=subaccount_id, - order_hash=order_hash, - order_mask=order_mask, - cid=cid, + ticker=ticker, + oracle_symbol=oracle_symbol, + oracle_provider=oracle_provider, + oracle_type=injective_oracle_pb.OracleType.Value(oracle_type), + oracle_scale_factor=oracle_scale_factor, + maker_fee_rate=f"{chain_maker_fee_rate.normalize():f}", + taker_fee_rate=f"{chain_taker_fee_rate.normalize():f}", + expiration_timestamp=expiration_timestamp, + settlement_timestamp=settlement_timestamp, + admin=admin, + quote_denom=quote_token.denom, + min_price_tick_size=f"{chain_min_price_tick_size.normalize():f}", + min_quantity_tick_size=f"{chain_min_quantity_tick_size.normalize():f}", ) - def MsgBatchCreateDerivativeLimitOrders(self, sender: str, orders: List): - return injective_exchange_tx_pb.MsgBatchCreateDerivativeLimitOrders(sender=sender, orders=orders) + def MsgCreateBinaryOptionsLimitOrder( + self, + market_id: str, + sender: str, + subaccount_id: str, + fee_recipient: str, + price: float, + quantity: float, + cid: Optional[str] = None, + **kwargs, + ): + """ + This method is deprecated and will be removed soon. Please use `msg_create_binary_options_limit_order` instead + """ + warn( + "This method is deprecated. Use msg_create_binary_options_limit_order instead", + DeprecationWarning, + stacklevel=2, + ) + if kwargs.get("is_reduce_only", False): + margin = Decimal(0) + else: + margin = Decimal(str(price)) * Decimal(str(quantity)) - def MsgBatchCancelDerivativeOrders(self, sender: str, data: List): - return injective_exchange_tx_pb.MsgBatchCancelDerivativeOrders(sender=sender, data=data) + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) - def MsgBatchUpdateOrders(self, sender: str, **kwargs): - return injective_exchange_tx_pb.MsgBatchUpdateOrders( + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + + elif kwargs.get("stop_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_BUY) + + elif kwargs.get("stop_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_SEll) + + elif kwargs.get("take_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_BUY) + + elif kwargs.get("take_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_SELL) + + return injective_exchange_tx_pb.MsgCreateBinaryOptionsLimitOrder( sender=sender, - subaccount_id=kwargs.get("subaccount_id"), - spot_market_ids_to_cancel_all=kwargs.get("spot_market_ids_to_cancel_all"), - derivative_market_ids_to_cancel_all=kwargs.get("derivative_market_ids_to_cancel_all"), - spot_orders_to_cancel=kwargs.get("spot_orders_to_cancel"), - derivative_orders_to_cancel=kwargs.get("derivative_orders_to_cancel"), - spot_orders_to_create=kwargs.get("spot_orders_to_create"), - derivative_orders_to_create=kwargs.get("derivative_orders_to_create"), - binary_options_orders_to_cancel=kwargs.get("binary_options_orders_to_cancel"), - binary_options_market_ids_to_cancel_all=kwargs.get("binary_options_market_ids_to_cancel_all"), - binary_options_orders_to_create=kwargs.get("binary_options_orders_to_create"), + order=self.binary_options_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=Decimal(str(kwargs["trigger_price"])) if "trigger_price" in kwargs else None, + denom=kwargs.get("denom"), + ), ) - def MsgLiquidatePosition( + def msg_create_binary_options_limit_order( self, + market_id: str, sender: str, subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + denom: Optional[Denom] = None, + ) -> injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder: + return injective_exchange_tx_pb.MsgCreateDerivativeLimitOrder( + sender=sender, + order=self.binary_options_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + denom=denom, + ), + ) + + def MsgCreateBinaryOptionsMarketOrder( + self, market_id: str, - order: Optional[injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.DerivativeOrder] = None, + sender: str, + subaccount_id: str, + fee_recipient: str, + price: float, + quantity: float, + cid: Optional[str] = None, + **kwargs, ): - return injective_exchange_tx_pb.MsgLiquidatePosition( - sender=sender, subaccount_id=subaccount_id, market_id=market_id, order=order + """ + This method is deprecated and will be removed soon. Please use `msg_create_binary_options_market_order` instead + """ + warn( + "This method is deprecated. Use msg_create_binary_options_market_order instead", + DeprecationWarning, + stacklevel=2, ) + if kwargs.get("is_reduce_only", False): + margin = Decimal(0) + else: + margin = Decimal(str(price)) * Decimal(str(quantity)) - def MsgIncreasePositionMargin( + if kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY) + + elif not kwargs.get("is_buy") and not kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL) + + elif kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.BUY_PO) + + elif not kwargs.get("is_buy") and kwargs.get("is_po"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.SELL_PO) + + elif kwargs.get("stop_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_BUY) + + elif kwargs.get("stop_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.STOP_SEll) + + elif kwargs.get("take_buy"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_BUY) + + elif kwargs.get("take_sell"): + order_type = injective_exchange_pb.OrderType.Name(injective_exchange_pb.OrderType.TAKE_SELL) + + return injective_exchange_tx_pb.MsgCreateBinaryOptionsMarketOrder( + sender=sender, + order=self.binary_options_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=Decimal(str(price)), + quantity=Decimal(str(quantity)), + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=Decimal(str(kwargs["trigger_price"])) if "trigger_price" in kwargs else None, + denom=kwargs.get("denom"), + ), + ) + + def msg_create_binary_options_market_order( + self, + market_id: str, + sender: str, + subaccount_id: str, + fee_recipient: str, + price: Decimal, + quantity: Decimal, + margin: Decimal, + order_type: str, + cid: Optional[str] = None, + trigger_price: Optional[Decimal] = None, + denom: Optional[Denom] = None, + ): + return injective_exchange_tx_pb.MsgCreateBinaryOptionsMarketOrder( + sender=sender, + order=self.binary_options_order( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + denom=denom, + ), + ) + + def MsgCancelBinaryOptionsOrder( self, sender: str, - source_subaccount_id: str, - destination_subaccount_id: str, market_id: str, - amount: float, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, ): - market = self.derivative_markets[market_id] + """ + This method is deprecated and will be removed soon. Please use `msg_cancel_binary_options_order` instead + """ + warn( + "This method is deprecated. Use msg_cancel_binary_options_order instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgCancelBinaryOptionsOrder( + sender=sender, + market_id=market_id, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + ) - additional_margin = market.margin_to_chain_format(human_readable_value=Decimal(str(amount))) - return injective_exchange_tx_pb.MsgIncreasePositionMargin( + def msg_cancel_binary_options_order( + self, + market_id: str, + sender: str, + subaccount_id: str, + order_hash: Optional[str] = None, + cid: Optional[str] = None, + is_conditional: Optional[bool] = False, + is_buy: Optional[bool] = False, + is_market_order: Optional[bool] = False, + ) -> injective_exchange_tx_pb.MsgCancelBinaryOptionsOrder: + order_mask = self._order_mask(is_conditional=is_conditional, is_buy=is_buy, is_market_order=is_market_order) + + return injective_exchange_tx_pb.MsgCancelBinaryOptionsOrder( sender=sender, - source_subaccount_id=source_subaccount_id, - destination_subaccount_id=destination_subaccount_id, market_id=market_id, - amount=str(int(additional_margin)), + subaccount_id=subaccount_id, + order_hash=order_hash, + order_mask=order_mask, + cid=cid, ) def MsgSubaccountTransfer( @@ -730,6 +1527,14 @@ def MsgSubaccountTransfer( amount: int, denom: str, ): + """ + This method is deprecated and will be removed soon. Please use `msg_subaccount_transfer` instead + """ + warn( + "This method is deprecated. Use msg_subaccount_transfer instead", + DeprecationWarning, + stacklevel=2, + ) be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgSubaccountTransfer( @@ -739,12 +1544,20 @@ def MsgSubaccountTransfer( amount=be_amount, ) - def MsgWithdraw(self, sender: str, subaccount_id: str, amount: float, denom: str): - be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) + def msg_subaccount_transfer( + self, + sender: str, + source_subaccount_id: str, + destination_subaccount_id: str, + amount: Decimal, + denom: str, + ) -> injective_exchange_tx_pb.MsgSubaccountTransfer: + be_amount = self.create_coin_amount(amount=amount, token_name=denom) - return injective_exchange_tx_pb.MsgWithdraw( + return injective_exchange_tx_pb.MsgSubaccountTransfer( sender=sender, - subaccount_id=subaccount_id, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, amount=be_amount, ) @@ -756,6 +1569,14 @@ def MsgExternalTransfer( amount: int, denom: str, ): + """ + This method is deprecated and will be removed soon. Please use `msg_external_transfer` instead + """ + warn( + "This method is deprecated. Use msg_external_transfer instead", + DeprecationWarning, + stacklevel=2, + ) coin = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgExternalTransfer( @@ -765,129 +1586,184 @@ def MsgExternalTransfer( amount=coin, ) - def MsgBid(self, sender: str, bid_amount: float, round: float): - be_amount = Decimal(str(bid_amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + def msg_external_transfer( + self, + sender: str, + source_subaccount_id: str, + destination_subaccount_id: str, + amount: Decimal, + denom: str, + ) -> injective_exchange_tx_pb.MsgExternalTransfer: + coin = self.create_coin_amount(amount=amount, token_name=denom) - return injective_auction_tx_pb.MsgBid( + return injective_exchange_tx_pb.MsgExternalTransfer( sender=sender, - round=round, - bid_amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + amount=coin, ) - def MsgGrantGeneric(self, granter: str, grantee: str, msg_type: str, expire_in: int): - auth = cosmos_authz_pb.GenericAuthorization(msg=msg_type) - any_auth = any_pb2.Any() - any_auth.Pack(auth, type_url_prefix="") - - grant = cosmos_authz_pb.Grant( - authorization=any_auth, - expiration=timestamp_pb2.Timestamp(seconds=(int(time()) + expire_in)), + def MsgLiquidatePosition( + self, + sender: str, + subaccount_id: str, + market_id: str, + order: Optional[injective_exchange_pb.DerivativeOrder] = None, + ): + """ + This method is deprecated and will be removed soon. Please use `msg_liquidate_position` instead + """ + warn( + "This method is deprecated. Use msg_liquidate_position instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgLiquidatePosition( + sender=sender, subaccount_id=subaccount_id, market_id=market_id, order=order ) - return cosmos_authz_tx_pb.MsgGrant(granter=granter, grantee=grantee, grant=grant) + def msg_liquidate_position( + self, + sender: str, + subaccount_id: str, + market_id: str, + order: Optional[injective_exchange_pb.DerivativeOrder] = None, + ) -> injective_exchange_tx_pb.MsgLiquidatePosition: + return injective_exchange_tx_pb.MsgLiquidatePosition( + sender=sender, subaccount_id=subaccount_id, market_id=market_id, order=order + ) - def MsgGrantTyped( + def msg_emergency_settle_market( self, - granter: str, - grantee: str, - msg_type: str, - expire_in: int, + sender: str, subaccount_id: str, - **kwargs, + market_id: str, + ) -> injective_exchange_tx_pb.MsgEmergencySettleMarket: + return injective_exchange_tx_pb.MsgEmergencySettleMarket( + sender=sender, subaccount_id=subaccount_id, market_id=market_id + ) + + def MsgIncreasePositionMargin( + self, + sender: str, + source_subaccount_id: str, + destination_subaccount_id: str, + market_id: str, + amount: float, ): - auth = None - if msg_type == "CreateSpotLimitOrderAuthz": - auth = injective_authz_pb.CreateSpotLimitOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CreateSpotMarketOrderAuthz": - auth = injective_authz_pb.CreateSpotMarketOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchCreateSpotLimitOrdersAuthz": - auth = injective_authz_pb.BatchCreateSpotLimitOrdersAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CancelSpotOrderAuthz": - auth = injective_authz_pb.CancelSpotOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchCancelSpotOrdersAuthz": - auth = injective_authz_pb.BatchCancelSpotOrdersAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CreateDerivativeLimitOrderAuthz": - auth = injective_authz_pb.CreateDerivativeLimitOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CreateDerivativeMarketOrderAuthz": - auth = injective_authz_pb.CreateDerivativeMarketOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchCreateDerivativeLimitOrdersAuthz": - auth = injective_authz_pb.BatchCreateDerivativeLimitOrdersAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "CancelDerivativeOrderAuthz": - auth = injective_authz_pb.CancelDerivativeOrderAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchCancelDerivativeOrdersAuthz": - auth = injective_authz_pb.BatchCancelDerivativeOrdersAuthz( - subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") - ) - elif msg_type == "BatchUpdateOrdersAuthz": - auth = injective_authz_pb.BatchUpdateOrdersAuthz( - subaccount_id=subaccount_id, - spot_markets=kwargs.get("spot_markets"), - derivative_markets=kwargs.get("derivative_markets"), - ) + """ + This method is deprecated and will be removed soon. Please use `msg_increase_position_margin` instead + """ + warn( + "This method is deprecated. Use msg_increase_position_margin instead", + DeprecationWarning, + stacklevel=2, + ) + market = self.derivative_markets[market_id] - any_auth = any_pb2.Any() - any_auth.Pack(auth, type_url_prefix="") + additional_margin = market.margin_to_chain_format(human_readable_value=Decimal(str(amount))) + return injective_exchange_tx_pb.MsgIncreasePositionMargin( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + market_id=market_id, + amount=str(int(additional_margin)), + ) - grant = cosmos_authz_pb.Grant( - authorization=any_auth, - expiration=timestamp_pb2.Timestamp(seconds=(int(time()) + expire_in)), + def msg_increase_position_margin( + self, + sender: str, + source_subaccount_id: str, + destination_subaccount_id: str, + market_id: str, + amount: Decimal, + ): + market = self.derivative_markets[market_id] + + additional_margin = market.margin_to_chain_format(human_readable_value=amount) + return injective_exchange_tx_pb.MsgIncreasePositionMargin( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + market_id=market_id, + amount=str(int(additional_margin)), ) - return cosmos_authz_tx_pb.MsgGrant(granter=granter, grantee=grantee, grant=grant) - - def MsgExec(self, grantee: str, msgs: List): - any_msgs: List[any_pb2.Any] = [] - for msg in msgs: - any_msg = any_pb2.Any() - any_msg.Pack(msg, type_url_prefix="") - any_msgs.append(any_msg) + def MsgRewardsOptOut(self, sender: str): + """ + This method is deprecated and will be removed soon. Please use `msg_rewards_opt_out` instead + """ + warn( + "This method is deprecated. Use msg_rewards_opt_out instead", + DeprecationWarning, + stacklevel=2, + ) + return injective_exchange_tx_pb.MsgRewardsOptOut(sender=sender) - return cosmos_authz_tx_pb.MsgExec(grantee=grantee, msgs=any_msgs) + def msg_rewards_opt_out(self, sender: str) -> injective_exchange_tx_pb.MsgRewardsOptOut: + return injective_exchange_tx_pb.MsgRewardsOptOut(sender=sender) - def MsgRevoke(self, granter: str, grantee: str, msg_type: str): - return cosmos_authz_tx_pb.MsgRevoke(granter=granter, grantee=grantee, msg_type_url=msg_type) + def MsgAdminUpdateBinaryOptionsMarket( + self, + sender: str, + market_id: str, + status: str, + **kwargs, + ): + """ + This method is deprecated and will be removed soon. Please use `msg_admin_update_binary_options_market` instead + """ + warn( + "This method is deprecated. Use msg_admin_update_binary_options_market instead", + DeprecationWarning, + stacklevel=2, + ) - def MsgRelayPriceFeedPrice(self, sender: list, base: list, quote: list, price: list): - return injective_oracle_tx_pb.MsgRelayPriceFeedPrice(sender=sender, base=base, quote=quote, price=price) + if kwargs.get("settlement_price") is not None: + scale_price = Decimal((kwargs.get("settlement_price") * pow(10, 18))) + price_to_bytes = bytes(str(scale_price), "utf-8") - def MsgSendToEth(self, denom: str, sender: str, eth_dest: str, amount: float, bridge_fee: float): - be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) - be_bridge_fee = self.create_coin_amount(amount=Decimal(str(bridge_fee)), token_name=denom) + else: + price_to_bytes = "" - return injective_peggy_tx_pb.MsgSendToEth( + return injective_exchange_tx_pb.MsgAdminUpdateBinaryOptionsMarket( sender=sender, - eth_dest=eth_dest, - amount=be_amount, - bridge_fee=be_bridge_fee, + market_id=market_id, + settlement_price=price_to_bytes, + expiration_timestamp=kwargs.get("expiration_timestamp"), + settlement_timestamp=kwargs.get("settlement_timestamp"), + status=status, ) - def MsgDelegate(self, delegator_address: str, validator_address: str, amount: float): - be_amount = Decimal(str(amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + def msg_admin_update_binary_options_market( + self, + sender: str, + market_id: str, + status: str, + settlement_price: Optional[Decimal] = None, + expiration_timestamp: Optional[int] = None, + settlement_timestamp: Optional[int] = None, + ) -> injective_exchange_tx_pb.MsgAdminUpdateBinaryOptionsMarket: + market = self.binary_option_markets[market_id] - return cosmos_staking_tx_pb.MsgDelegate( - delegator_address=delegator_address, - validator_address=validator_address, - amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), + if settlement_price is not None: + chain_settlement_price = market.price_to_chain_format(human_readable_value=settlement_price) + price_parameter = f"{chain_settlement_price.normalize():f}" + else: + price_parameter = None + + return injective_exchange_tx_pb.MsgAdminUpdateBinaryOptionsMarket( + sender=sender, + market_id=market_id, + settlement_price=price_parameter, + expiration_timestamp=expiration_timestamp, + settlement_timestamp=settlement_timestamp, + status=status, ) + # endregion + + # region Insurance module def MsgCreateInsuranceFund( self, sender: str, @@ -941,38 +1817,53 @@ def MsgRequestRedemption( amount=self.coin(amount=amount, denom=share_denom), ) - def MsgVote( - self, - proposal_id: str, - voter: str, - option: int, - ): - return cosmos_gov_tx_pb.MsgVote(proposal_id=proposal_id, voter=voter, option=option) + # endregion - def MsgPrivilegedExecuteContract( - self, sender: str, contract: str, msg: str, **kwargs - ) -> injective_exchange_tx_pb.MsgPrivilegedExecuteContract: - return injective_exchange_tx_pb.MsgPrivilegedExecuteContract( - sender=sender, - contract_address=contract, - data=msg, - funds=kwargs.get("funds") # funds is a string of Coin strings, comma separated, - # e.g. 100000inj,20000000000usdt + # region Oracle module + def MsgRelayProviderPrices(self, sender: str, provider: str, symbols: list, prices: list): + oracle_prices = [] + + for price in prices: + scale_price = Decimal((price) * pow(10, 18)) + price_to_bytes = bytes(str(scale_price), "utf-8") + oracle_prices.append(price_to_bytes) + + return injective_oracle_tx_pb.MsgRelayProviderPrices( + sender=sender, provider=provider, symbols=symbols, prices=oracle_prices ) - def MsgInstantiateContract( - self, sender: str, admin: str, code_id: int, label: str, message: bytes, **kwargs - ) -> wasm_tx_pb.MsgInstantiateContract: - return wasm_tx_pb.MsgInstantiateContract( + def MsgRelayPriceFeedPrice(self, sender: list, base: list, quote: list, price: list): + return injective_oracle_tx_pb.MsgRelayPriceFeedPrice(sender=sender, base=base, quote=quote, price=price) + + # endregion + + # region Peggy module + def MsgSendToEth(self, denom: str, sender: str, eth_dest: str, amount: float, bridge_fee: float): + be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) + be_bridge_fee = self.create_coin_amount(amount=Decimal(str(bridge_fee)), token_name=denom) + + return injective_peggy_tx_pb.MsgSendToEth( sender=sender, - admin=admin, - code_id=code_id, - label=label, - msg=message, - funds=kwargs.get("funds"), # funds is a list of cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin. - # The coins in the list must be sorted in alphabetical order by denoms. + eth_dest=eth_dest, + amount=be_amount, + bridge_fee=be_bridge_fee, + ) + + # endregion + + # region Staking module + def MsgDelegate(self, delegator_address: str, validator_address: str, amount: float): + be_amount = Decimal(str(amount)) * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return cosmos_staking_tx_pb.MsgDelegate( + delegator_address=delegator_address, + validator_address=validator_address, + amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), ) + # endregion + + # region Tokenfactory module def msg_create_denom( self, sender: str, @@ -990,14 +1881,14 @@ def msg_create_denom( def msg_mint( self, sender: str, - amount: cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin, + amount: base_coin_pb.Coin, ) -> token_factory_tx_pb.MsgMint: return token_factory_tx_pb.MsgMint(sender=sender, amount=amount) def msg_burn( self, sender: str, - amount: cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin, + amount: base_coin_pb.Coin, ) -> token_factory_tx_pb.MsgBurn: return token_factory_tx_pb.MsgBurn(sender=sender, amount=amount) @@ -1047,14 +1938,108 @@ def msg_change_admin( new_admin=new_admin, ) - def msg_execute_contract_compat(self, sender: str, contract: str, msg: str, funds: str): - return wasmx_tx_pb.MsgExecuteContractCompat( + # endregion + + # region Wasm module + def MsgInstantiateContract( + self, sender: str, admin: str, code_id: int, label: str, message: bytes, **kwargs + ) -> wasm_tx_pb.MsgInstantiateContract: + return wasm_tx_pb.MsgInstantiateContract( + sender=sender, + admin=admin, + code_id=code_id, + label=label, + msg=message, + funds=kwargs.get("funds"), # funds is a list of base_coin_pb.Coin. + # The coins in the list must be sorted in alphabetical order by denoms. + ) + + def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): + return wasm_tx_pb.MsgExecuteContract( sender=sender, contract=contract, - msg=msg, - funds=funds, + msg=bytes(msg, "utf-8"), + funds=kwargs.get("funds") # funds is a list of base_coin_pb.Coin. + # The coins in the list must be sorted in alphabetical order by denoms. + ) + + # endregion + + def MsgGrantTyped( + self, + granter: str, + grantee: str, + msg_type: str, + expire_in: int, + subaccount_id: str, + **kwargs, + ): + auth = None + if msg_type == "CreateSpotLimitOrderAuthz": + auth = injective_authz_pb.CreateSpotLimitOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CreateSpotMarketOrderAuthz": + auth = injective_authz_pb.CreateSpotMarketOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchCreateSpotLimitOrdersAuthz": + auth = injective_authz_pb.BatchCreateSpotLimitOrdersAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CancelSpotOrderAuthz": + auth = injective_authz_pb.CancelSpotOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchCancelSpotOrdersAuthz": + auth = injective_authz_pb.BatchCancelSpotOrdersAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CreateDerivativeLimitOrderAuthz": + auth = injective_authz_pb.CreateDerivativeLimitOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CreateDerivativeMarketOrderAuthz": + auth = injective_authz_pb.CreateDerivativeMarketOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchCreateDerivativeLimitOrdersAuthz": + auth = injective_authz_pb.BatchCreateDerivativeLimitOrdersAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "CancelDerivativeOrderAuthz": + auth = injective_authz_pb.CancelDerivativeOrderAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchCancelDerivativeOrdersAuthz": + auth = injective_authz_pb.BatchCancelDerivativeOrdersAuthz( + subaccount_id=subaccount_id, market_ids=kwargs.get("market_ids") + ) + elif msg_type == "BatchUpdateOrdersAuthz": + auth = injective_authz_pb.BatchUpdateOrdersAuthz( + subaccount_id=subaccount_id, + spot_markets=kwargs.get("spot_markets"), + derivative_markets=kwargs.get("derivative_markets"), + ) + + any_auth = any_pb2.Any() + any_auth.Pack(auth, type_url_prefix="") + + grant = cosmos_authz_pb.Grant( + authorization=any_auth, + expiration=timestamp_pb2.Timestamp(seconds=(int(time()) + expire_in)), ) + return cosmos_authz_tx_pb.MsgGrant(granter=granter, grantee=grantee, grant=grant) + + def MsgVote( + self, + proposal_id: str, + voter: str, + option: int, + ): + return cosmos_gov_tx_pb.MsgVote(proposal_id=proposal_id, voter=voter, option=option) + def chain_stream_bank_balances_filter( self, accounts: Optional[List[str]] = None ) -> chain_stream_query.BankBalancesFilter: @@ -1144,7 +2129,7 @@ def MsgWithdrawValidatorCommission(self, validator_address: str): def msg_withdraw_validator_commission(self, validator_address: str): return cosmos_distribution_tx_pb.MsgWithdrawValidatorCommission(validator_address=validator_address) - def msg_fund_community_pool(self, amounts: List[cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin], depositor: str): + def msg_fund_community_pool(self, amounts: List[base_coin_pb.Coin], depositor: str): return cosmos_distribution_tx_pb.MsgFundCommunityPool(amount=amounts, depositor=depositor) def msg_update_distribution_params(self, authority: str, community_tax: str, withdraw_address_enabled: bool): @@ -1154,9 +2139,7 @@ def msg_update_distribution_params(self, authority: str, community_tax: str, wit ) return cosmos_distribution_tx_pb.MsgUpdateParams(authority=authority, params=params) - def msg_community_pool_spend( - self, authority: str, recipient: str, amount: List[cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin] - ): + def msg_community_pool_spend(self, authority: str, recipient: str, amount: List[base_coin_pb.Coin]): return cosmos_distribution_tx_pb.MsgCommunityPoolSpend(authority=authority, recipient=recipient, amount=amount) # data field format: [request-msg-header][raw-byte-msg-response] @@ -1369,3 +2352,61 @@ def _initialize_markets_and_tokens_from_files(self): self.spot_markets = spot_markets self.derivative_markets = derivative_markets self.binary_option_markets = dict() + + def _order_mask(self, is_conditional: bool, is_buy: bool, is_market_order: bool) -> int: + order_mask = 0 + + if is_conditional: + order_mask += injective_exchange_pb.OrderMask.CONDITIONAL + else: + order_mask += injective_exchange_pb.OrderMask.REGULAR + + if is_buy: + order_mask += injective_exchange_pb.OrderMask.DIRECTION_BUY_OR_HIGHER + else: + order_mask += injective_exchange_pb.OrderMask.DIRECTION_SELL_OR_LOWER + + if is_market_order: + order_mask += injective_exchange_pb.OrderMask.TYPE_MARKET + else: + order_mask += injective_exchange_pb.OrderMask.TYPE_LIMIT + + if order_mask == 0: + order_mask = 1 + + return order_mask + + def _basic_derivative_order( + self, + market_id: str, + subaccount_id: str, + fee_recipient: str, + chain_price: Decimal, + chain_quantity: Decimal, + chain_margin: Decimal, + order_type: str, + cid: Optional[str] = None, + chain_trigger_price: Optional[Decimal] = None, + ) -> injective_exchange_pb.DerivativeOrder: + formatted_quantity = f"{chain_quantity.normalize():f}" + formatted_price = f"{chain_price.normalize():f}" + formatted_margin = f"{chain_margin.normalize():f}" + + trigger_price = chain_trigger_price or Decimal(0) + formatted_trigger_price = f"{trigger_price.normalize():f}" + + chain_order_type = injective_exchange_pb.OrderType.Value(order_type) + + return injective_exchange_pb.DerivativeOrder( + market_id=market_id, + order_info=injective_exchange_pb.OrderInfo( + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=formatted_price, + quantity=formatted_quantity, + cid=cid, + ), + order_type=chain_order_type, + margin=formatted_margin, + trigger_price=formatted_trigger_price, + ) diff --git a/pyinjective/core/market.py b/pyinjective/core/market.py index 2bd4fe1b..66063130 100644 --- a/pyinjective/core/market.py +++ b/pyinjective/core/market.py @@ -169,6 +169,17 @@ def price_to_chain_format(self, human_readable_value: Decimal, special_denom: Op return extended_chain_formatted_value + def margin_to_chain_format(self, human_readable_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal: + decimals = self.quote_token.decimals if special_denom is None else special_denom.quote + min_quantity_tick_size = ( + self.min_quantity_tick_size if special_denom is None else special_denom.min_quantity_tick_size + ) + chain_formatted_value = human_readable_value * Decimal(f"1e{decimals}") + quantized_value = (chain_formatted_value // min_quantity_tick_size) * min_quantity_tick_size + extended_chain_formatted_value = quantized_value * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + return extended_chain_formatted_value + def calculate_margin_in_chain_format( self, human_readable_quantity: Decimal, diff --git a/tests/core/test_gas_limit_estimator.py b/tests/core/test_gas_limit_estimator.py index 916c47a9..293f5f25 100644 --- a/tests/core/test_gas_limit_estimator.py +++ b/tests/core/test_gas_limit_estimator.py @@ -24,26 +24,24 @@ def test_estimation_for_batch_create_spot_limit_orders(self): spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=5, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("5"), + quantity=Decimal("1"), + order_type="BUY", ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=4, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("4"), + quantity=Decimal("1"), + order_type="BUY", ), ] - message = composer.MsgBatchCreateSpotLimitOrders(sender="sender", orders=orders) + message = composer.msg_batch_create_spot_limit_orders(sender="sender", orders=orders) estimator = GasLimitEstimator.for_message(message=message) expected_order_gas_limit = 50000 @@ -55,23 +53,23 @@ def test_estimation_for_batch_cancel_spot_orders(self): spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", ), ] - message = composer.MsgBatchCancelSpotOrders(sender="sender", data=orders) + message = composer.msg_batch_cancel_spot_orders(sender="sender", orders_data=orders) estimator = GasLimitEstimator.for_message(message=message) expected_order_gas_limit = 50000 @@ -83,28 +81,26 @@ def test_estimation_for_batch_create_derivative_limit_orders(self): market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" composer = Composer(network="testnet") orders = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=3, - quantity=1, - leverage=1, - is_buy=True, - is_po=False, + price=Decimal(3), + quantity=Decimal(1), + margin=Decimal(3), + order_type="BUY", ), - composer.DerivativeOrder( + composer.derivative_order( 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, + price=Decimal(20), + quantity=Decimal(1), + margin=Decimal(20), + order_type="SELL", ), ] - message = composer.MsgBatchCreateDerivativeLimitOrders(sender="sender", orders=orders) + message = composer.msg_batch_create_derivative_limit_orders(sender="sender", orders=orders) estimator = GasLimitEstimator.for_message(message=message) expected_order_gas_limit = 70_000 @@ -116,23 +112,23 @@ def test_estimation_for_batch_cancel_derivative_orders(self): spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=spot_market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", ), ] - message = composer.MsgBatchCancelDerivativeOrders(sender="sender", data=orders) + message = composer.msg_batch_cancel_derivative_orders(sender="sender", orders_data=orders) estimator = GasLimitEstimator.for_message(message=message) expected_order_gas_limit = 60_000 @@ -144,23 +140,21 @@ def test_estimation_for_batch_update_orders_to_create_spot_orders(self): market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.SpotOrder( + composer.spot_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=5, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("5"), + quantity=Decimal("1"), + order_type="BUY", ), - composer.SpotOrder( + composer.spot_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=4, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("4"), + quantity=Decimal("1"), + order_type="BUY", ), ] message = composer.MsgBatchUpdateOrders( @@ -181,25 +175,23 @@ def test_estimation_for_batch_update_orders_to_create_derivative_orders(self): market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" composer = Composer(network="testnet") orders = [ - composer.DerivativeOrder( + composer.derivative_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=3, - quantity=1, - leverage=1, - is_buy=True, - is_po=False, + price=Decimal(3), + quantity=Decimal(1), + margin=Decimal(3), + order_type="BUY", ), - composer.DerivativeOrder( + composer.derivative_order( 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, + price=Decimal(20), + quantity=Decimal(1), + margin=Decimal(20), + order_type="SELL", ), ] message = composer.MsgBatchUpdateOrders( @@ -238,25 +230,23 @@ def test_estimation_for_batch_update_orders_to_create_binary_orders(self, usdt_t ) composer.binary_option_markets[market.id] = market orders = [ - composer.BinaryOptionsOrder( + composer.binary_options_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=3, - quantity=1, - leverage=1, - is_buy=True, - is_po=False, + price=Decimal(3), + quantity=Decimal(1), + margin=Decimal(3), + order_type="BUY", ), - composer.BinaryOptionsOrder( + composer.binary_options_order( 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, + price=Decimal(20), + quantity=Decimal(1), + margin=Decimal(20), + order_type="SELL", ), ] message = composer.MsgBatchUpdateOrders( @@ -278,17 +268,17 @@ def test_estimation_for_batch_update_orders_to_cancel_spot_orders(self): market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", @@ -312,17 +302,17 @@ def test_estimation_for_batch_update_orders_to_cancel_derivative_orders(self): market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", @@ -346,17 +336,17 @@ def test_estimation_for_batch_update_orders_to_cancel_binary_orders(self): market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" composer = Composer(network="testnet") orders = [ - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", ), - composer.OrderData( + composer.order_data( market_id=market_id, subaccount_id="subaccount_id", order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", @@ -441,14 +431,13 @@ def test_estimation_for_exec_message(self): market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe" composer = Composer(network="testnet") orders = [ - composer.SpotOrder( + composer.spot_order( market_id=market_id, subaccount_id="subaccount_id", fee_recipient="fee_recipient", - price=5, - quantity=1, - is_buy=True, - is_po=False, + price=Decimal("5"), + quantity=Decimal("1"), + order_type="BUY", ), ] inner_message = composer.MsgBatchUpdateOrders( @@ -510,15 +499,14 @@ def test_estimation_for_governance_message(self): def test_estimation_for_generic_exchange_message(self): composer = Composer(network="testnet") - message = composer.MsgCreateSpotLimitOrder( + message = composer.msg_create_spot_limit_order( 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, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", ) estimator = GasLimitEstimator.for_message(message=message) diff --git a/tests/core/test_market.py b/tests/core/test_market.py index ede8aea5..48c2f5e5 100644 --- a/tests/core/test_market.py +++ b/tests/core/test_market.py @@ -248,6 +248,42 @@ def test_convert_price_to_chain_format_without_fixed_denom(self, first_match_bet assert quantized_chain_format_value == chain_value + def test_convert_margin_to_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + fixed_denom = Denom( + description="Fixed denom", + base=2, + quote=4, + min_quantity_tick_size=100, + min_price_tick_size=10000, + ) + + chain_value = first_match_bet_market.margin_to_chain_format( + human_readable_value=original_quantity, + special_denom=fixed_denom, + ) + price_decimals = fixed_denom.quote + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = (expected_value // Decimal(str(fixed_denom.min_quantity_tick_size))) * Decimal( + str(fixed_denom.min_quantity_tick_size) + ) + quantized_chain_format_value = quantized_value * Decimal("1e18") + + assert quantized_chain_format_value == chain_value + + def test_convert_margin_to_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): + original_quantity = Decimal("123.456789") + + chain_value = first_match_bet_market.margin_to_chain_format(human_readable_value=original_quantity) + price_decimals = first_match_bet_market.quote_token.decimals + expected_value = original_quantity * Decimal(f"1e{price_decimals}") + quantized_value = ( + expected_value // first_match_bet_market.min_quantity_tick_size + ) * first_match_bet_market.min_quantity_tick_size + quantized_chain_format_value = quantized_value * Decimal("1e18") + + assert quantized_chain_format_value == chain_value + def test_calculate_margin_for_buy_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket): original_quantity = Decimal("123.456789") original_price = Decimal("0.6789") diff --git a/tests/core/test_message_based_transaction_fee_calculator.py b/tests/core/test_message_based_transaction_fee_calculator.py index 23e263c9..b1d774e0 100644 --- a/tests/core/test_message_based_transaction_fee_calculator.py +++ b/tests/core/test_message_based_transaction_fee_calculator.py @@ -117,15 +117,14 @@ async def test_gas_fee_for_exchange_message(self): gas_price=5_000_000, ) - message = composer.MsgCreateSpotLimitOrder( + message = composer.msg_create_spot_limit_order( 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, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", ) transaction = Transaction() transaction.with_messages(message) @@ -148,15 +147,14 @@ async def test_gas_fee_for_msg_exec_message(self): gas_price=5_000_000, ) - inner_message = composer.MsgCreateSpotLimitOrder( + inner_message = composer.msg_create_spot_limit_order( 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, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", ) message = composer.MsgExec(grantee="grantee", msgs=[inner_message]) transaction = Transaction() @@ -184,15 +182,14 @@ async def test_gas_fee_for_two_messages_in_one_transaction(self): gas_price=5_000_000, ) - inner_message = composer.MsgCreateSpotLimitOrder( + inner_message = composer.msg_create_spot_limit_order( 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, + price=Decimal("7.523"), + quantity=Decimal("0.01"), + order_type="BUY", ) message = composer.MsgExec(grantee="grantee", msgs=[inner_message]) diff --git a/tests/test_composer.py b/tests/test_composer.py index a0cca2ab..2dcbd056 100644 --- a/tests/test_composer.py +++ b/tests/test_composer.py @@ -2,12 +2,11 @@ from decimal import Decimal import pytest +from google.protobuf import json_format from pyinjective.composer import Composer -from pyinjective.core.market import BinaryOptionMarket, DerivativeMarket, SpotMarket +from pyinjective.constant import ADDITIONAL_CHAIN_FORMAT_DECIMALS from pyinjective.core.network import Network -from pyinjective.proto.injective.exchange.v1beta1 import exchange_pb2 -from pyinjective.utils.denom import Denom from tests.model_fixtures.markets_fixtures import btc_usdt_perp_market # noqa: F401 from tests.model_fixtures.markets_fixtures import first_match_bet_market # noqa: F401 from tests.model_fixtures.markets_fixtures import inj_token # noqa: F401 @@ -57,211 +56,6 @@ def test_composer_initialization_from_ini_files(self): assert 6 == inj_usdt_spot_market.quote_token.decimals assert 6 == inj_usdt_perp_market.quote_token.decimals - def test_buy_spot_order_creation(self, basic_composer: Composer, inj_usdt_spot_market: SpotMarket): - fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - price = 6.869 - quantity = 1587 - order = basic_composer.SpotOrder( - market_id=inj_usdt_spot_market.id, - subaccount_id="1", - fee_recipient=fee_recipient, - price=price, - quantity=quantity, - is_buy=True, - ) - - price_decimals = inj_usdt_spot_market.quote_token.decimals - inj_usdt_spot_market.base_token.decimals - chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") - expected_price = ( - (chain_format_price // inj_usdt_spot_market.min_price_tick_size) - * inj_usdt_spot_market.min_price_tick_size - * Decimal("1e18") - ) - chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{inj_usdt_spot_market.base_token.decimals}") - expected_quantity = ( - (chain_format_quantity // inj_usdt_spot_market.min_quantity_tick_size) - * inj_usdt_spot_market.min_quantity_tick_size - * Decimal("1e18") - ) - - assert order.market_id == inj_usdt_spot_market.id - assert order.order_info.subaccount_id == "1" - assert order.order_info.fee_recipient == fee_recipient - assert order.order_info.price == str(int(expected_price)) - assert order.order_info.quantity == str(int(expected_quantity)) - assert order.order_type == exchange_pb2.OrderType.BUY - assert order.trigger_price == "0" - - def test_buy_derivative_order_creation(self, basic_composer: Composer, btc_usdt_perp_market: DerivativeMarket): - fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - price = 6.869 - quantity = 1587 - leverage = 2 - order = basic_composer.DerivativeOrder( - market_id=btc_usdt_perp_market.id, - subaccount_id="1", - fee_recipient=fee_recipient, - price=price, - quantity=quantity, - is_buy=True, - leverage=leverage, - ) - - price_decimals = btc_usdt_perp_market.quote_token.decimals - chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") - expected_price = ( - (chain_format_price // btc_usdt_perp_market.min_price_tick_size) - * btc_usdt_perp_market.min_price_tick_size - * Decimal("1e18") - ) - chain_format_quantity = Decimal(str(quantity)) - expected_quantity = ( - (chain_format_quantity // btc_usdt_perp_market.min_quantity_tick_size) - * btc_usdt_perp_market.min_quantity_tick_size - * Decimal("1e18") - ) - chain_format_margin = (chain_format_quantity * chain_format_price) / Decimal(leverage) - expected_margin = ( - (chain_format_margin // btc_usdt_perp_market.min_quantity_tick_size) - * btc_usdt_perp_market.min_quantity_tick_size - * Decimal("1e18") - ) - - assert order.market_id == btc_usdt_perp_market.id - assert order.order_info.subaccount_id == "1" - assert order.order_info.fee_recipient == fee_recipient - assert order.order_info.price == str(int(expected_price)) - assert order.order_info.quantity == str(int(expected_quantity)) - assert order.order_type == exchange_pb2.OrderType.BUY - assert order.margin == str(int(expected_margin)) - assert order.trigger_price == "0" - - def test_increase_position_margin(self, basic_composer: Composer, btc_usdt_perp_market: DerivativeMarket): - sender = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - amount = 1587.789 - message = basic_composer.MsgIncreasePositionMargin( - sender=sender, - source_subaccount_id="1", - destination_subaccount_id="2", - market_id=btc_usdt_perp_market.id, - amount=amount, - ) - - price_decimals = btc_usdt_perp_market.quote_token.decimals - chain_format_margin = Decimal(str(amount)) * Decimal(f"1e{price_decimals}") - expected_margin = ( - (chain_format_margin // btc_usdt_perp_market.min_quantity_tick_size) - * btc_usdt_perp_market.min_quantity_tick_size - * Decimal("1e18") - ) - - assert message.market_id == btc_usdt_perp_market.id - assert message.sender == sender - assert message.source_subaccount_id == "1" - assert message.destination_subaccount_id == "2" - assert message.amount == str(int(expected_margin)) - - def test_buy_binary_option_order_creation_with_fixed_denom( - self, basic_composer: Composer, first_match_bet_market: BinaryOptionMarket - ): - fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - price = 6.869 - quantity = 1587 - fixed_denom = Denom( - description="Fixed denom", - base=2, - quote=6, - min_price_tick_size=1000, - min_quantity_tick_size=10000, - ) - - order = basic_composer.BinaryOptionsOrder( - market_id=first_match_bet_market.id, - subaccount_id="1", - fee_recipient=fee_recipient, - price=price, - quantity=quantity, - is_buy=True, - denom=fixed_denom, - ) - - price_decimals = fixed_denom.quote - chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") - expected_price = ( - (chain_format_price // Decimal(str(fixed_denom.min_price_tick_size))) - * Decimal(str(fixed_denom.min_price_tick_size)) - * Decimal("1e18") - ) - quantity_decimals = fixed_denom.base - chain_format_quantity = Decimal(str(quantity)) * Decimal(f"1e{quantity_decimals}") - expected_quantity = ( - (chain_format_quantity // Decimal(str(fixed_denom.min_quantity_tick_size))) - * Decimal(str(fixed_denom.min_quantity_tick_size)) - * Decimal("1e18") - ) - chain_format_margin = chain_format_quantity * chain_format_price - expected_margin = ( - (chain_format_margin // Decimal(str(fixed_denom.min_quantity_tick_size))) - * Decimal(str(fixed_denom.min_quantity_tick_size)) - * Decimal("1e18") - ) - - assert order.market_id == first_match_bet_market.id - assert order.order_info.subaccount_id == "1" - assert order.order_info.fee_recipient == fee_recipient - assert order.order_info.price == str(int(expected_price)) - assert order.order_info.quantity == str(int(expected_quantity)) - assert order.order_type == exchange_pb2.OrderType.BUY - assert order.margin == str(int(expected_margin)) - assert order.trigger_price == "0" - - def test_buy_binary_option_order_creation_without_fixed_denom( - self, - basic_composer: Composer, - first_match_bet_market: BinaryOptionMarket, - ): - fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" - price = 6.869 - quantity = 1587 - - order = basic_composer.BinaryOptionsOrder( - market_id=first_match_bet_market.id, - subaccount_id="1", - fee_recipient=fee_recipient, - price=price, - quantity=quantity, - is_buy=True, - ) - - price_decimals = first_match_bet_market.quote_token.decimals - chain_format_price = Decimal(str(price)) * Decimal(f"1e{price_decimals}") - expected_price = ( - (chain_format_price // first_match_bet_market.min_price_tick_size) - * first_match_bet_market.min_price_tick_size - * Decimal("1e18") - ) - chain_format_quantity = Decimal(str(quantity)) - expected_quantity = ( - (chain_format_quantity // first_match_bet_market.min_quantity_tick_size) - * first_match_bet_market.min_quantity_tick_size - * Decimal("1e18") - ) - chain_format_margin = chain_format_quantity * chain_format_price - expected_margin = ( - (chain_format_margin // first_match_bet_market.min_quantity_tick_size) - * first_match_bet_market.min_quantity_tick_size - * Decimal("1e18") - ) - - assert order.market_id == first_match_bet_market.id - assert order.order_info.subaccount_id == "1" - assert order.order_info.fee_recipient == fee_recipient - assert order.order_info.price == str(int(expected_price)) - assert order.order_info.quantity == str(int(expected_quantity)) - assert order.order_type == exchange_pb2.OrderType.BUY - assert order.margin == str(int(expected_margin)) - assert order.trigger_price == "0" - def test_msg_create_denom(self, basic_composer: Composer): sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" subdenom = "inj-test" @@ -380,3 +174,1259 @@ def test_msg_execute_contract_compat(self, basic_composer): assert message.contract == contract assert message.msg == msg assert message.funds == funds + + def test_msg_deposit(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + amount = Decimal(100) + denom = "INJ" + + token = basic_composer.tokens[denom] + + expected_amount = token.chain_formatted_value(human_readable_value=Decimal(amount)) + + message = basic_composer.msg_deposit( + sender=sender, + subaccount_id=subaccount_id, + amount=amount, + denom=denom, + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "amount": { + "amount": f"{expected_amount.normalize():f}", + "denom": token.denom, + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_withdraw(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + amount = Decimal(100) + denom = "INJ" + + token = basic_composer.tokens[denom] + + expected_amount = token.chain_formatted_value(human_readable_value=Decimal(amount)) + + message = basic_composer.msg_withdraw( + sender=sender, + subaccount_id=subaccount_id, + amount=amount, + denom=denom, + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "amount": { + "amount": f"{expected_amount.normalize():f}", + "denom": token.denom, + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_instant_spot_market_launch(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + ticker = "INJ/USDT" + base_denom = "INJ" + quote_denom = "USDT" + min_price_tick_size = Decimal("0.01") + min_quantity_tick_size = Decimal("1") + + base_token = basic_composer.tokens[base_denom] + quote_token = basic_composer.tokens[quote_denom] + + expected_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals - base_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + expected_min_quantity_tick_size = min_quantity_tick_size * Decimal( + f"1e{base_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + + message = basic_composer.msg_instant_spot_market_launch( + sender=sender, + ticker=ticker, + base_denom=base_denom, + quote_denom=quote_denom, + min_price_tick_size=min_price_tick_size, + min_quantity_tick_size=min_quantity_tick_size, + ) + + expected_message = { + "sender": sender, + "ticker": ticker, + "baseDenom": base_token.denom, + "quoteDenom": quote_token.denom, + "minPriceTickSize": f"{expected_min_price_tick_size.normalize():f}", + "minQuantityTickSize": f"{expected_min_quantity_tick_size.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_instant_perpetual_market_launch(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + ticker = "BTC/INJ PERP" + quote_denom = "INJ" + oracle_base = "BTC" + oracle_quote = "INJ" + oracle_scale_factor = 6 + oracle_type = "Band" + min_price_tick_size = Decimal("0.01") + min_quantity_tick_size = Decimal("1") + maker_fee_rate = Decimal("0.001") + taker_fee_rate = Decimal("-0.002") + initial_margin_ratio = Decimal("0.05") + maintenance_margin_ratio = Decimal("0.03") + + quote_token = basic_composer.tokens[quote_denom] + + expected_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + expected_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_initial_margin_ratio = initial_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maintenance_margin_ratio = maintenance_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + message = basic_composer.msg_instant_perpetual_market_launch( + sender=sender, + ticker=ticker, + quote_denom=quote_denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_scale_factor=oracle_scale_factor, + oracle_type=oracle_type, + maker_fee_rate=maker_fee_rate, + taker_fee_rate=taker_fee_rate, + initial_margin_ratio=initial_margin_ratio, + maintenance_margin_ratio=maintenance_margin_ratio, + min_price_tick_size=min_price_tick_size, + min_quantity_tick_size=min_quantity_tick_size, + ) + + expected_message = { + "sender": sender, + "ticker": ticker, + "quoteDenom": quote_token.denom, + "oracleBase": oracle_base, + "oracleQuote": oracle_quote, + "oracleScaleFactor": oracle_scale_factor, + "oracleType": oracle_type, + "makerFeeRate": f"{expected_maker_fee_rate.normalize():f}", + "takerFeeRate": f"{expected_taker_fee_rate.normalize():f}", + "initialMarginRatio": f"{expected_initial_margin_ratio.normalize():f}", + "maintenanceMarginRatio": f"{expected_maintenance_margin_ratio.normalize():f}", + "minPriceTickSize": f"{expected_min_price_tick_size.normalize():f}", + "minQuantityTickSize": f"{expected_min_quantity_tick_size.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_instant_expiry_futures_market_launch(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + ticker = "BTC/INJ PERP" + quote_denom = "INJ" + oracle_base = "BTC" + oracle_quote = "INJ" + oracle_scale_factor = 6 + oracle_type = "Band" + expiry = 1630000000 + min_price_tick_size = Decimal("0.01") + min_quantity_tick_size = Decimal("1") + maker_fee_rate = Decimal("0.001") + taker_fee_rate = Decimal("-0.002") + initial_margin_ratio = Decimal("0.05") + maintenance_margin_ratio = Decimal("0.03") + + quote_token = basic_composer.tokens[quote_denom] + + expected_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + expected_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_initial_margin_ratio = initial_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maintenance_margin_ratio = maintenance_margin_ratio * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + message = basic_composer.msg_instant_expiry_futures_market_launch( + sender=sender, + ticker=ticker, + quote_denom=quote_denom, + oracle_base=oracle_base, + oracle_quote=oracle_quote, + oracle_scale_factor=oracle_scale_factor, + oracle_type=oracle_type, + expiry=expiry, + maker_fee_rate=maker_fee_rate, + taker_fee_rate=taker_fee_rate, + initial_margin_ratio=initial_margin_ratio, + maintenance_margin_ratio=maintenance_margin_ratio, + min_price_tick_size=min_price_tick_size, + min_quantity_tick_size=min_quantity_tick_size, + ) + + expected_message = { + "sender": sender, + "ticker": ticker, + "quoteDenom": quote_token.denom, + "oracleBase": oracle_base, + "oracleQuote": oracle_quote, + "oracleType": oracle_type, + "oracleScaleFactor": oracle_scale_factor, + "expiry": str(expiry), + "makerFeeRate": f"{expected_maker_fee_rate.normalize():f}", + "takerFeeRate": f"{expected_taker_fee_rate.normalize():f}", + "initialMarginRatio": f"{expected_initial_margin_ratio.normalize():f}", + "maintenanceMarginRatio": f"{expected_maintenance_margin_ratio.normalize():f}", + "minPriceTickSize": f"{expected_min_price_tick_size.normalize():f}", + "minQuantityTickSize": f"{expected_min_quantity_tick_size.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_spot_order(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + order = basic_composer.spot_order( + market_id=spot_market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = spot_market.price_to_chain_format(human_readable_value=price) + expected_quantity = spot_market.quantity_to_chain_format(human_readable_value=quantity) + expected_trigger_price = spot_market.price_to_chain_format(human_readable_value=trigger_price) + + expected_order = { + "marketId": spot_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=order, + including_default_value_fields=True, + ) + assert dict_message == expected_order + + def test_derivative_order(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + order = basic_composer.derivative_order( + market_id=derivative_market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = derivative_market.price_to_chain_format(human_readable_value=price) + expected_quantity = derivative_market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = derivative_market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = derivative_market.price_to_chain_format(human_readable_value=trigger_price) + + expected_order = { + "marketId": derivative_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "orderType": order_type, + "margin": f"{expected_margin.normalize():f}", + "triggerPrice": f"{expected_trigger_price.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=order, + including_default_value_fields=True, + ) + assert dict_message == expected_order + + def test_msg_create_spot_limit_order(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_spot_limit_order( + market_id=spot_market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = spot_market.price_to_chain_format(human_readable_value=price) + expected_quantity = spot_market.quantity_to_chain_format(human_readable_value=quantity) + expected_trigger_price = spot_market.price_to_chain_format(human_readable_value=trigger_price) + + assert "injective.exchange.v1beta1.MsgCreateSpotLimitOrder" == message.DESCRIPTOR.full_name + expected_message = { + "sender": sender, + "order": { + "marketId": spot_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_create_spot_limit_orders(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + order = basic_composer.spot_order( + market_id=spot_market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + message = basic_composer.msg_batch_create_spot_limit_orders( + sender=sender, + orders=[order], + ) + + expected_message = { + "sender": sender, + "orders": [json_format.MessageToDict(message=order, including_default_value_fields=True)], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_spot_market_order(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_spot_market_order( + market_id=spot_market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = spot_market.price_to_chain_format(human_readable_value=price) + expected_quantity = spot_market.quantity_to_chain_format(human_readable_value=quantity) + expected_trigger_price = spot_market.price_to_chain_format(human_readable_value=trigger_price) + + assert "injective.exchange.v1beta1.MsgCreateSpotMarketOrder" == message.DESCRIPTOR.full_name + expected_message = { + "sender": sender, + "order": { + "marketId": spot_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_cancel_spot_order(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + order_hash = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + cid = "test_cid" + + message = basic_composer.msg_cancel_spot_order( + market_id=spot_market.id, + sender=sender, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + ) + + expected_message = { + "sender": sender, + "marketId": spot_market.id, + "subaccountId": subaccount_id, + "orderHash": order_hash, + "cid": cid, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_cancel_spot_orders(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + + order_data = basic_composer.order_data( + market_id=spot_market.id, + subaccount_id=subaccount_id, + order_hash="0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000", + ) + + message = basic_composer.msg_batch_cancel_spot_orders( + sender=sender, + orders_data=[order_data], + ) + + assert "injective.exchange.v1beta1.MsgBatchCancelSpotOrders" == message.DESCRIPTOR.full_name + expected_message = { + "sender": sender, + "data": [json_format.MessageToDict(message=order_data, including_default_value_fields=True)], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_update_orders(self, basic_composer): + spot_market = list(basic_composer.spot_markets.values())[0] + derivative_market = list(basic_composer.derivative_markets.values())[0] + binary_options_market = list(basic_composer.binary_option_markets.values())[0] + + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + spot_market_id = spot_market.id + derivative_market_id = derivative_market.id + binary_options_market_id = binary_options_market.id + spot_order_to_cancel = basic_composer.order_data( + market_id=spot_market_id, + subaccount_id=subaccount_id, + order_hash="0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000", + ) + derivative_order_to_cancel = basic_composer.order_data( + market_id=derivative_market_id, + subaccount_id=subaccount_id, + order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2", + ) + binary_options_order_to_cancel = basic_composer.order_data( + market_id=binary_options_market_id, + subaccount_id=subaccount_id, + order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5", + ) + spot_order_to_create = basic_composer.spot_order( + market_id=spot_market_id, + subaccount_id=subaccount_id, + fee_recipient="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + price=Decimal("36.1"), + quantity=Decimal("100"), + order_type="BUY", + cid="test_cid", + trigger_price=Decimal("43.5"), + ) + derivative_order_to_create = basic_composer.derivative_order( + market_id=derivative_market_id, + subaccount_id=subaccount_id, + fee_recipient="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + price=Decimal("36.1"), + quantity=Decimal("100"), + margin=Decimal("36.1") * Decimal("100"), + order_type="BUY", + ) + binary_options_order_to_create = basic_composer.binary_options_order( + market_id=binary_options_market_id, + subaccount_id=subaccount_id, + fee_recipient="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + price=Decimal("36.1"), + quantity=Decimal("100"), + margin=Decimal("36.1") * Decimal("100"), + order_type="BUY", + ) + + message = basic_composer.msg_batch_update_orders( + sender=sender, + subaccount_id=subaccount_id, + spot_market_ids_to_cancel_all=[spot_market_id], + derivative_market_ids_to_cancel_all=[derivative_market_id], + spot_orders_to_cancel=[spot_order_to_cancel], + derivative_orders_to_cancel=[derivative_order_to_cancel], + spot_orders_to_create=[spot_order_to_create], + derivative_orders_to_create=[derivative_order_to_create], + binary_options_orders_to_cancel=[binary_options_order_to_cancel], + binary_options_market_ids_to_cancel_all=[binary_options_market_id], + binary_options_orders_to_create=[binary_options_order_to_create], + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "spotMarketIdsToCancelAll": [spot_market_id], + "derivativeMarketIdsToCancelAll": [derivative_market_id], + "spotOrdersToCancel": [ + json_format.MessageToDict(message=spot_order_to_cancel, including_default_value_fields=True) + ], + "derivativeOrdersToCancel": [ + json_format.MessageToDict(message=derivative_order_to_cancel, including_default_value_fields=True) + ], + "spotOrdersToCreate": [ + json_format.MessageToDict(message=spot_order_to_create, including_default_value_fields=True) + ], + "derivativeOrdersToCreate": [ + json_format.MessageToDict(message=derivative_order_to_create, including_default_value_fields=True) + ], + "binaryOptionsOrdersToCancel": [ + json_format.MessageToDict(message=binary_options_order_to_cancel, including_default_value_fields=True) + ], + "binaryOptionsMarketIdsToCancelAll": [binary_options_market_id], + "binaryOptionsOrdersToCreate": [ + json_format.MessageToDict(message=binary_options_order_to_create, including_default_value_fields=True) + ], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_privileged_execute_contract(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + contract_address = "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7" + data = "test_data" + funds = "100inj,420peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7" + + message = basic_composer.msg_privileged_execute_contract( + sender=sender, + contract_address=contract_address, + data=data, + funds=funds, + ) + + expected_message = { + "sender": sender, + "funds": funds, + "contractAddress": contract_address, + "data": data, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_derivative_limit_order(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_derivative_limit_order( + market_id=derivative_market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = derivative_market.price_to_chain_format(human_readable_value=price) + expected_quantity = derivative_market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = derivative_market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = derivative_market.price_to_chain_format(human_readable_value=trigger_price) + + expected_message = { + "sender": sender, + "order": { + "marketId": derivative_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "margin": f"{expected_margin.normalize():f}", + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_create_derivative_limit_orders(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + order = basic_composer.derivative_order( + market_id=derivative_market.id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=price * quantity, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + message = basic_composer.msg_batch_create_derivative_limit_orders( + sender=sender, + orders=[order], + ) + + expected_message = { + "sender": sender, + "orders": [json_format.MessageToDict(message=order, including_default_value_fields=True)], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_derivative_market_order(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_derivative_market_order( + market_id=derivative_market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = derivative_market.price_to_chain_format(human_readable_value=price) + expected_quantity = derivative_market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = derivative_market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = derivative_market.price_to_chain_format(human_readable_value=trigger_price) + + expected_message = { + "sender": sender, + "order": { + "marketId": derivative_market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "margin": f"{expected_margin.normalize():f}", + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_cancel_derivative_order(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + order_hash = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + cid = "test_cid" + is_conditional = False + is_buy = True + is_market_order = False + + expected_order_mask = basic_composer._order_mask( + is_conditional=is_conditional, + is_buy=is_buy, + is_market_order=is_market_order, + ) + + message = basic_composer.msg_cancel_derivative_order( + market_id=derivative_market.id, + sender=sender, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + is_conditional=is_conditional, + is_buy=is_buy, + is_market_order=is_market_order, + ) + + expected_message = { + "sender": sender, + "marketId": derivative_market.id, + "subaccountId": subaccount_id, + "orderHash": order_hash, + "orderMask": expected_order_mask, + "cid": cid, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_batch_cancel_derivative_orders(self, basic_composer): + derivative_market = list(basic_composer.derivative_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + + order_data = basic_composer.order_data( + market_id=derivative_market.id, + subaccount_id=subaccount_id, + order_hash="0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000", + ) + + message = basic_composer.msg_batch_cancel_derivative_orders( + sender=sender, + orders_data=[order_data], + ) + + expected_message = { + "sender": sender, + "data": [json_format.MessageToDict(message=order_data, including_default_value_fields=True)], + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_instant_binary_options_market_launch(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + ticker = "B2500/INJ" + oracle_symbol = "B2500_1/INJ" + oracle_provider = "Injective" + oracle_scale_factor = 6 + oracle_type = "Band" + quote_denom = "INJ" + min_price_tick_size = Decimal("0.01") + min_quantity_tick_size = Decimal("1") + maker_fee_rate = Decimal("0.001") + taker_fee_rate = Decimal("-0.002") + expiration_timestamp = 1630000000 + settlement_timestamp = 1660000000 + admin = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + + quote_token = basic_composer.tokens[quote_denom] + + expected_min_price_tick_size = min_price_tick_size * Decimal( + f"1e{quote_token.decimals + ADDITIONAL_CHAIN_FORMAT_DECIMALS}" + ) + expected_min_quantity_tick_size = min_quantity_tick_size * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_maker_fee_rate = maker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + expected_taker_fee_rate = taker_fee_rate * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}") + + message = basic_composer.msg_instant_binary_options_market_launch( + sender=sender, + ticker=ticker, + oracle_symbol=oracle_symbol, + oracle_provider=oracle_provider, + oracle_type=oracle_type, + oracle_scale_factor=oracle_scale_factor, + maker_fee_rate=maker_fee_rate, + taker_fee_rate=taker_fee_rate, + expiration_timestamp=expiration_timestamp, + settlement_timestamp=settlement_timestamp, + admin=admin, + quote_denom=quote_denom, + min_price_tick_size=min_price_tick_size, + min_quantity_tick_size=min_quantity_tick_size, + ) + + expected_message = { + "sender": sender, + "ticker": ticker, + "oracleSymbol": oracle_symbol, + "oracleProvider": oracle_provider, + "oracleType": oracle_type, + "oracleScaleFactor": oracle_scale_factor, + "makerFeeRate": f"{expected_maker_fee_rate.normalize():f}", + "takerFeeRate": f"{expected_taker_fee_rate.normalize():f}", + "expirationTimestamp": str(expiration_timestamp), + "settlementTimestamp": str(settlement_timestamp), + "admin": admin, + "quoteDenom": quote_token.denom, + "minPriceTickSize": f"{expected_min_price_tick_size.normalize():f}", + "minQuantityTickSize": f"{expected_min_quantity_tick_size.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_binary_options_limit_order(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_binary_options_limit_order( + market_id=market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = market.price_to_chain_format(human_readable_value=price) + expected_quantity = market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = market.price_to_chain_format(human_readable_value=trigger_price) + + expected_message = { + "sender": sender, + "order": { + "marketId": market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "margin": f"{expected_margin.normalize():f}", + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_create_binary_options_market_order(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + price = Decimal("36.1") + quantity = Decimal("100") + margin = price * quantity + order_type = "BUY" + cid = "test_cid" + trigger_price = Decimal("43.5") + + message = basic_composer.msg_create_binary_options_market_order( + market_id=market.id, + sender=sender, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=price, + quantity=quantity, + margin=margin, + order_type=order_type, + cid=cid, + trigger_price=trigger_price, + ) + + expected_price = market.price_to_chain_format(human_readable_value=price) + expected_quantity = market.quantity_to_chain_format(human_readable_value=quantity) + expected_margin = market.margin_to_chain_format(human_readable_value=margin) + expected_trigger_price = market.price_to_chain_format(human_readable_value=trigger_price) + + expected_message = { + "sender": sender, + "order": { + "marketId": market.id, + "orderInfo": { + "subaccountId": subaccount_id, + "feeRecipient": fee_recipient, + "price": f"{expected_price.normalize():f}", + "quantity": f"{expected_quantity.normalize():f}", + "cid": cid, + }, + "margin": f"{expected_margin.normalize():f}", + "orderType": order_type, + "triggerPrice": f"{expected_trigger_price.normalize():f}", + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_cancel_derivative_order(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + order_hash = "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000000" + cid = "test_cid" + is_conditional = False + is_buy = True + is_market_order = False + + expected_order_mask = basic_composer._order_mask( + is_conditional=is_conditional, + is_buy=is_buy, + is_market_order=is_market_order, + ) + + message = basic_composer.msg_cancel_derivative_order( + market_id=market.id, + sender=sender, + subaccount_id=subaccount_id, + order_hash=order_hash, + cid=cid, + is_conditional=is_conditional, + is_buy=is_buy, + is_market_order=is_market_order, + ) + + expected_message = { + "sender": sender, + "marketId": market.id, + "subaccountId": subaccount_id, + "orderHash": order_hash, + "orderMask": expected_order_mask, + "cid": cid, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_subaccount_transfer(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + source_subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + destination_subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000002" + amount = Decimal(100) + denom = "INJ" + + token = basic_composer.tokens[denom] + + expected_amount = token.chain_formatted_value(human_readable_value=amount) + + message = basic_composer.msg_subaccount_transfer( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + amount=amount, + denom=denom, + ) + + expected_message = { + "sender": sender, + "sourceSubaccountId": source_subaccount_id, + "destinationSubaccountId": destination_subaccount_id, + "amount": { + "amount": f"{expected_amount.normalize():f}", + "denom": token.denom, + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_external_transfer(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + source_subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + destination_subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000" + amount = Decimal(100) + denom = "INJ" + + token = basic_composer.tokens[denom] + + expected_amount = token.chain_formatted_value(human_readable_value=amount) + + message = basic_composer.msg_subaccount_transfer( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + amount=amount, + denom=denom, + ) + + expected_message = { + "sender": sender, + "sourceSubaccountId": source_subaccount_id, + "destinationSubaccountId": destination_subaccount_id, + "amount": { + "amount": f"{expected_amount.normalize():f}", + "denom": token.denom, + }, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_liquidate_position(self, basic_composer): + market = list(basic_composer.derivative_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + order = basic_composer.derivative_order( + market_id=market.id, + subaccount_id=subaccount_id, + fee_recipient="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r", + price=Decimal("36.1"), + quantity=Decimal("100"), + margin=Decimal("36.1") * Decimal("100"), + order_type="BUY", + ) + + message = basic_composer.msg_liquidate_position( + sender=sender, + subaccount_id=subaccount_id, + market_id=market.id, + order=order, + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "marketId": market.id, + "order": json_format.MessageToDict(message=order, including_default_value_fields=True), + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_emergency_settle_market(self, basic_composer): + market = list(basic_composer.derivative_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + + message = basic_composer.msg_emergency_settle_market( + sender=sender, + subaccount_id=subaccount_id, + market_id=market.id, + ) + + expected_message = { + "sender": sender, + "subaccountId": subaccount_id, + "marketId": market.id, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_external_transfer(self, basic_composer): + market = list(basic_composer.derivative_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + source_subaccount_id = "0x893f2abf8034627e50cbc63923120b1122503ce0000000000000000000000001" + destination_subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000" + amount = Decimal(100) + + expected_amount = market.margin_to_chain_format(human_readable_value=amount) + + message = basic_composer.msg_increase_position_margin( + sender=sender, + source_subaccount_id=source_subaccount_id, + destination_subaccount_id=destination_subaccount_id, + market_id=market.id, + amount=amount, + ) + + expected_message = { + "sender": sender, + "sourceSubaccountId": source_subaccount_id, + "destinationSubaccountId": destination_subaccount_id, + "marketId": market.id, + "amount": f"{expected_amount.normalize():f}", + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_rewards_opt_out(self, basic_composer): + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + + message = basic_composer.msg_rewards_opt_out( + sender=sender, + ) + + expected_message = { + "sender": sender, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message + + def test_msg_admin_update_binary_options_market(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" + status = "Paused" + settlement_price = Decimal("100.5") + expiration_timestamp = 1630000000 + settlement_timestamp = 1660000000 + + expected_settlement_price = market.price_to_chain_format(human_readable_value=settlement_price) + + message = basic_composer.msg_admin_update_binary_options_market( + sender=sender, + market_id=market.id, + status=status, + settlement_price=settlement_price, + expiration_timestamp=expiration_timestamp, + settlement_timestamp=settlement_timestamp, + ) + + expected_message = { + "sender": sender, + "marketId": market.id, + "settlementPrice": f"{expected_settlement_price.normalize():f}", + "expirationTimestamp": str(expiration_timestamp), + "settlementTimestamp": str(settlement_timestamp), + "status": status, + } + dict_message = json_format.MessageToDict( + message=message, + including_default_value_fields=True, + ) + assert dict_message == expected_message diff --git a/tests/test_composer_deprecation_warnings.py b/tests/test_composer_deprecation_warnings.py new file mode 100644 index 00000000..20a86779 --- /dev/null +++ b/tests/test_composer_deprecation_warnings.py @@ -0,0 +1,522 @@ +import warnings +from decimal import Decimal + +import pytest + +from pyinjective.composer import Composer +from pyinjective.core.network import Network +from tests.model_fixtures.markets_fixtures import btc_usdt_perp_market # noqa: F401 +from tests.model_fixtures.markets_fixtures import first_match_bet_market # noqa: F401 +from tests.model_fixtures.markets_fixtures import inj_token # noqa: F401 +from tests.model_fixtures.markets_fixtures import inj_usdt_spot_market # noqa: F401 +from tests.model_fixtures.markets_fixtures import usdt_perp_token # noqa: F401 +from tests.model_fixtures.markets_fixtures import usdt_token # noqa: F401 + + +class TestComposerDeprecationWarnings: + @pytest.fixture + def basic_composer(self, inj_usdt_spot_market, btc_usdt_perp_market, first_match_bet_market): + composer = Composer( + network=Network.devnet().string(), + spot_markets={inj_usdt_spot_market.id: inj_usdt_spot_market}, + derivative_markets={btc_usdt_perp_market.id: btc_usdt_perp_market}, + binary_option_markets={first_match_bet_market.id: first_match_bet_market}, + tokens={ + inj_usdt_spot_market.base_token.symbol: inj_usdt_spot_market.base_token, + inj_usdt_spot_market.quote_token.symbol: inj_usdt_spot_market.quote_token, + btc_usdt_perp_market.quote_token.symbol: btc_usdt_perp_market.quote_token, + }, + ) + + return composer + + def test_msg_deposit_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgDeposit(sender="sender", subaccount_id="subaccount id", amount=1, denom="INJ") + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_deposit instead" + + def test_msg_withdraw_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgWithdraw(sender="sender", subaccount_id="subaccount id", amount=1, denom="USDT") + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_withdraw instead" + + def teste_order_data_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.OrderData( + market_id="market id", + subaccount_id="subaccount id", + order_hash="order hash", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use order_data instead" + + def test_spot_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.SpotOrder( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + is_buy=True, + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use spot_order instead" + + def test_derivative_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.DerivativeOrder( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + is_buy=True, + cid="cid", + leverage=1, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use derivative_order instead" + + def test_msg_create_spot_limit_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCreateSpotLimitOrder( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_create_spot_limit_order instead" + ) + + def test_msg_batch_create_spot_limit_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + order = composer.spot_order( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=Decimal(1), + quantity=Decimal(1), + order_type="BUY", + ) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchCreateSpotLimitOrders( + sender="sender", + orders=[order], + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_batch_create_spot_limit_orders instead" + ) + + def test_msg_create_spot_market_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCreateSpotMarketOrder( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + is_buy=True, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_spot_market_order instead" + ) + + def test_msg_cancel_spot_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCancelSpotOrder( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + sender="sender", + subaccount_id="subaccount id", + order_hash="order hash", + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_cancel_spot_order instead" + + def test_msg_batch_cancel_spot_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + orders = [ + composer.order_data( + market_id="0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0", + subaccount_id="subaccount_id", + order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", + ), + ] + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchCancelSpotOrders(sender="sender", data=orders) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_batch_cancel_spot_orders instead" + ) + + def test_msg_batch_update_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchUpdateOrders(sender="sender") + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_batch_update_orders instead" + + def test_msg_privileged_execute_contract_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgPrivilegedExecuteContract( + sender="sender", + contract="contract", + msg="msg", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_privileged_execute_contract instead" + ) + + def test_msg_create_derivative_limit_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCreateDerivativeLimitOrder( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + leverage=1, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_derivative_limit_order instead" + ) + + def test_msg_batch_create_derivative_limit_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + order = composer.derivative_order( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=Decimal(1), + quantity=Decimal(1), + margin=Decimal(1), + order_type="BUY", + ) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchCreateDerivativeLimitOrders( + sender="sender", + orders=[order], + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_batch_create_derivative_limit_orders instead" + ) + + def test_msg_create_derivative_market_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCreateDerivativeMarketOrder( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + leverage=1, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_derivative_market_order instead" + ) + + def test_msg_cancel_derivative_order_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgCancelDerivativeOrder( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + sender="sender", + subaccount_id="subaccount id", + order_hash="order hash", + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_cancel_derivative_order instead" + ) + + def test_msg_batch_cancel_derivative_orders_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + orders = [ + composer.order_data( + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + subaccount_id="subaccount_id", + order_hash="0x3870fbdd91f07d54425147b1bb96404f4f043ba6335b422a6d494d285b387f2d", + ), + ] + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgBatchCancelDerivativeOrders(sender="sender", data=orders) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_batch_cancel_derivative_orders instead" + ) + + def test_msg_instant_binary_options_market_launch_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgInstantBinaryOptionsMarketLaunch( + sender="sender", + ticker="B2400/INJ", + oracle_symbol="B2400/INJ", + oracle_provider="injective", + oracle_type="Band", + oracle_scale_factor=6, + maker_fee_rate=0.001, + taker_fee_rate=0.001, + expiration_timestamp=1630000000, + settlement_timestamp=1630000000, + quote_denom="inj", + quote_decimals=18, + min_price_tick_size=0.01, + min_quantity_tick_size=0.01, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_instant_binary_options_market_launch instead" + ) + + def test_msg_create_binary_options_limit_order_deprecation_warning(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + + with warnings.catch_warnings(record=True) as all_warnings: + basic_composer.MsgCreateBinaryOptionsLimitOrder( + market_id=market.id, + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + is_buy=True, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_binary_options_limit_order instead" + ) + + def test_msg_create_binary_options_market_order_deprecation_warning(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + + with warnings.catch_warnings(record=True) as all_warnings: + basic_composer.MsgCreateBinaryOptionsMarketOrder( + market_id=market.id, + sender="sender", + subaccount_id="subaccount id", + fee_recipient="fee recipient", + price=1, + quantity=1, + cid="cid", + is_buy=True, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_create_binary_options_market_order instead" + ) + + def test_msg_cancel_binary_options_order_deprecation_warning(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + + with warnings.catch_warnings(record=True) as all_warnings: + basic_composer.MsgCancelBinaryOptionsOrder( + market_id=market.id, + sender="sender", + subaccount_id="subaccount id", + order_hash="order hash", + cid="cid", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_cancel_binary_options_order instead" + ) + + def test_msg_subaccount_transfer_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgSubaccountTransfer( + sender="sender", + source_subaccount_id="source subaccount id", + destination_subaccount_id="destination subaccount id", + amount=1, + denom="INJ", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_subaccount_transfer instead" + + def test_msg_external_transfer_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgExternalTransfer( + sender="sender", + source_subaccount_id="source subaccount id", + destination_subaccount_id="destination subaccount id", + amount=1, + denom="INJ", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_external_transfer instead" + + def test_msg_liquidate_position_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgLiquidatePosition( + sender="sender", + subaccount_id="subaccount id", + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_liquidate_position instead" + + def test_msg_increase_position_margin_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgIncreasePositionMargin( + sender="sender", + source_subaccount_id="source_subaccount id", + destination_subaccount_id="destination_subaccount id", + market_id="0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4", + amount=1, + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_increase_position_margin instead" + ) + + def test_msg_rewards_opt_out_deprecation_warning(self): + composer = Composer(network=Network.devnet().string()) + + with warnings.catch_warnings(record=True) as all_warnings: + composer.MsgRewardsOptOut( + sender="sender", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert str(deprecation_warnings[0].message) == "This method is deprecated. Use msg_rewards_opt_out instead" + + def test_msg_admin_update_binary_options_market_deprecation_warning(self, basic_composer): + market = list(basic_composer.binary_option_markets.values())[0] + + with warnings.catch_warnings(record=True) as all_warnings: + basic_composer.MsgAdminUpdateBinaryOptionsMarket( + sender="sender", + market_id=market.id, + status="Paused", + ) + + deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)] + assert len(deprecation_warnings) == 1 + assert ( + str(deprecation_warnings[0].message) + == "This method is deprecated. Use msg_admin_update_binary_options_market instead" + ) diff --git a/tests/test_orderhash.py b/tests/test_orderhash.py index c57b6305..c2940d8d 100644 --- a/tests/test_orderhash.py +++ b/tests/test_orderhash.py @@ -1,3 +1,5 @@ +from decimal import Decimal + from pyinjective import PrivateKey from pyinjective.composer import Composer from pyinjective.core.network import Network @@ -22,23 +24,21 @@ def test_spot_order_hash(self, requests_mock): fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r" spot_orders = [ - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=0.524, - quantity=0.01, - is_buy=True, - is_po=False, + price=Decimal("0.524"), + quantity=Decimal("0.01"), + order_type="BUY", ), - composer.SpotOrder( + composer.spot_order( market_id=spot_market_id, subaccount_id=subaccount_id, fee_recipient=fee_recipient, - price=27.92, - quantity=0.01, - is_buy=False, - is_po=False, + price=Decimal("27.92"), + quantity=Decimal("0.01"), + order_type="SELL", ), ] From 2991ccd3bb69ff0ca2854f4a610345dfd1b8ba98 Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 27 Feb 2024 10:50:54 -0300 Subject: [PATCH 6/7] (feat) Adde CodeRabbit configuration file --- .coderabbit.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 00000000..8e534ba3 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,6 @@ +reviews: + auto_review: + base_branches: + - "master" + - "dev" + - "feat/.*" From a435b211596f304bbf24a57e85eb9ef67f0ee13b Mon Sep 17 00:00:00 2001 From: abel Date: Tue, 27 Feb 2024 13:11:47 -0300 Subject: [PATCH 7/7] (fix) Fix in CodeRabbit confir YAML file --- .coderabbit.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 8e534ba3..930db111 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -4,3 +4,5 @@ reviews: - "master" - "dev" - "feat/.*" +chat: + auto_reply: true