Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/add support exchange v2 #354

Draft
wants to merge 7 commits into
base: dev
Choose a base branch
from
Draft

Conversation

aarmoa
Copy link
Collaborator

@aarmoa aarmoa commented Nov 4, 2024

  • Added support for all queries and messages from the new Exchange V2.
  • Applied the required updates for the chain stream
  • Deprecated all methods from Exchange V1 in favor of the ones from Exchange V2.
  • Updated all example scripts using Exchange V1 elements to use Exchange V2.
  • Updated unit tests.

IMPORTANT: Do not merge this PR until the Exchange V2 protos are officially part of a chain releas and the buf.gen.yaml file can be changed to point to an official tag instead of a non-release branch.

Solves CHAIN-220

Summary by CodeRabbit

  • New Features

    • Introduced new asynchronous methods for querying active stake grants and grant authorizations.
    • Added support for Level 3 order book queries for both spot and derivative markets.
    • Enhanced the ChainGrpcExchangeApi with new functionalities related to trading operations and market data retrieval.
  • Bug Fixes

    • Updated method signatures and response handling to align with new API specifications.
  • Documentation

    • Added detailed comments and structure to newly generated protocol buffer files for better understanding and integration.
  • Refactor

    • Improved method naming conventions and parameter handling across various modules for consistency and clarity.

…include new V2 chain stream protos. Fixed all failing tests
…ies and messages. Added tests for the deprecated V1 methods. Updated all example scripts related to Exchange module
…lient to get markets from the chain. Removed logic in Composer to load markets and tokens from the denom INI files
Copy link
Contributor

coderabbitai bot commented Nov 4, 2024

Walkthrough

This pull request encompasses a wide-ranging update across various modules in the Injective ecosystem. Key changes include modifications to the buf.gen.yaml configuration file, updates to method signatures in multiple Python scripts to reflect new versions of order creation and messaging functions, and the introduction of new protocol buffer definitions for version 2 of the exchange API. Additionally, several new tests have been added to enhance the testing framework for the updated functionalities. The changes aim to align the codebase with the latest specifications and improve the handling of trading operations.

Changes

File Change Summary
buf.gen.yaml Updated version tags for InjectiveLabs/cosmos-sdk and InjectiveLabs/wasmd; modified configuration for InjectiveLabs/injective-core.
examples/chain_client/*.py Updated method calls for order creation and messaging to new versions (e.g., create_v2_spot_order, msg_batch_create_spot_limit_orders_v2, etc.); adjustments to event filtering logic.
examples/chain_client/authz/*.py Updated message types and method signatures to reflect new API versions.
examples/chain_client/exchange/*.py Updated method signatures for various order and market operations to their new versions; added new market and order-related messages.
pyinjective/client/chain/grpc/chain_grpc_exchange_api.py Introduced new asynchronous methods for fetching active stake grants and grant authorizations.
pyinjective/proto/injective/exchange/v2/*.py Added new message types and methods for handling trading operations, including proposals and market data.
tests/client/chain/grpc/*.py Added new test methods for enhanced coverage of the updated functionalities, including stake grants and order books.
pyinjective/constant.py Removed configuration loading logic for different network environments.
pyinjective/utils/*.py Removed files related to metadata fetching and validation.
pyinjective/proto/injective/exchange/v1beta1/*.py Updates to existing messages and methods to accommodate new fields and types.

Possibly related PRs

  • Implement OFAC list address check #346: The changes in the main PR involve updates to configuration files and repository references, while this PR introduces an OFAC address check, which is a compliance feature that could relate to how addresses are managed in the configuration.

Poem

🐇 In the land of code where rabbits play,
New methods hop in, brightening the day.
With orders and markets, all in a line,
The changes are many, the future looks fine!
So let’s code and create, let our dreams take flight,
In the world of Injective, everything feels right! 🌟


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@aarmoa aarmoa marked this pull request as draft November 4, 2024 18:15
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

🛑 Comments failed to post (38)
examples/chain_client/tx/query/1_GetTx.py (1)

8-8: 💡 Codebase verification

Based on the search results, I can now generate the final response since I have enough information to verify the network configuration change:

Network configuration change requires attention

The switch from testnet() to devnet() in this example file is inconsistent with the rest of the codebase. The search results show that almost all example files (180+ files) use Network.testnet(), with only 7 files using devnet() and these are specifically in the permissions module examples.

  • examples/chain_client/tx/query/1_GetTx.py should maintain consistency with other example files by using Network.testnet()
🔗 Analysis chain

Verify the network configuration change.

The switch from testnet() to devnet() might impact example execution and documentation. Given that this PR is about Exchange V2 support, we should ensure this environment change aligns with where V2 features are currently deployed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if other example files consistently use devnet
# and verify if there's documentation about the network requirement

# Check network configuration across all example files
echo "Checking network configuration in example files..."
rg -l "Network\." examples/ | xargs rg "Network\.(testnet|devnet|mainnet)"

# Check if there's documentation about network requirements
echo "Checking for network documentation..."
fd -t f "README" examples/ | xargs rg -i "network|devnet|testnet"

Length of output: 174929

examples/chain_client/exchange/query/60_L3SpotOrderBook.py (2)

20-21: 🛠️ Refactor suggestion

Use modern asyncio patterns.

Replace the deprecated get_event_loop().run_until_complete() with the modern asyncio.run().

 if __name__ == "__main__":
-    asyncio.get_event_loop().run_until_complete(main())
+    asyncio.run(main())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

if __name__ == "__main__":
    asyncio.run(main())

7-17: 🛠️ Refactor suggestion

Add error handling and documentation.

The example would benefit from:

  1. Error handling for potential network/gRPC failures
  2. Documentation explaining the market ID and response format
  3. Proper cleanup of client resources

Consider this improved implementation:

 async def main() -> None:
+    """
+    Example demonstrating how to fetch L3 spot orderbook using Exchange V2.
+    
+    Market ID represents INJ/USDT spot market on testnet.
+    Response includes buy/sell orders with price levels and quantities.
+    """
     # select network: local, testnet, mainnet
     network = Network.testnet()
 
     # initialize grpc client
     client = AsyncClient(network)
+    try:
+        orderbook = await client.fetch_l3_spot_orderbook_v2(
+            market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
+        )
+        print(orderbook)
+    except Exception as e:
+        print(f"Failed to fetch orderbook: {e}")
+    finally:
+        await client.close()
-    orderbook = await client.fetch_l3_spot_orderbook_v2(
-        market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
-    )
-    print(orderbook)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

async def main() -> None:
    """
    Example demonstrating how to fetch L3 spot orderbook using Exchange V2.
    
    Market ID represents INJ/USDT spot market on testnet.
    Response includes buy/sell orders with price levels and quantities.
    """
    # select network: local, testnet, mainnet
    network = Network.testnet()

    # initialize grpc client
    client = AsyncClient(network)
    try:
        orderbook = await client.fetch_l3_spot_orderbook_v2(
            market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
        )
        print(orderbook)
    except Exception as e:
        print(f"Failed to fetch orderbook: {e}")
    finally:
        await client.close()
examples/chain_client/exchange/query/59_L3DerivativeOrderBook.py (1)

7-17: 🛠️ Refactor suggestion

Add error handling and improve documentation.

As this is an example script, it should demonstrate proper error handling and provide clear documentation for users.

Consider applying these improvements:

-async def main() -> None:
+async def main() -> None:
+    """Fetch and display L3 derivative orderbook data.
+    
+    Market ID represents INJ/USDT perpetual futures market on testnet.
+    The orderbook response includes buy and sell orders with price levels.
+    """
     # select network: local, testnet, mainnet
     network = Network.testnet()
 
     # initialize grpc client
     client = AsyncClient(network)
 
-    orderbook = await client.fetch_l3_derivative_orderbook_v2(
-        market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
-    )
-    print(orderbook)
+    try:
+        orderbook = await client.fetch_l3_derivative_orderbook_v2(
+            market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
+        )
+        print("L3 Derivative Orderbook:")
+        print(f"Market ID: {orderbook.market_id}")
+        print("\nBuy Orders:")
+        for order in orderbook.buys:
+            print(f"  Price: {order.price}, Quantity: {order.quantity}")
+        print("\nSell Orders:")
+        for order in orderbook.sells:
+            print(f"  Price: {order.price}, Quantity: {order.quantity}")
+    except Exception as e:
+        print(f"Error fetching orderbook: {str(e)}")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

async def main() -> None:
    """Fetch and display L3 derivative orderbook data.
    
    Market ID represents INJ/USDT perpetual futures market on testnet.
    The orderbook response includes buy and sell orders with price levels.
    """
    # select network: local, testnet, mainnet
    network = Network.testnet()

    # initialize grpc client
    client = AsyncClient(network)

    try:
        orderbook = await client.fetch_l3_derivative_orderbook_v2(
            market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
        )
        print("L3 Derivative Orderbook:")
        print(f"Market ID: {orderbook.market_id}")
        print("\nBuy Orders:")
        for order in orderbook.buys:
            print(f"  Price: {order.price}, Quantity: {order.quantity}")
        print("\nSell Orders:")
        for order in orderbook.sells:
            print(f"  Price: {order.price}, Quantity: {order.quantity}")
    except Exception as e:
        print(f"Error fetching orderbook: {str(e)}")
examples/chain_client/exchange/query/56_ActiveStakeGrant.py (2)

26-27: 🛠️ Refactor suggestion

Use modern asyncio patterns.

The current event loop pattern is deprecated. Use asyncio.run() instead for better error handling and cleaner code.

 if __name__ == "__main__":
-    asyncio.get_event_loop().run_until_complete(main())
+    asyncio.run(main())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

if __name__ == "__main__":
    asyncio.run(main())

10-23: ⚠️ Potential issue

Add error handling and input validation.

The implementation needs several improvements for robustness:

  1. Add error handling for missing environment variables
  2. Validate the grantee address format
  3. Properly close the AsyncClient

Here's the suggested implementation:

 async def main() -> None:
     dotenv.load_dotenv()
-    grantee_public_address = os.getenv("INJECTIVE_GRANTEE_PUBLIC_ADDRESS")
+    grantee_public_address = os.getenv("INJECTIVE_GRANTEE_PUBLIC_ADDRESS")
+    if not grantee_public_address:
+        raise ValueError("INJECTIVE_GRANTEE_PUBLIC_ADDRESS environment variable is required")
+
+    # Basic address format validation
+    if not grantee_public_address.startswith("inj"):
+        raise ValueError("Invalid Injective address format")

     # select network: local, testnet, mainnet
     network = Network.testnet()

     # initialize grpc client
     client = AsyncClient(network)
+    try:
+        active_grant = await client.fetch_active_stake_grant(
+            grantee=grantee_public_address,
+        )
+        print(active_grant)
+    finally:
+        await client.close()
-    active_grant = await client.fetch_active_stake_grant(
-        grantee=grantee_public_address,
-    )
-    print(active_grant)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

async def main() -> None:
    dotenv.load_dotenv()
    grantee_public_address = os.getenv("INJECTIVE_GRANTEE_PUBLIC_ADDRESS")
    if not grantee_public_address:
        raise ValueError("INJECTIVE_GRANTEE_PUBLIC_ADDRESS environment variable is required")

    # Basic address format validation
    if not grantee_public_address.startswith("inj"):
        raise ValueError("Invalid Injective address format")

    # select network: local, testnet, mainnet
    network = Network.testnet()

    # initialize grpc client
    client = AsyncClient(network)
    try:
        active_grant = await client.fetch_active_stake_grant(
            grantee=grantee_public_address,
        )
        print(active_grant)
    finally:
        await client.close()
examples/chain_client/exchange/query/5_AggregateVolumes.py (1)

26-29: 🛠️ Refactor suggestion

Add error handling for the API call.

The example should demonstrate proper error handling for production use.

-    volume = await client.fetch_aggregate_volumes_v2(
-        accounts=[address.to_acc_bech32()],
-        market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"],
-    )
-    print(volume)
+    try:
+        volume = await client.fetch_aggregate_volumes_v2(
+            accounts=[address.to_acc_bech32()],
+            market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"],
+        )
+        print(volume)
+    except Exception as e:
+        print(f"Failed to fetch aggregate volumes: {str(e)}")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    try:
        volume = await client.fetch_aggregate_volumes_v2(
            accounts=[address.to_acc_bech32()],
            market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"],
        )
        print(volume)
    except Exception as e:
        print(f"Failed to fetch aggregate volumes: {str(e)}")
examples/chain_client/exchange/query/58_GrantAuthorizations.py (4)

12-14: ⚠️ Potential issue

Add error handling for environment variables.

The script should gracefully handle missing or invalid environment variables.

-    dotenv.load_dotenv()
-    configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
+    if not dotenv.load_dotenv():
+        raise RuntimeError("Failed to load .env file")
+    
+    configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
+    if not configured_private_key:
+        raise ValueError("INJECTIVE_PRIVATE_KEY environment variable is not set")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    if not dotenv.load_dotenv():
        raise RuntimeError("Failed to load .env file")
    
    configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
    if not configured_private_key:
        raise ValueError("INJECTIVE_PRIVATE_KEY environment variable is not set")


21-23: ⚠️ Potential issue

Add error handling for private key conversion.

The private key conversion should be wrapped in a try-catch block to handle invalid keys gracefully.

-    priv_key = PrivateKey.from_hex(configured_private_key)
-    pub_key = priv_key.to_public_key()
-    address = pub_key.to_address()
+    try:
+        priv_key = PrivateKey.from_hex(configured_private_key)
+        pub_key = priv_key.to_public_key()
+        address = pub_key.to_address()
+    except ValueError as e:
+        raise ValueError(f"Invalid private key format: {e}")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    try:
        priv_key = PrivateKey.from_hex(configured_private_key)
        pub_key = priv_key.to_public_key()
        address = pub_key.to_address()
    except ValueError as e:
        raise ValueError(f"Invalid private key format: {e}")

31-32: 🛠️ Refactor suggestion

Update to modern asyncio pattern.

Replace the deprecated event loop pattern with asyncio.run() for better compatibility with Python 3.7+.

 if __name__ == "__main__":
-    asyncio.get_event_loop().run_until_complete(main())
+    asyncio.run(main())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

if __name__ == "__main__":
    asyncio.run(main())

25-28: ⚠️ Potential issue

Add error handling for API call and cleanup resources.

The API call should handle potential exceptions, and the client should be properly cleaned up after use.

-    active_grant = await client.fetch_grant_authorizations(
-        granter=address.to_acc_bech32(),
-    )
-    print(active_grant)
+    try:
+        active_grant = await client.fetch_grant_authorizations(
+            granter=address.to_acc_bech32(),
+        )
+        print(active_grant)
+    except Exception as e:
+        print(f"Failed to fetch grant authorizations: {e}")
+        raise
+    finally:
+        await client.close()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    try:
        active_grant = await client.fetch_grant_authorizations(
            granter=address.to_acc_bech32(),
        )
        print(active_grant)
    except Exception as e:
        print(f"Failed to fetch grant authorizations: {e}")
        raise
    finally:
        await client.close()
buf.gen.yaml (1)

26-28: ⚠️ Potential issue

Replace feature branch with official release tag.

Using a feature branch (feat/update_chain_stream_for_exchange_v2) in production dependencies is risky as they're unstable and can change unexpectedly. According to the PR objectives, this PR should not be merged until the Exchange V2 protobufs are in an official chain release and this file references an official tag.

Wait for the official release and then apply this change:

  - git_repo: https://github.com/InjectiveLabs/injective-core
-   branch: feat/update_chain_stream_for_exchange_v2
+   tag: <official-release-tag>
    subdir: proto

Committable suggestion skipped: line range outside the PR's diff.

examples/chain_client/exchange/query/57_GrantAuthorization.py (4)

33-34: 🛠️ Refactor suggestion

Update asyncio usage to modern pattern.

The get_event_loop().run_until_complete() pattern is deprecated. Use asyncio.run() instead.

Apply this improvement:

 if __name__ == "__main__":
-    asyncio.get_event_loop().run_until_complete(main())
+    asyncio.run(main())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

if __name__ == "__main__":
    asyncio.run(main())

22-24: 🛠️ Refactor suggestion

Add error handling for key conversion.

The private key conversion could fail if the input format is invalid. Consider adding try-catch block to handle potential errors gracefully.

Consider this improvement:

-    priv_key = PrivateKey.from_hex(configured_private_key)
-    pub_key = priv_key.to_public_key()
-    address = pub_key.to_address()
+    try:
+        priv_key = PrivateKey.from_hex(configured_private_key)
+        pub_key = priv_key.to_public_key()
+        address = pub_key.to_address()
+    except ValueError as e:
+        raise ValueError(f"Invalid private key format: {e}")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    try:
        priv_key = PrivateKey.from_hex(configured_private_key)
        pub_key = priv_key.to_public_key()
        address = pub_key.to_address()
    except ValueError as e:
        raise ValueError(f"Invalid private key format: {e}")

26-30: 🛠️ Refactor suggestion

Enhance error handling and response formatting.

The current implementation could benefit from proper error handling and formatted output.

Consider these improvements:

-    active_grant = await client.fetch_grant_authorization(
-        granter=address.to_acc_bech32(),
-        grantee=grantee_public_address,
-    )
-    print(active_grant)
+    try:
+        active_grant = await client.fetch_grant_authorization(
+            granter=address.to_acc_bech32(),
+            grantee=grantee_public_address,
+        )
+        print("Grant Authorization Details:")
+        print(f"Granter: {address.to_acc_bech32()}")
+        print(f"Grantee: {grantee_public_address}")
+        print(f"Authorization: {active_grant}")
+    except Exception as e:
+        print(f"Error fetching grant authorization: {e}")
+        raise
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    try:
        active_grant = await client.fetch_grant_authorization(
            granter=address.to_acc_bech32(),
            grantee=grantee_public_address,
        )
        print("Grant Authorization Details:")
        print(f"Granter: {address.to_acc_bech32()}")
        print(f"Grantee: {grantee_public_address}")
        print(f"Authorization: {active_grant}")
    except Exception as e:
        print(f"Error fetching grant authorization: {e}")
        raise

11-15: 🛠️ Refactor suggestion

Add environment variable validation and error handling.

The script should validate that required environment variables are present and contain valid values before proceeding.

Consider applying this improvement:

 async def main() -> None:
     dotenv.load_dotenv()
     configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
     grantee_public_address = os.getenv("INJECTIVE_GRANTEE_PUBLIC_ADDRESS")
+    
+    if not configured_private_key or not grantee_public_address:
+        raise ValueError(
+            "Missing required environment variables. Please ensure INJECTIVE_PRIVATE_KEY "
+            "and INJECTIVE_GRANTEE_PUBLIC_ADDRESS are set in your .env file"
+        )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

async def main() -> None:
    dotenv.load_dotenv()
    configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
    grantee_public_address = os.getenv("INJECTIVE_GRANTEE_PUBLIC_ADDRESS")
    
    if not configured_private_key or not grantee_public_address:
        raise ValueError(
            "Missing required environment variables. Please ensure INJECTIVE_PRIVATE_KEY "
            "and INJECTIVE_GRANTEE_PUBLIC_ADDRESS are set in your .env file"
        )
examples/chain_client/2_StreamEventOrderFail.py (1)

35-36: 🛠️ Refactor suggestion

Add error handling for event processing.

While the path updates for Exchange V2 are correct, the code lacks error handling for missing or malformed events.

Consider wrapping the event processing in a try-except block:

-            failed_order_hashes = json.loads(result["events"]["injective.exchange.v2.EventOrderFail.hashes"][0])
-            failed_order_codes = json.loads(result["events"]["injective.exchange.v2.EventOrderFail.flags"][0])
+            try:
+                failed_order_hashes = json.loads(result["events"]["injective.exchange.v2.EventOrderFail.hashes"][0])
+                failed_order_codes = json.loads(result["events"]["injective.exchange.v2.EventOrderFail.flags"][0])
+            except (KeyError, IndexError, json.JSONDecodeError) as e:
+                print(f"Error processing event: {e}")
+                continue
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

            try:
                failed_order_hashes = json.loads(result["events"]["injective.exchange.v2.EventOrderFail.hashes"][0])
                failed_order_codes = json.loads(result["events"]["injective.exchange.v2.EventOrderFail.flags"][0])
            except (KeyError, IndexError, json.JSONDecodeError) as e:
                print(f"Error processing event: {e}")
                continue
examples/chain_client/ibc/transfer/1_MsgTransfer.py (1)

39-42: 🛠️ Refactor suggestion

Add validation and improve clarity of token amount calculation.

While the use of Decimal for precise calculations is good, consider adding basic validation:

 token_decimals = 18
+# Validate transfer amount is positive
 transfer_amount = Decimal("0.1") * Decimal(f"1e{token_decimals}")
+if transfer_amount <= 0:
+    raise ValueError("Transfer amount must be positive")
 inj_chain_denom = "inj"
 token_amount = composer.coin(amount=int(transfer_amount), denom=inj_chain_denom)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    token_decimals = 18
    # Validate transfer amount is positive
    transfer_amount = Decimal("0.1") * Decimal(f"1e{token_decimals}")
    if transfer_amount <= 0:
        raise ValueError("Transfer amount must be positive")
    inj_chain_denom = "inj"
    token_amount = composer.coin(amount=int(transfer_amount), denom=inj_chain_denom)
examples/chain_client/exchange/4_MsgInstantPerpetualMarketLaunch.py (1)

41-41: 💡 Codebase verification

🛠️ Refactor suggestion

Based on the gathered information, I can now generate the final response.

Add documentation for the factory quote denom format

The factory quote denom format (factory/<creator_address>/<subdenom>) is used consistently across spot, perpetual, and futures market launches, but lacks documentation. Add the following comment to explain the format:

    message = composer.msg_instant_perpetual_market_launch_v2(
        sender=address.to_acc_bech32(),
        ticker="INJ/USDC PERP",
+       # Quote denom format: factory/<creator_address>/<subdenom>
+       # creator_address: The Injective address that created the token
+       # subdenom: The token's subdenom (e.g., 'usdc')
        quote_denom="factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/usdc",

Evidence:

  • The format is used in multiple market launch examples but lacks explanation
  • Token factory module tests confirm this is the expected format (e.g., "factory/inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0/ninja")
  • The format is part of the token factory module's core functionality for creating and managing custom tokens
🔗 Analysis chain

Document the factory quote denom format.

The quote denom now uses a factory address format (factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/usdc). This is a breaking change that requires documentation.

Add a comment explaining the factory quote denom format:

    message = composer.msg_instant_perpetual_market_launch_v2(
        sender=address.to_acc_bech32(),
        ticker="INJ/USDC PERP",
+       # Quote denom format: factory/<creator_address>/<subdenom>
        quote_denom="factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/usdc",

Let's verify the factory address format consistency:


Let me search for any existing documentation about the factory quote denom format.


Let me check for any existing comments or documentation in the example files.


Let me check if there are any related test files or documentation that might explain the factory denom format.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify quote denom factory address format usage
# Expected: Should find consistent usage of factory address format

# Check for factory address format usage
echo "Checking factory address format usage..."
rg "factory/inj\w+/usdc" --type py -B 2 -A 2

Length of output: 1797


Script:

#!/bin/bash
# Look for documentation about factory quote denom format
echo "Searching for documentation in Python files..."
rg -i "factory.*denom" --type py -B 2 -A 2

echo -e "\nSearching for documentation in markdown files..."
rg -i "factory.*denom|quote.*denom" --type md -B 2 -A 2

echo -e "\nChecking docstrings in relevant files..."
rg "\"\"\".*factory.*denom|'''.*factory.*denom" --multiline --type py

Length of output: 34918


Script:

#!/bin/bash
# Look for comments or documentation in example files
echo "Checking example files for documentation..."
rg -B 2 -A 2 "quote_denom.*factory" examples/
rg -B 2 -A 2 "# .*factory.*denom" examples/
rg -B 2 -A 2 "\"\"\".*factory.*denom" examples/

Length of output: 1897


Script:

#!/bin/bash
# Look for test files and documentation related to factory denom
echo "Checking test files..."
fd -t f "test.*token_factory" -x cat {}

echo -e "\nChecking for token factory documentation..."
fd -t f "README|CHANGELOG|docs" -x rg -i "factory.*denom|token.*factory" {}

Length of output: 5781

examples/chain_client/exchange/1_MsgDeposit.py (1)

34-34: 🛠️ Refactor suggestion

Add documentation for V2 API changes and migration.

This example demonstrates the new V2 deposit message, but lacks documentation about important API changes:

  1. The amount parameter is now an integer instead of float
  2. The denom format has changed to lowercase
  3. V1 deposit method is being deprecated

Add a docstring explaining the changes:

+# Example of depositing funds using Exchange V2 API
+# Note: This example uses msg_deposit_v2 which expects:
+# - amount as integer (e.g., 1 instead of 0.000001)
+# - denom in lowercase format (e.g., "inj" instead of "INJ")
+# The older msg_deposit (V1) is deprecated and will be removed in future versions.
 msg = composer.msg_deposit_v2(sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=1, denom="inj")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

# Example of depositing funds using Exchange V2 API
# Note: This example uses msg_deposit_v2 which expects:
# - amount as integer (e.g., 1 instead of 0.000001)
# - denom in lowercase format (e.g., "inj" instead of "INJ")
# The older msg_deposit (V1) is deprecated and will be removed in future versions.
msg = composer.msg_deposit_v2(sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=1, denom="inj")
examples/chain_client/insurance/1_MsgCreateInsuranceFund.py (1)

35-39: 🛠️ Refactor suggestion

Add parameter validation and documentation.

Several critical parameters have been updated:

  1. The ticker format includes a timestamp (5202d32a9-1701406800-SF)
  2. quote_denom now uses a specific Peggy contract address
  3. oracle_type is now a string enum ("Band")

Consider adding:

  • Input validation for the ticker format
  • Documentation for valid oracle_type values
  • Verification of the Peggy contract address
 msg = composer.msg_create_insurance_fund(
+    # Ticker format: <id>-<timestamp>-SF
     sender=address.to_acc_bech32(),
     ticker="5202d32a9-1701406800-SF",
+    # Peggy contract address for USDT
     quote_denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
     oracle_base="Frontrunner",
     oracle_quote="Frontrunner",
+    # Supported values: "Band", "Pyth", "Provider"
     oracle_type="Band",
     expiry=-2,
     initial_deposit=1000,
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        msg = composer.msg_create_insurance_fund(
            # Ticker format: <id>-<timestamp>-SF
            sender=address.to_acc_bech32(),
            ticker="5202d32a9-1701406800-SF",
            # Peggy contract address for USDT
            quote_denom="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
            oracle_base="Frontrunner",
            oracle_quote="Frontrunner",
            # Supported values: "Band", "Pyth", "Provider"
            oracle_type="Band",
            expiry=-2,
            initial_deposit=1000,
        )
examples/chain_client/insurance/2_MsgUnderwrite.py (1)

34-36: 🛠️ Refactor suggestion

Consider making token_decimals configurable.

The hardcoded value of 6 for token_decimals might not work for all tokens. Different tokens can have different decimal places (e.g., USDT typically has 6, while others might have 18).

Consider fetching the decimals from a configuration or token metadata:

-token_decimals = 6
+# Fetch from token metadata or config
+token_decimals = get_token_decimals(quote_denom)
amount = 100
chain_amount = Decimal(str(amount)) * Decimal(f"1e{token_decimals}")

Committable suggestion skipped: line range outside the PR's diff.

examples/chain_client/exchange/12_MsgCancelDerivativeOrder.py (1)

38-45: 🛠️ Refactor suggestion

Document the new V2 parameters and improve example usability.

While the code correctly demonstrates the new V2 message structure, it could be more helpful for users migrating from V1 to V2.

Consider these improvements:

-    msg = composer.msg_cancel_derivative_order_v2(
-        sender=address.to_acc_bech32(),
-        market_id=market_id,
-        subaccount_id=subaccount_id,
-        order_hash=order_hash,
-        is_buy=True,
-        is_market_order=False,
-        is_conditional=False,
-    )
+    # New in V2: Additional parameters required for canceling orders
+    # is_buy: True for buy orders, False for sell orders
+    # is_market_order: True for market orders, False for limit orders
+    # is_conditional: True for conditional orders (e.g., stop-loss), False otherwise
+    
+    # Fetch the original order details to ensure correct cancellation parameters
+    # In a real scenario, you would typically:
+    # 1. Fetch the order details using the order_hash
+    # 2. Extract is_buy, is_market_order, and is_conditional from the order
+    
+    msg = composer.msg_cancel_derivative_order_v2(
+        sender=address.to_acc_bech32(),
+        market_id=market_id,
+        subaccount_id=subaccount_id,
+        order_hash=order_hash,
+        # These values should match the original order's properties
+        is_buy=True,  # Example: True for buy orders
+        is_market_order=False,  # Example: False for limit orders
+        is_conditional=False,  # Example: False for regular orders
+    )

Additionally, consider adding parameter validation:

def validate_order_params(is_buy: bool, is_market_order: bool, is_conditional: bool) -> None:
    """Validate the order parameters match the original order to prevent cancellation failures."""
    if not isinstance(is_buy, bool) or not isinstance(is_market_order, bool) or not isinstance(is_conditional, bool):
        raise ValueError("Order parameters must be boolean values")
examples/chain_client/peggy/1_MsgSendToEth.py (1)

40-41: 🛠️ Refactor suggestion

Consider making token decimals configurable.

The hardcoded token_decimals = 6 might not work for all tokens. Consider making this configurable or fetching it dynamically based on the token being bridged.

-token_decimals = 6
+# Fetch from token registry or pass as parameter
+token_decimals = get_token_decimals("inj")  # or pass as parameter

Committable suggestion skipped: line range outside the PR's diff.

examples/chain_client/exchange/16_MsgCancelBinaryOptionsOrder.py (1)

38-45: 🛠️ Refactor suggestion

Add documentation for new V2 parameters

The example uses hardcoded values for the new V2 parameters (is_buy=True, is_market_order=False, is_conditional=False) without explaining their significance. This could be confusing for users migrating from V1 to V2.

Consider adding comments to explain:

  1. The purpose of each new parameter
  2. How these parameters affect order cancellation
  3. When to use different combinations of these parameters
 # prepare tx msg
+# V2 Parameters explanation:
+# is_buy: True for buy orders, False for sell orders
+# is_market_order: True for market orders, False for limit orders
+# is_conditional: True for conditional orders, False for regular orders
 msg = composer.msg_cancel_binary_options_order_v2(
     sender=address.to_acc_bech32(),
     market_id=market_id,
     subaccount_id=subaccount_id,
     order_hash=order_hash,
     is_buy=True,  # Canceling a buy order
     is_market_order=False,  # Canceling a limit order
     is_conditional=False,  # Canceling a regular (non-conditional) order
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    # prepare tx msg
    # V2 Parameters explanation:
    # is_buy: True for buy orders, False for sell orders
    # is_market_order: True for market orders, False for limit orders
    # is_conditional: True for conditional orders, False for regular orders
    msg = composer.msg_cancel_binary_options_order_v2(
        sender=address.to_acc_bech32(),
        market_id=market_id,
        subaccount_id=subaccount_id,
        order_hash=order_hash,
        is_buy=True,  # Canceling a buy order
        is_market_order=False,  # Canceling a limit order
        is_conditional=False,  # Canceling a regular (non-conditional) order
    )
pyinjective/orderhash.py (1)

99-101: ⚠️ Potential issue

Add input validation to prevent potential conversion errors.

The function assumes the input string is a valid decimal number. Consider adding input validation to handle malformed inputs gracefully.

Here's a suggested improvement:

 def param_to_backend_go(param: str) -> str:
+    try:
+        decimal_param = Decimal(param)
+        if decimal_param < 0:
+            raise ValueError("Negative values are not allowed")
+    except (ValueError, TypeError, InvalidOperation) as e:
+        raise ValueError(f"Invalid parameter value: {param}. Error: {str(e)}")
     go_param = Token.convert_value_from_extended_decimal_format(value=Decimal(param))
     return f"{go_param.normalize():.18f}"

Committable suggestion skipped: line range outside the PR's diff.

examples/chain_client/1_LocalOrderHash.py (2)

92-96: 🛠️ Refactor suggestion

Consider refactoring duplicate transaction code.

The transaction building and broadcasting code is duplicated multiple times in this file. Consider extracting the common transaction building logic into a helper function.

Here's a suggested refactor:

async def build_and_broadcast_tx(
    client, 
    composer, 
    messages, 
    address, 
    network, 
    priv_key, 
    pub_key
):
    tx = (
        Transaction()
        .with_messages(*messages)
        .with_sequence(client.get_sequence())
        .with_account_num(client.get_number())
        .with_chain_id(network.chain_id)
    )
    gas_price = GAS_PRICE
    base_gas = 85000
    gas_limit = base_gas + GAS_FEE_BUFFER_AMOUNT
    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)
    
    res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
    gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
    
    return res, gas_limit, gas_fee

Then use it like:

res, gas_limit, gas_fee = await build_and_broadcast_tx(
    client=client,
    composer=composer,
    messages=[spot_msg, deriv_msg],
    address=address,
    network=network,
    priv_key=priv_key,
    pub_key=pub_key
)

221-225: ⚠️ Potential issue

Fix version compatibility issue.

This code attempts to create V2 batch messages (msg_batch_create_spot_limit_orders_v2) using orders created with V1 methods. This mixing of V1 and V2 methods could lead to compatibility issues.

Ensure that both order creation and message creation use the same version (V2) consistently throughout the example.

tests/client/chain/grpc/configurable_exchange_v2_query_servicer.py (1)

74-361: ⚠️ Potential issue

Handle potential deque underflow in response methods

In the methods from QueryExchangeParams to L3SpotOrderBook, you're calling pop() on the response deques without checking if they are empty. If a deque is empty, calling pop() will raise an IndexError. To ensure robustness, consider checking if the deque is not empty before popping, and handle the empty case appropriately.

Here is how you can modify the methods:

 async def QueryExchangeParams(
     self, request: exchange_query_pb.QueryExchangeParamsRequest, context=None, metadata=None
 ):
-    return self.exchange_params.pop()
+    if self.exchange_params:
+        return self.exchange_params.pop()
+    else:
+        # Handle empty deque case, e.g., return a default response or raise an appropriate exception
+        raise ValueError("No responses available in exchange_params deque")

Apply similar changes to all methods where you're popping from a deque to prevent unhandled exceptions.

Committable suggestion skipped: line range outside the PR's diff.

pyinjective/proto/injective/exchange/v2/market_pb2.py (1)

15-16: 🛠️ Refactor suggestion

Remove unused imports to clean up the code

The imports gogoproto_dot_gogo__pb2 and injective_dot_oracle_dot_v1beta1_dot_oracle__pb2 are not used in this module. Removing them will reduce unnecessary dependencies and improve code readability.

Apply this diff to remove the unused imports:

-from pyinjective.proto.gogoproto import gogo_pb2 as gogoproto_dot_gogo__pb2
-from pyinjective.proto.injective.oracle.v1beta1 import oracle_pb2 as injective_dot_oracle_dot_v1beta1_dot_oracle__pb2
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.


🧰 Tools
🪛 Ruff

15-15: pyinjective.proto.gogoproto.gogo_pb2 imported but unused

Remove unused import: pyinjective.proto.gogoproto.gogo_pb2

(F401)


16-16: pyinjective.proto.injective.oracle.v1beta1.oracle_pb2 imported but unused

Remove unused import: pyinjective.proto.injective.oracle.v1beta1.oracle_pb2

(F401)

pyinjective/client/chain/grpc/chain_grpc_exchange_v2_api.py (2)

625-626: 🛠️ Refactor suggestion

⚠️ Potential issue

Ensure proper exception handling in _execute_call

The _execute_call method is crucial for executing all gRPC calls within this class. It is important to ensure that this method handles exceptions appropriately to prevent unhandled exceptions from propagating and to provide meaningful error messages.

Consider reviewing the implementation of self._assistant.execute_call() to confirm that:

  • Exceptions are caught and handled or logged as needed.
  • Retry logic is implemented for transient errors.
  • Appropriate error messages are returned to the caller.

555-566: ⚠️ Potential issue

Add input validation in fetch_trader_derivative_conditional_orders

The method accepts optional subaccount_id and market_id. If both are None, the request may be invalid or return unintended results. Adding input validation to ensure that at least one parameter is provided would enhance reliability.

Apply this diff to include input validation:

 async def fetch_trader_derivative_conditional_orders(
         self,
         subaccount_id: Optional[str] = None,
         market_id: Optional[str] = None,
     ) -> Dict[str, Any]:
+        if subaccount_id is None and market_id is None:
+            raise ValueError("At least one of 'subaccount_id' or 'market_id' must be provided.")
         request = exchange_query_pb.QueryTraderDerivativeConditionalOrdersRequest(
             subaccount_id=subaccount_id,
             market_id=market_id,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        self,
        subaccount_id: Optional[str] = None,
        market_id: Optional[str] = None,
    ) -> Dict[str, Any]:
        if subaccount_id is None and market_id is None:
            raise ValueError("At least one of 'subaccount_id' or 'market_id' must be provided.")
        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
pyinjective/proto/injective/exchange/v2/exchange_pb2.py (1)

15-20: 🛠️ Refactor suggestion

Remove unused imports from the generated file.

Static analysis tools have detected that the following imports are unused:

-from pyinjective.proto.gogoproto import gogo_pb2 as gogoproto_dot_gogo__pb2
-from pyinjective.proto.amino import amino_pb2 as amino_dot_amino__pb2
-from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as cosmos_dot_base_dot_v1beta1_dot_coin__pb2
-from pyinjective.proto.injective.oracle.v1beta1 import oracle_pb2 as injective_dot_oracle_dot_v1beta1_dot_oracle__pb2
-from pyinjective.proto.injective.exchange.v2 import market_pb2 as injective_dot_exchange_dot_v2_dot_market__pb2
-from pyinjective.proto.injective.exchange.v2 import order_pb2 as injective_dot_exchange_dot_v2_dot_order__pb2

Removing these unused imports will clean up the code and eliminate unnecessary dependencies.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.


🧰 Tools
🪛 Ruff

15-15: pyinjective.proto.gogoproto.gogo_pb2 imported but unused

Remove unused import: pyinjective.proto.gogoproto.gogo_pb2

(F401)


16-16: pyinjective.proto.amino.amino_pb2 imported but unused

Remove unused import: pyinjective.proto.amino.amino_pb2

(F401)


17-17: pyinjective.proto.cosmos.base.v1beta1.coin_pb2 imported but unused

Remove unused import: pyinjective.proto.cosmos.base.v1beta1.coin_pb2

(F401)


18-18: pyinjective.proto.injective.oracle.v1beta1.oracle_pb2 imported but unused

Remove unused import: pyinjective.proto.injective.oracle.v1beta1.oracle_pb2

(F401)


19-19: pyinjective.proto.injective.exchange.v2.market_pb2 imported but unused

Remove unused import: pyinjective.proto.injective.exchange.v2.market_pb2

(F401)


20-20: pyinjective.proto.injective.exchange.v2.order_pb2 imported but unused

Remove unused import: pyinjective.proto.injective.exchange.v2.order_pb2

(F401)

pyinjective/proto/injective/exchange/v2/proposal_pb2.py (1)

15-23: 🛠️ Refactor suggestion

Remove unused imports to clean up the code

The imports on lines 15-23 are not used in this module and can be safely removed to improve code cleanliness and reduce warnings from static analysis tools. Since this file is auto-generated, please consider adjusting the code generation process or the .proto definitions to prevent unused imports.

- from pyinjective.proto.cosmos_proto import cosmos_pb2 as cosmos__proto_dot_cosmos__pb2
- from pyinjective.proto.gogoproto import gogo_pb2 as gogoproto_dot_gogo__pb2
- from pyinjective.proto.amino import amino_pb2 as amino_dot_amino__pb2
- from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as cosmos_dot_base_dot_v1beta1_dot_coin__pb2
- from pyinjective.proto.cosmos.msg.v1 import msg_pb2 as cosmos_dot_msg_dot_v1_dot_msg__pb2
- from pyinjective.proto.cosmos.distribution.v1beta1 import distribution_pb2 as cosmos_dot_distribution_dot_v1beta1_dot_distribution__pb2
- from pyinjective.proto.injective.exchange.v2 import exchange_pb2 as injective_dot_exchange_dot_v2_dot_exchange__pb2
- from pyinjective.proto.injective.exchange.v2 import market_pb2 as injective_dot_exchange_dot_v2_dot_market__pb2
- from pyinjective.proto.injective.oracle.v1beta1 import oracle_pb2 as injective_dot_oracle_dot_v1beta1_dot_oracle__pb2

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Ruff

15-15: pyinjective.proto.cosmos_proto.cosmos_pb2 imported but unused

Remove unused import: pyinjective.proto.cosmos_proto.cosmos_pb2

(F401)


16-16: pyinjective.proto.gogoproto.gogo_pb2 imported but unused

Remove unused import: pyinjective.proto.gogoproto.gogo_pb2

(F401)


17-17: pyinjective.proto.amino.amino_pb2 imported but unused

Remove unused import: pyinjective.proto.amino.amino_pb2

(F401)


18-18: pyinjective.proto.cosmos.base.v1beta1.coin_pb2 imported but unused

Remove unused import: pyinjective.proto.cosmos.base.v1beta1.coin_pb2

(F401)


19-19: pyinjective.proto.cosmos.msg.v1.msg_pb2 imported but unused

Remove unused import: pyinjective.proto.cosmos.msg.v1.msg_pb2

(F401)


20-20: pyinjective.proto.cosmos.distribution.v1beta1.distribution_pb2 imported but unused

Remove unused import: pyinjective.proto.cosmos.distribution.v1beta1.distribution_pb2

(F401)


21-21: pyinjective.proto.injective.exchange.v2.exchange_pb2 imported but unused

Remove unused import: pyinjective.proto.injective.exchange.v2.exchange_pb2

(F401)


22-22: pyinjective.proto.injective.exchange.v2.market_pb2 imported but unused

Remove unused import: pyinjective.proto.injective.exchange.v2.market_pb2

(F401)


23-23: pyinjective.proto.injective.oracle.v1beta1.oracle_pb2 imported but unused

Remove unused import: pyinjective.proto.injective.oracle.v1beta1.oracle_pb2

(F401)

pyinjective/proto/injective/exchange/v2/tx_pb2_grpc.py (3)

644-644: ⚠️ Potential issue

Invalid use of add_registered_method_handlers on the server object.

At line 644, the method server.add_registered_method_handlers is called:

server.add_registered_method_handlers('injective.exchange.v2.Msg', rpc_method_handlers)

This method is not part of the standard gRPC server API in Python and will result in an AttributeError. The correct approach is to use add_generic_rpc_handlers, which has already been called on the previous line (line 643). Therefore, this line should be removed.

Apply the following change:

server.add_generic_rpc_handlers((generic_handler,))
-server.add_registered_method_handlers('injective.exchange.v2.Msg', rpc_method_handlers)

653-1595: ⚠️ Potential issue

Remove _registered_method=True from Msg class method definitions.

The static methods in the Msg class (lines 653-1595) include _registered_method=True in the call to grpc.experimental.unary_unary. The grpc.experimental.unary_unary function does not accept this parameter. Including it will cause runtime errors.

Apply the following change to each method:

return grpc.experimental.unary_unary(
    request,
    target,
    '/injective.exchange.v2.Msg/Deposit',
    injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDeposit.SerializeToString,
    injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDepositResponse.FromString,
    options,
    channel_credentials,
    insecure,
    call_credentials,
    compression,
    wait_for_ready,
    timeout,
    metadata,
-   _registered_method=True)
+   )

Repeat this change for all static methods in the Msg class to ensure they function correctly.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    def Deposit(request,
            target,
            options=(),
            channel_credentials=None,
            call_credentials=None,
            insecure=False,
            compression=None,
            wait_for_ready=None,
            timeout=None,
            metadata=None):
        return grpc.experimental.unary_unary(
            request,
            target,
            '/injective.exchange.v2.Msg/Deposit',
            injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDeposit.SerializeToString,
            injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDepositResponse.FromString,
            options,
            channel_credentials,
            insecure,
            call_credentials,
            compression,
            wait_for_ready,
            timeout,
            metadata)

    @staticmethod
    def Withdraw(request,
            target,
            options=(),
            channel_credentials=None,
            call_credentials=None,
            insecure=False,
            compression=None,
            wait_for_ready=None,
            timeout=None,
            metadata=None):
        return grpc.experimental.unary_unary(
            request,
            target,
            '/injective.exchange.v2.Msg/Withdraw',
            injective_dot_exchange_dot_v2_dot_tx__pb2.MsgWithdraw.SerializeToString,
            injective_dot_exchange_dot_v2_dot_tx__pb2.MsgWithdrawResponse.FromString,
            options,
            channel_credentials,
            insecure,
            call_credentials,
            compression,
            wait_for_ready,
            timeout,
            metadata)

18-193: ⚠️ Potential issue

Remove _registered_method=True from gRPC method definitions in MsgStub class.

In the MsgStub class (lines 18-193), each method includes the parameter _registered_method=True in the call to channel.unary_unary. The unary_unary method of the gRPC Channel does not accept a _registered_method parameter. Including it will cause runtime errors.

Apply the following change to each method:

self.Deposit = channel.unary_unary(
    '/injective.exchange.v2.Msg/Deposit',
    request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDeposit.SerializeToString,
    response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDepositResponse.FromString,
-   _registered_method=True)
+   )

Repeat this change for all methods in the MsgStub class to ensure compatibility with the gRPC Python library.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        self.Deposit = channel.unary_unary(
                '/injective.exchange.v2.Msg/Deposit',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDeposit.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDepositResponse.FromString)
        self.Withdraw = channel.unary_unary(
                '/injective.exchange.v2.Msg/Withdraw',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgWithdraw.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgWithdrawResponse.FromString)
        self.InstantSpotMarketLaunch = channel.unary_unary(
                '/injective.exchange.v2.Msg/InstantSpotMarketLaunch',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgInstantSpotMarketLaunch.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgInstantSpotMarketLaunchResponse.FromString)
        self.InstantPerpetualMarketLaunch = channel.unary_unary(
                '/injective.exchange.v2.Msg/InstantPerpetualMarketLaunch',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgInstantPerpetualMarketLaunch.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgInstantPerpetualMarketLaunchResponse.FromString)
        self.InstantExpiryFuturesMarketLaunch = channel.unary_unary(
                '/injective.exchange.v2.Msg/InstantExpiryFuturesMarketLaunch',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgInstantExpiryFuturesMarketLaunch.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgInstantExpiryFuturesMarketLaunchResponse.FromString)
        self.CreateSpotLimitOrder = channel.unary_unary(
                '/injective.exchange.v2.Msg/CreateSpotLimitOrder',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateSpotLimitOrder.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateSpotLimitOrderResponse.FromString)
        self.BatchCreateSpotLimitOrders = channel.unary_unary(
                '/injective.exchange.v2.Msg/BatchCreateSpotLimitOrders',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCreateSpotLimitOrders.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCreateSpotLimitOrdersResponse.FromString)
        self.CreateSpotMarketOrder = channel.unary_unary(
                '/injective.exchange.v2.Msg/CreateSpotMarketOrder',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateSpotMarketOrder.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateSpotMarketOrderResponse.FromString)
        self.CancelSpotOrder = channel.unary_unary(
                '/injective.exchange.v2.Msg/CancelSpotOrder',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCancelSpotOrder.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCancelSpotOrderResponse.FromString)
        self.BatchCancelSpotOrders = channel.unary_unary(
                '/injective.exchange.v2.Msg/BatchCancelSpotOrders',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCancelSpotOrders.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCancelSpotOrdersResponse.FromString)
        self.BatchUpdateOrders = channel.unary_unary(
                '/injective.exchange.v2.Msg/BatchUpdateOrders',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchUpdateOrders.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchUpdateOrdersResponse.FromString)
        self.PrivilegedExecuteContract = channel.unary_unary(
                '/injective.exchange.v2.Msg/PrivilegedExecuteContract',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgPrivilegedExecuteContract.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgPrivilegedExecuteContractResponse.FromString)
        self.CreateDerivativeLimitOrder = channel.unary_unary(
                '/injective.exchange.v2.Msg/CreateDerivativeLimitOrder',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateDerivativeLimitOrder.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateDerivativeLimitOrderResponse.FromString)
        self.BatchCreateDerivativeLimitOrders = channel.unary_unary(
                '/injective.exchange.v2.Msg/BatchCreateDerivativeLimitOrders',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCreateDerivativeLimitOrders.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCreateDerivativeLimitOrdersResponse.FromString)
        self.CreateDerivativeMarketOrder = channel.unary_unary(
                '/injective.exchange.v2.Msg/CreateDerivativeMarketOrder',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateDerivativeMarketOrder.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateDerivativeMarketOrderResponse.FromString)
        self.CancelDerivativeOrder = channel.unary_unary(
                '/injective.exchange.v2.Msg/CancelDerivativeOrder',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCancelDerivativeOrder.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCancelDerivativeOrderResponse.FromString)
        self.BatchCancelDerivativeOrders = channel.unary_unary(
                '/injective.exchange.v2.Msg/BatchCancelDerivativeOrders',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCancelDerivativeOrders.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCancelDerivativeOrdersResponse.FromString)
        self.InstantBinaryOptionsMarketLaunch = channel.unary_unary(
                '/injective.exchange.v2.Msg/InstantBinaryOptionsMarketLaunch',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgInstantBinaryOptionsMarketLaunch.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgInstantBinaryOptionsMarketLaunchResponse.FromString)
        self.CreateBinaryOptionsLimitOrder = channel.unary_unary(
                '/injective.exchange.v2.Msg/CreateBinaryOptionsLimitOrder',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateBinaryOptionsLimitOrder.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateBinaryOptionsLimitOrderResponse.FromString)
        self.CreateBinaryOptionsMarketOrder = channel.unary_unary(
                '/injective.exchange.v2.Msg/CreateBinaryOptionsMarketOrder',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateBinaryOptionsMarketOrder.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCreateBinaryOptionsMarketOrderResponse.FromString)
        self.CancelBinaryOptionsOrder = channel.unary_unary(
                '/injective.exchange.v2.Msg/CancelBinaryOptionsOrder',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCancelBinaryOptionsOrder.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgCancelBinaryOptionsOrderResponse.FromString)
        self.BatchCancelBinaryOptionsOrders = channel.unary_unary(
                '/injective.exchange.v2.Msg/BatchCancelBinaryOptionsOrders',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCancelBinaryOptionsOrders.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgBatchCancelBinaryOptionsOrdersResponse.FromString)
        self.SubaccountTransfer = channel.unary_unary(
                '/injective.exchange.v2.Msg/SubaccountTransfer',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgSubaccountTransfer.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgSubaccountTransferResponse.FromString)
        self.ExternalTransfer = channel.unary_unary(
                '/injective.exchange.v2.Msg/ExternalTransfer',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgExternalTransfer.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgExternalTransferResponse.FromString)
        self.LiquidatePosition = channel.unary_unary(
                '/injective.exchange.v2.Msg/LiquidatePosition',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgLiquidatePosition.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgLiquidatePositionResponse.FromString)
        self.EmergencySettleMarket = channel.unary_unary(
                '/injective.exchange.v2.Msg/EmergencySettleMarket',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgEmergencySettleMarket.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgEmergencySettleMarketResponse.FromString)
        self.IncreasePositionMargin = channel.unary_unary(
                '/injective.exchange.v2.Msg/IncreasePositionMargin',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgIncreasePositionMargin.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgIncreasePositionMarginResponse.FromString)
        self.DecreasePositionMargin = channel.unary_unary(
                '/injective.exchange.v2.Msg/DecreasePositionMargin',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDecreasePositionMargin.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgDecreasePositionMarginResponse.FromString)
        self.RewardsOptOut = channel.unary_unary(
                '/injective.exchange.v2.Msg/RewardsOptOut',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgRewardsOptOut.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgRewardsOptOutResponse.FromString)
        self.AdminUpdateBinaryOptionsMarket = channel.unary_unary(
                '/injective.exchange.v2.Msg/AdminUpdateBinaryOptionsMarket',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgAdminUpdateBinaryOptionsMarket.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgAdminUpdateBinaryOptionsMarketResponse.FromString)
        self.UpdateParams = channel.unary_unary(
                '/injective.exchange.v2.Msg/UpdateParams',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgUpdateParams.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgUpdateParamsResponse.FromString)
        self.UpdateSpotMarket = channel.unary_unary(
                '/injective.exchange.v2.Msg/UpdateSpotMarket',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgUpdateSpotMarket.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgUpdateSpotMarketResponse.FromString)
        self.UpdateDerivativeMarket = channel.unary_unary(
                '/injective.exchange.v2.Msg/UpdateDerivativeMarket',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgUpdateDerivativeMarket.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgUpdateDerivativeMarketResponse.FromString)
        self.AuthorizeStakeGrants = channel.unary_unary(
                '/injective.exchange.v2.Msg/AuthorizeStakeGrants',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgAuthorizeStakeGrants.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgAuthorizeStakeGrantsResponse.FromString)
        self.ActivateStakeGrant = channel.unary_unary(
                '/injective.exchange.v2.Msg/ActivateStakeGrant',
                request_serializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgActivateStakeGrant.SerializeToString,
                response_deserializer=injective_dot_exchange_dot_v2_dot_tx__pb2.MsgActivateStakeGrantResponse.FromString)
pyinjective/proto/injective/exchange/v1beta1/query_pb2.py (1)

22-22: ⚠️ Potential issue

Auto-generated code: Modifications should be made in the .proto files

This file is generated by the protocol buffer compiler as indicated by the header comments. Any changes should be made in the corresponding .proto files and then regenerated to reflect here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant