-
Notifications
You must be signed in to change notification settings - Fork 33
[CP-396] Add support for v1.16 #381
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
Conversation
WalkthroughThis update introduces comprehensive support for ERC20 and EVM proto queries and message types within the client, including new asynchronous API wrappers, message composers, and example scripts. The release also adds corresponding unit tests, updates protobuf descriptors, and modifies some test cases to accommodate new fields and features. Minor version and dependency updates are included. Changes
Sequence Diagram(s)sequenceDiagram
participant UserScript as Example Script
participant AsyncClient
participant ChainGrpcERC20Api
participant ChainGrpcEVMApi
participant gRPCServer as gRPC Server
UserScript->>AsyncClient: Call fetch_erc20_all_token_pairs()
AsyncClient->>ChainGrpcERC20Api: fetch_all_token_pairs()
ChainGrpcERC20Api->>gRPCServer: QueryAllTokenPairs (gRPC)
gRPCServer-->>ChainGrpcERC20Api: Response
ChainGrpcERC20Api-->>AsyncClient: Dict result
AsyncClient-->>UserScript: Dict result
UserScript->>AsyncClient: Call fetch_evm_account(address)
AsyncClient->>ChainGrpcEVMApi: fetch_account(address)
ChainGrpcEVMApi->>gRPCServer: QueryAccount (gRPC)
gRPCServer-->>ChainGrpcEVMApi: Response
ChainGrpcEVMApi-->>AsyncClient: Dict result
AsyncClient-->>UserScript: Dict result
Poem
📜 Recent review detailsConfiguration used: .coderabbit.yaml 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms (2)
🔇 Additional comments (7)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Adds support for Injective v1.16 by integrating new ERC20 and EVM gRPC query APIs, updating client registration, and refreshing examples and dependency versions
- Introduce
ChainGrpcERC20ApiandChainGrpcEVMApiwith full set of query methods - Register new APIs in
AsyncClientand add example scripts for all ERC20 & EVM queries - Bump proto versions in
buf.gen.yaml, update indexer branch inMakefile, and document changes inCHANGELOG.md
Reviewed Changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| pyinjective/client/chain/grpc/chain_grpc_evm_api.py | New EVM module query client |
| pyinjective/client/chain/grpc/chain_grpc_erc20_api.py | New ERC20 module query client |
| pyinjective/async_client.py | Registered and exposed ERC20 & EVM APIs in client |
| examples/chain_client/… | Updated examples to use new_using_gas_heuristics and new queries |
| buf.gen.yaml | Bumped Injective proto tags for v1.16 |
| Makefile | Updated indexer branch from v1.16.0-rc2 to v1.16.3 |
| CHANGELOG.md | Documented added ERC20 and EVM support |
Comments suppressed due to low confidence (5)
pyinjective/client/chain/grpc/chain_grpc_evm_api.py:15
- [nitpick] The method name
fetch_paramsis ambiguous in the EVM context; consider renaming it tofetch_evm_paramsfor consistency with other EVM methods and to parallel the ERC20 client naming.
async def fetch_params(self) -> Dict[str, Any]:
buf.gen.yaml:18
- Indentation and dash placement were changed on this line, which may break the YAML list structure. Ensure each
tagentry retains its leading dash and consistent indentation.
- tag: v1.0.1-inj
pyinjective/client/chain/grpc/chain_grpc_erc20_api.py:1
- New ERC20 API methods have been added; verify that corresponding unit tests cover
fetch_erc20_paramsand the other query methods to prevent regressions.
from typing import Any, Callable, Dict
pyinjective/async_client.py:3009
- The ERC20
Paramsquery is implemented inChainGrpcERC20Apibut not exposed inAsyncClient. Consider adding afetch_erc20_paramswrapper to complete the ERC20 API surface.
async def fetch_erc20_all_token_pairs(self) -> Dict[str, Any]:
pyinjective/async_client.py:3022
- While most EVM queries are exposed, the EVM
Paramscall (ChainGrpcEVMApi.fetch_params) lacks anAsyncClientwrapper. Add afetch_evm_paramsmethod for full coverage.
async def fetch_evm_account(self, address: str) -> Dict[str, Any]:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 18
🧹 Nitpick comments (12)
examples/chain_client/evm/query/1_Account.py (1)
12-35: Add error handling for robustness.The example demonstrates the EVM account query functionality correctly, but lacks error handling that would make it more robust:
- Missing environment variable handling: No check if
INJECTIVE_PRIVATE_KEYexists- No network error handling: API calls could fail due to network issues
- Hardcoded address: While acceptable for examples, consider adding a comment explaining the address
Consider adding basic error handling:
async def main() -> None: dotenv.load_dotenv() configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") + + if not configured_private_key: + raise ValueError("INJECTIVE_PRIVATE_KEY environment variable is required") # 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()) + # Example ERC20 contract address on testnet erc20_address = "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d" - result = await client.fetch_evm_account(address=erc20_address) - print(json.dumps(result, indent=2)) + try: + result = await client.fetch_evm_account(address=erc20_address) + print(json.dumps(result, indent=2)) + except Exception as e: + print(f"Error fetching EVM account: {e}")examples/chain_client/evm/query/2_CosmosAccount.py (2)
28-30: Consider making the ERC20 address configurable.The ERC20 address is hardcoded, which limits the example's flexibility for testing with different contracts.
- erc20_address = "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d" + # You can replace this with any ERC20 contract address you want to query + erc20_address = os.getenv("ERC20_ADDRESS", "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d") result = await client.fetch_evm_cosmos_account(address=erc20_address) print(json.dumps(result, indent=2))
33-34: Consider using asyncio.run() for better compatibility.The current approach
asyncio.get_event_loop().run_until_complete()is deprecated in favor ofasyncio.run()in Python 3.7+.if __name__ == "__main__": - asyncio.get_event_loop().run_until_complete(main()) + asyncio.run(main())examples/chain_client/evm/query/4_Balance.py (2)
28-30: Consider making the ERC20 address configurable.Similar to the previous example, the hardcoded ERC20 address reduces flexibility.
- erc20_address = "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d" + # You can replace this with any ERC20 contract address you want to query + erc20_address = os.getenv("ERC20_ADDRESS", "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d") result = await client.fetch_evm_balance(address=erc20_address) print(json.dumps(result, indent=2))
33-34: Consider using asyncio.run() for better compatibility.Same modernization opportunity as the previous example.
if __name__ == "__main__": - asyncio.get_event_loop().run_until_complete(main()) + asyncio.run(main())examples/chain_client/erc20/2_DeleteTokenPair.py (2)
42-48: Consider parameterizing the hardcoded denomination.The USDT denomination is hardcoded, which works for demonstration purposes but could be made more flexible for real-world usage.
Consider adding a comment explaining this is a testnet-specific denomination:
+ # Example USDT denomination on testnet - replace with actual denomination for your use case usdt_denom = "factory/inj10vkkttgxdeqcgeppu20x9qtyvuaxxev8qh0awq/usdt"
55-58: Verify the necessity of duplicate gas price updates.The gas price is updated again after broadcasting, but this pattern may not be necessary for single-transaction examples.
Consider whether this gas price refresh is needed for this example, or add a comment explaining why it's included:
+ # Refresh gas price for potential subsequent transactions gas_price = await client.current_chain_gas_price()examples/chain_client/erc20/1_CreateTokenPair.py (1)
57-60: Gas price update pattern is consistent but may be unnecessary.Same observation as the delete example - the gas price refresh after transaction may not be needed for single-transaction examples.
tests/client/chain/grpc/configurable_evm_query_servicer.py (1)
18-40: Consider adding error handling for empty response queues.The current implementation will raise an
IndexErrorif a test calls a method when the corresponding response deque is empty. This could lead to unclear test failures.Consider adding defensive checks or clearer error messages:
async def Params(self, request: evm_query_pb.QueryParamsRequest, context=None, metadata=None): + if not self.params_responses: + raise RuntimeError("No more Params responses configured for mock servicer") return self.params_responses.pop()Alternatively, you could return a default empty response or make this behavior configurable based on testing needs.
pyinjective/client/chain/grpc/chain_grpc_evm_api.py (1)
10-65: Consider adding docstrings for better API documentation.While the code is well-structured and follows established patterns, consider adding docstrings to public methods to improve API documentation and developer experience.
Example for the
fetch_accountmethod:async def fetch_account(self, address: str) -> Dict[str, Any]: + """ + Fetch EVM account details for the specified address. + + Args: + address: The EVM address to query + + Returns: + Dictionary containing account details + """ request = evm_query_pb.QueryAccountRequest(address=address) response = await self._execute_call(call=self._stub.Account, request=request) return responsepyinjective/async_client.py (2)
3009-3018: Consider adding the missing ERC20 params method.The ERC20 methods are well-implemented and follow the established delegation pattern. However, the underlying
ChainGrpcERC20Apialso provides afetch_erc20_params()method that's not exposed here.Consider adding the missing method for completeness:
async def fetch_erc20_token_pair_by_erc20_address(self, erc20_address: str) -> Dict[str, Any]: return await self.chain_erc20_api.fetch_token_pair_by_erc20_address(erc20_address=erc20_address) +async def fetch_erc20_params(self) -> Dict[str, Any]: + return await self.chain_erc20_api.fetch_erc20_params()
3022-3042: Consider adding the missing EVM params method.The EVM methods are well-implemented and provide comprehensive coverage of EVM functionality. However, the underlying
ChainGrpcEVMApialso provides afetch_params()method that's not exposed here.Consider adding the missing method for completeness:
async def fetch_evm_base_fee(self) -> Dict[str, Any]: return await self.chain_evm_api.fetch_base_fee() +async def fetch_evm_params(self) -> Dict[str, Any]: + return await self.chain_evm_api.fetch_params()
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (30)
CHANGELOG.md(1 hunks)Makefile(1 hunks)buf.gen.yaml(1 hunks)examples/chain_client/erc20/1_CreateTokenPair.py(1 hunks)examples/chain_client/erc20/2_DeleteTokenPair.py(1 hunks)examples/chain_client/erc20/query/1_AllTokenPairs.py(1 hunks)examples/chain_client/erc20/query/2_TokenPairByDenom.py(1 hunks)examples/chain_client/erc20/query/3_TokenPairByERC20Address.py(1 hunks)examples/chain_client/evm/query/1_Account.py(1 hunks)examples/chain_client/evm/query/2_CosmosAccount.py(1 hunks)examples/chain_client/evm/query/3_ValidatorAccount.py(1 hunks)examples/chain_client/evm/query/4_Balance.py(1 hunks)examples/chain_client/evm/query/5_Storage.py(1 hunks)examples/chain_client/evm/query/6_Code.py(1 hunks)examples/chain_client/evm/query/7_BaseFee.py(1 hunks)examples/chain_client/exchange/28_MsgCreateGTBSpotLimitOrder.py(1 hunks)examples/chain_client/exchange/29_MsgCreateGTBDerivativeLimitOrder.py(1 hunks)pyinjective/async_client.py(3 hunks)pyinjective/client/chain/grpc/chain_grpc_erc20_api.py(1 hunks)pyinjective/client/chain/grpc/chain_grpc_evm_api.py(1 hunks)pyinjective/composer.py(2 hunks)pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2.py(2 hunks)pyproject.toml(1 hunks)tests/client/chain/grpc/configurable_erc20_query_servicer.py(1 hunks)tests/client/chain/grpc/configurable_evm_query_servicer.py(1 hunks)tests/client/chain/grpc/test_chain_grpc_erc20_api.py(1 hunks)tests/client/chain/grpc/test_chain_grpc_evm_api.py(1 hunks)tests/client/indexer/grpc/test_indexer_grpc_derivative_api.py(8 hunks)tests/client/indexer/stream_grpc/test_indexer_grpc_derivative_stream.py(4 hunks)tests/test_composer.py(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (8)
examples/chain_client/exchange/28_MsgCreateGTBSpotLimitOrder.py (1)
pyinjective/core/broadcaster.py (1)
MsgBroadcasterWithPk(62-411)
examples/chain_client/evm/query/1_Account.py (4)
pyinjective/wallet.py (4)
PrivateKey(28-103)from_hex(73-76)to_public_key(84-92)to_address(175-181)pyinjective/async_client.py (3)
AsyncClient(74-3293)fetch_account(332-347)fetch_evm_account(3022-3023)pyinjective/core/network.py (1)
testnet(163-215)pyinjective/client/chain/grpc/chain_grpc_evm_api.py (1)
fetch_account(21-25)
examples/chain_client/exchange/29_MsgCreateGTBDerivativeLimitOrder.py (1)
pyinjective/core/broadcaster.py (1)
MsgBroadcasterWithPk(62-411)
tests/client/chain/grpc/configurable_evm_query_servicer.py (2)
tests/client/chain/grpc/configurable_erc20_query_servicer.py (1)
Params(14-15)pyinjective/core/network.py (1)
metadata(20-25)
pyinjective/client/chain/grpc/chain_grpc_evm_api.py (4)
pyinjective/core/network.py (1)
CookieAssistant(11-25)pyinjective/utils/grpc_api_request_assistant.py (2)
GrpcApiRequestAssistant(8-25)execute_call(13-25)pyinjective/client/chain/grpc/chain_grpc_erc20_api.py (1)
_execute_call(39-40)tests/client/chain/grpc/configurable_evm_query_servicer.py (8)
Params(18-19)Account(21-22)CosmosAccount(24-25)ValidatorAccount(27-28)Balance(30-31)Storage(33-34)Code(36-37)BaseFee(39-40)
tests/client/chain/grpc/configurable_erc20_query_servicer.py (1)
tests/client/chain/grpc/configurable_evm_query_servicer.py (1)
Params(18-19)
pyinjective/client/chain/grpc/chain_grpc_erc20_api.py (3)
pyinjective/core/network.py (1)
CookieAssistant(11-25)pyinjective/utils/grpc_api_request_assistant.py (2)
GrpcApiRequestAssistant(8-25)execute_call(13-25)tests/client/chain/grpc/configurable_erc20_query_servicer.py (4)
Params(14-15)AllTokenPairs(17-18)TokenPairByDenom(20-21)TokenPairByERC20Address(23-26)
pyinjective/async_client.py (2)
pyinjective/client/chain/grpc/chain_grpc_erc20_api.py (4)
ChainGrpcERC20Api(10-40)fetch_all_token_pairs(21-25)fetch_token_pair_by_denom(27-31)fetch_token_pair_by_erc20_address(33-37)pyinjective/client/chain/grpc/chain_grpc_evm_api.py (8)
ChainGrpcEVMApi(10-64)fetch_account(21-25)fetch_cosmos_account(27-31)fetch_validator_account(33-37)fetch_balance(39-43)fetch_storage(45-49)fetch_code(51-55)fetch_base_fee(57-61)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: run-tests (3.11, windows-latest)
- GitHub Check: run-tests (3.10, windows-latest)
🔇 Additional comments (48)
buf.gen.yaml (1)
19-21: LGTM! Version updates align with v1.16 support.The dependency version bumps for
cometbftandcosmos-sdkrepositories are appropriate incremental updates that support the new ERC20 and EVM module features being introduced.pyinjective/proto/exchange/injective_derivative_exchange_rpc_pb2.py (2)
17-17: Generated protobuf code updated correctly.The serialized descriptor has been updated to include the new
reduce_margin_ratiofield in theDerivativeMarketInfomessage as mentioned in the AI summary.
30-176: Protobuf descriptor offsets updated appropriately.All the descriptor start/end offsets have been recalculated to accommodate the new field addition. This is the expected behavior when protobuf schemas are regenerated.
pyproject.toml (1)
3-3: Version bump is appropriate for the new features.The increment from
1.11.0-rc1to1.11.0-rc2correctly reflects the addition of ERC20 and EVM support as documented in the changelog.CHANGELOG.md (1)
8-12: Changelog accurately documents the new features.The entries for ERC20 and EVM support are well-formatted and align perfectly with the PR objectives. The documentation of both the core functionality and example additions provides good visibility into the scope of changes.
Makefile (1)
34-34: LGTM! Version update to stable release.The update from
v1.16.0-rc2tov1.16.3moves from a release candidate to a stable version, which is appropriate for adding v1.16 support as mentioned in the PR objectives.examples/chain_client/exchange/28_MsgCreateGTBSpotLimitOrder.py (1)
30-36: LGTM! Valid gas estimation strategy change.The switch from
new_using_simulationtonew_using_gas_heuristicsis a compatible change that uses message-based gas estimation instead of transaction simulation. Both methods accept identical parameters and provide valid fee calculation strategies.examples/chain_client/exchange/29_MsgCreateGTBDerivativeLimitOrder.py (1)
30-36: LGTM! Consistent gas estimation strategy update.This change aligns with the update in
28_MsgCreateGTBSpotLimitOrder.py, providing consistency across exchange examples by standardizing the use of gas heuristics for fee calculation.examples/chain_client/evm/query/1_Account.py (1)
1-35: Example functionality is correct.The script properly demonstrates the new EVM account query capability using the
fetch_evm_accountmethod. The integration with the pyinjective SDK is correct and follows established patterns from other examples.examples/chain_client/erc20/query/3_TokenPairByERC20Address.py (1)
28-28: LGTM! Clear example usage with meaningful address.The hardcoded USDT ERC20 address provides a concrete example that users can understand and test with.
tests/client/indexer/grpc/test_indexer_grpc_derivative_api.py (2)
40-40: LGTM! Consistent addition of lastFundingRate field.The
last_funding_ratefield has been correctly added to both the mockPerpetualMarketFundingobjects and the corresponding expected results across all relevant test methods.Also applies to: 118-118, 149-149, 223-223
53-53: LGTM! Consistent addition of reduceMarginRatio field.The
reduce_margin_ratiofield has been correctly added to both the mockDerivativeMarketInfoobjects and the corresponding expected results across all relevant test methods. This aligns with the protobuf schema updates.Also applies to: 91-91, 162-162, 196-196
examples/chain_client/evm/query/6_Code.py (1)
28-30: LGTM! Clear demonstration of EVM code querying.The example correctly demonstrates how to query EVM contract code using the new async client functionality.
examples/chain_client/erc20/query/2_TokenPairByDenom.py (1)
28-29: LGTM! Clear example with appropriate denomination.The example correctly demonstrates querying ERC20 token pairs by bank denomination using "usdt" as a common and understandable example.
examples/chain_client/evm/query/2_CosmosAccount.py (1)
1-10: LGTM! Clean import structure and good separation of concerns.The imports are well-organized with standard libraries first, followed by external dependencies, and then pyinjective-specific imports.
examples/chain_client/evm/query/4_Balance.py (1)
1-10: LGTM! Consistent import structure.The imports follow the same clean pattern as the previous example.
tests/client/indexer/stream_grpc/test_indexer_grpc_derivative_stream.py (4)
45-45: LGTM! Proper addition of new funding rate field.The
last_funding_ratefield has been correctly added to thePerpetualMarketFundingmock data with a reasonable test value.
58-58: LGTM! Consistent addition of margin ratio field.The
reduce_margin_ratiofield has been properly added to theDerivativeMarketInfomock data.
108-108: LGTM! Expected output updated to match new schema.The expected dictionary correctly includes the new
reduceMarginRatiofield, maintaining consistency with the protobuf schema changes.
135-135: LGTM! Funding rate field properly included in expected output.The expected dictionary correctly includes the new
lastFundingRatefield, ensuring the test validates the complete response structure.pyinjective/composer.py (2)
28-28: LGTM! Clean import for ERC20 protobuf definitions.The import statement correctly brings in both the ERC20 protobuf definitions (
erc20_pb2) and transaction definitions (tx_pb2) from the appropriate module path, following the established naming conventions used throughout the file.
2934-2953: Well-implemented ERC20 token pair management methods.The new ERC20 module methods are cleanly implemented and follow the established patterns in the codebase:
msg_create_token_pair: Properly constructs aTokenPairobject and wraps it in aMsgCreateTokenPairmessagemsg_delete_token_pair: Simple and direct implementation for token pair deletion- Both methods have appropriate type annotations and parameter naming
- The code structure follows the regional organization pattern used throughout the class
The implementation correctly uses the imported protobuf classes and maintains consistency with other message construction methods.
examples/chain_client/erc20/2_DeleteTokenPair.py (1)
1-11: LGTM: Clean import structure and dependencies.The imports are well-organized and follow the established pattern from other example scripts in the codebase.
examples/chain_client/erc20/1_CreateTokenPair.py (1)
42-50: Verify the ERC20 address corresponds to the bank denomination.The script uses hardcoded values for both the bank denomination and ERC20 address. Ensure these represent the same token on different networks.
The USDT bank denomination and ERC20 address should represent the same underlying asset. Please verify that:
factory/inj10vkkttgxdeqcgeppu20x9qtyvuaxxev8qh0awq/usdtcorresponds to USDT on Injective0xdAC17F958D2ee523a2206206994597C13D831ec7is the correct USDT contract address on EthereumConsider adding a comment to clarify this relationship:
+ # USDT token pair: Injective bank denomination and corresponding Ethereum ERC20 address usdt_denom = "factory/inj10vkkttgxdeqcgeppu20x9qtyvuaxxev8qh0awq/usdt" usdt_erc20 = "0xdAC17F958D2ee523a2206206994597C13D831ec7"tests/test_composer.py (2)
2177-2196: LGTM: Well-structured test for create token pair message.The test follows the established pattern and correctly validates the message structure with nested
tokenPairobject containingbankDenomanderc20Addressfields.
2198-2213: LGTM: Consistent test implementation for delete token pair message.The test correctly validates the simpler structure for delete operations, requiring only
senderandbankDenomfields. The implementation is consistent with other composer tests.tests/client/chain/grpc/configurable_evm_query_servicer.py (1)
6-16: LGTM: Well-organized mock servicer structure.The class properly inherits from the gRPC QueryServicer and initializes separate deques for each query type, providing good separation of concerns for testing different scenarios.
tests/client/chain/grpc/configurable_erc20_query_servicer.py (1)
1-27: LGTM! Clean test utility implementation.The configurable servicer follows the established pattern seen in the EVM servicer and provides comprehensive mock support for all ERC20 query methods. The use of deques for pre-configured responses is a solid approach for controlled testing.
tests/client/chain/grpc/test_chain_grpc_evm_api.py (2)
23-108: Excellent comprehensive test coverage for EVM parameters.The test thoroughly covers all chain configuration parameters and validates the complex nested structure transformation from protobuf to dictionary format. This ensures robust testing of the EVM params functionality.
210-223: Good handling of binary data encoding.The test correctly handles binary code data by using base64 encoding in the expected response, which matches how the API should transform binary protobuf fields.
tests/client/chain/grpc/test_chain_grpc_erc20_api.py (2)
21-38: Good test coverage for ERC20 parameters.The test correctly handles the empty params case and validates the response structure transformation.
41-106: Comprehensive token pair testing.The tests provide excellent coverage of all token pair query methods, validating both the request parameters and response data transformation for different query scenarios.
pyinjective/client/chain/grpc/chain_grpc_erc20_api.py (3)
10-13: Well-structured class initialization.The constructor properly initializes the gRPC stub and request assistant, following the established pattern used by other gRPC API classes in the codebase.
15-37: Clean and consistent API method implementations.All four query methods follow a consistent pattern: create request, execute call through the private helper, and return response. This provides good maintainability and follows the DRY principle.
39-40: Good separation of concerns with private helper method.The
_execute_callmethod centralizes the gRPC call execution and delegates to the request assistant, providing consistent error handling and response processing across all API methods.pyinjective/client/chain/grpc/chain_grpc_evm_api.py (11)
1-8: LGTM: Clean and appropriate imports.The imports are well-organized and include all necessary dependencies for the EVM gRPC API implementation.
10-14: LGTM: Consistent constructor implementation.The constructor follows the established pattern from the ERC20 API, properly initializing the gRPC stub and request assistant with dependency injection.
15-20: LGTM: Clean parameter fetching implementation.The method correctly creates a parameterless request and delegates to the helper method.
21-26: LGTM: Proper account fetching with address parameter.The implementation correctly constructs the request with the required address parameter.
27-32: LGTM: Cosmos account query implementation.The method follows the same reliable pattern as other fetch methods.
33-38: LGTM: Validator account query with consensus address.The implementation correctly uses the
cons_addressparameter as expected for validator queries.
39-44: LGTM: Balance query implementation.The method follows the established pattern for address-based queries.
45-50: LGTM: Storage query with optional key parameter.The implementation correctly handles the optional
keyparameter, which will be passed asNoneto the protobuf request when not provided.
51-56: LGTM: Code fetching implementation.The method correctly implements contract code retrieval for the specified address.
57-62: LGTM: Base fee query implementation.The method correctly creates a parameterless request for base fee information.
63-65: LGTM: Consistent helper method implementation.The private
_execute_callmethod follows the exact same pattern as the ERC20 API, ensuring consistency across the codebase.pyinjective/async_client.py (2)
13-14: LGTM! Clean import additions.The new imports for ERC20 and EVM APIs are properly placed and follow the established naming conventions and import structure.
129-136: LGTM! Consistent API initialization.The ERC20 and EVM API instances are initialized following the same pattern as other chain APIs, with proper dependency injection of the gRPC channel and cookie assistant.
| 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()) | ||
|
|
||
| pairs = await client.fetch_erc20_all_token_pairs() | ||
| print(json.dumps(pairs, indent=2)) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.get_event_loop().run_until_complete(main()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling and use modern asyncio pattern.
The script lacks error handling and uses a deprecated asyncio pattern. Consider these improvements:
- Missing error handling: No validation for environment variables or network calls
- Deprecated asyncio usage:
asyncio.get_event_loop().run_until_complete()is deprecated - Security concern: No validation of private key format
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
+
+ if not configured_private_key:
+ raise ValueError("INJECTIVE_PRIVATE_KEY environment variable is required")
# 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())
-
- pairs = await client.fetch_erc20_all_token_pairs()
- print(json.dumps(pairs, indent=2))
+ try:
+ # 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())
+
+ pairs = await client.fetch_erc20_all_token_pairs()
+ print(json.dumps(pairs, indent=2))
+ except Exception as e:
+ print(f"Error: {e}")
+ raise
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.
| 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()) | |
| pairs = await client.fetch_erc20_all_token_pairs() | |
| print(json.dumps(pairs, indent=2)) | |
| if __name__ == "__main__": | |
| asyncio.get_event_loop().run_until_complete(main()) | |
| async def main() -> None: | |
| dotenv.load_dotenv() | |
| configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") | |
| if not configured_private_key: | |
| raise ValueError("INJECTIVE_PRIVATE_KEY environment variable is required") | |
| # select network: local, testnet, mainnet | |
| network = Network.testnet() | |
| # initialize grpc client | |
| client = AsyncClient(network) | |
| try: | |
| # 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()) | |
| pairs = await client.fetch_erc20_all_token_pairs() | |
| print(json.dumps(pairs, indent=2)) | |
| except Exception as e: | |
| print(f"Error: {e}") | |
| raise | |
| if __name__ == "__main__": | |
| asyncio.run(main()) |
🤖 Prompt for AI Agents
In examples/chain_client/erc20/query/1_AllTokenPairs.py around lines 12 to 33,
add error handling to validate the presence and format of the
INJECTIVE_PRIVATE_KEY environment variable before using it, and wrap network
calls in try-except blocks to catch and handle exceptions gracefully. Replace
the deprecated asyncio.get_event_loop().run_until_complete(main()) with the
modern asyncio.run(main()) pattern for running the async main function.
| 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()) | ||
|
|
||
| erc20_address = "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d" | ||
| key = "key" | ||
| result = await client.fetch_evm_storage(address=erc20_address, key=key) | ||
| print(json.dumps(result, indent=2)) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.get_event_loop().run_until_complete(main()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Apply the same error handling improvements as suggested for the ERC20 example.
This script has identical structural issues to the previous example script.
Apply the same error handling and modern asyncio pattern improvements suggested for the ERC20 token pairs example.
🤖 Prompt for AI Agents
In examples/chain_client/evm/query/5_Storage.py around lines 12 to 35, the
script lacks proper error handling and uses an outdated asyncio pattern.
Refactor the main function to include try-except blocks to catch and log
exceptions during execution. Replace
asyncio.get_event_loop().run_until_complete(main()) with the modern
asyncio.run(main()) for better readability and compatibility.
| erc20_address = "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d" | ||
| key = "key" | ||
| result = await client.fetch_evm_storage(address=erc20_address, key=key) | ||
| print(json.dumps(result, indent=2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Make storage query parameters more meaningful and configurable.
The hardcoded ERC20 address and generic "key" parameter should be more meaningful for a practical example.
- erc20_address = "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d"
- key = "key"
+ # Example: Query the balance storage slot for the first account
+ erc20_address = "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d" # Example USDT contract
+ # Storage key for balance mapping: keccak256(abi.encodePacked(address, slot))
+ # For demonstration, using a meaningful storage key
+ key = "0x0000000000000000000000000000000000000000000000000000000000000000" # Total supply slot
result = await client.fetch_evm_storage(address=erc20_address, key=key)📝 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.
| erc20_address = "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d" | |
| key = "key" | |
| result = await client.fetch_evm_storage(address=erc20_address, key=key) | |
| print(json.dumps(result, indent=2)) | |
| # Example: Query the balance storage slot for the first account | |
| erc20_address = "0xDFd5293D8e347dFe59E90eFd55b2956a1343963d" # Example USDT contract | |
| # Storage key for balance mapping: keccak256(abi.encodePacked(address, slot)) | |
| # For demonstration, using a meaningful storage key | |
| key = "0x0000000000000000000000000000000000000000000000000000000000000000" # Total supply slot | |
| result = await client.fetch_evm_storage(address=erc20_address, key=key) | |
| print(json.dumps(result, indent=2)) |
🤖 Prompt for AI Agents
In examples/chain_client/evm/query/5_Storage.py around lines 28 to 31, the ERC20
address and storage key are hardcoded with generic values that lack practical
meaning. Replace the hardcoded ERC20 address with a relevant, well-known
contract address and update the storage key to a meaningful value that
corresponds to an actual storage slot or variable in that contract.
Additionally, make these parameters configurable, for example by accepting them
as function arguments or reading from a configuration, to allow easier reuse and
testing with different contracts and keys.
| 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()) | ||
|
|
||
| result = await client.fetch_evm_base_fee() | ||
| print(json.dumps(result, indent=2)) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.get_event_loop().run_until_complete(main()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Apply consistent error handling and modern asyncio pattern.
This script follows the same pattern as the other examples and should have consistent error handling and use modern asyncio patterns.
Apply the same improvements suggested for the ERC20 token pairs example:
- Add environment variable validation
- Add try-catch error handling for network calls
- Use
asyncio.run(main())instead of the deprecated event loop method
🤖 Prompt for AI Agents
In examples/chain_client/evm/query/7_BaseFee.py from lines 12 to 33, add
validation to check if the environment variable INJECTIVE_PRIVATE_KEY is set and
raise an error or exit if not. Wrap the network calls inside the main async
function with try-except blocks to catch and handle exceptions gracefully.
Replace the deprecated asyncio.get_event_loop().run_until_complete(main()) with
the modern asyncio.run(main()) call in the script entry point for better
compatibility and readability.
| 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()) | ||
|
|
||
| cons_address = "injvalcons1h5u937etuat5hnr2s34yaaalfpkkscl5ndadqm" | ||
| result = await client.fetch_evm_validator_account(cons_address=cons_address) | ||
| print(json.dumps(result, indent=2)) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.get_event_loop().run_until_complete(main()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Apply consistent error handling improvements.
This script needs the same error handling and asyncio improvements as the other example scripts.
Apply the same error handling, environment variable validation, and modern asyncio pattern improvements suggested for the other example scripts.
🤖 Prompt for AI Agents
In examples/chain_client/evm/query/3_ValidatorAccount.py around lines 12 to 34,
the script lacks proper error handling, environment variable validation, and
uses an outdated asyncio pattern. Add validation to check if the environment
variable INJECTIVE_PRIVATE_KEY is set and raise an error or exit gracefully if
not. Wrap the main async logic in a try-except block to catch and log
exceptions. Replace asyncio.get_event_loop().run_until_complete(main()) with the
modern asyncio.run(main()) call for better compatibility and clarity.
| 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()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for missing environment variable.
Same issue as in the Cosmos account example - missing validation for the required environment variable.
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
+
+ if not configured_private_key:
+ raise ValueError("INJECTIVE_PRIVATE_KEY environment variable is required")
# select network: local, testnet, mainnet
network = Network.testnet()📝 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") | |
| # 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()) | |
| async def main() -> None: | |
| dotenv.load_dotenv() | |
| configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY") | |
| if not configured_private_key: | |
| raise ValueError("INJECTIVE_PRIVATE_KEY environment variable is required") | |
| # 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()) |
🤖 Prompt for AI Agents
In examples/chain_client/evm/query/4_Balance.py around lines 12 to 26, the code
does not check if the environment variable INJECTIVE_PRIVATE_KEY is set before
using it, which can cause runtime errors. Add a validation step after loading
the environment variable to verify it is not None or empty, and raise a clear
error or exit gracefully if the variable is missing to prevent further failures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
tests/client/chain/grpc/test_chain_grpc_erc20_api.py (1)
19-106: Comprehensive test coverage with room for optional improvements.The test methods provide excellent coverage of all ERC20 API endpoints and correctly verify the protobuf-to-dictionary transformation. Consider these optional improvements for better maintainability:
Optional refactoring suggestions:
- Extract test data to constants or fixtures:
+# Test constants +TEST_BANK_DENOM = "denom" +TEST_ERC20_ADDRESS = "0xd2C6753F6B1783EF0a3857275e16e79D91b539a3" +@pytest.fixture +def sample_token_pair(): + return erc20_pb.TokenPair( + bank_denom=TEST_BANK_DENOM, + erc20_address=TEST_ERC20_ADDRESS, + )
- Consider adding error case tests:
- Invalid ERC20 address format
- Non-existent denom/address
- Network/gRPC errors
This would improve test robustness and catch edge cases in the API layer.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
tests/client/chain/grpc/test_chain_grpc_erc20_api.py(1 hunks)tests/client/chain/grpc/test_chain_grpc_evm_api.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/client/chain/grpc/test_chain_grpc_evm_api.py
🧰 Additional context used
🧬 Code Graph Analysis (1)
tests/client/chain/grpc/test_chain_grpc_erc20_api.py (6)
pyinjective/client/chain/grpc/chain_grpc_erc20_api.py (5)
ChainGrpcERC20Api(10-40)fetch_erc20_params(15-19)fetch_all_token_pairs(21-25)fetch_token_pair_by_denom(27-31)fetch_token_pair_by_erc20_address(33-37)pyinjective/core/network.py (3)
DisabledCookieAssistant(97-102)Network(105-370)devnet(145-160)tests/client/chain/grpc/configurable_erc20_query_servicer.py (2)
ConfigurableERC20QueryServicer(6-26)Params(14-15)tests/client/chain/grpc/test_chain_grpc_evm_api.py (1)
_api_instance(242-250)tests/client/indexer/grpc/test_indexer_grpc_derivative_api.py (1)
_api_instance(1382-1390)tests/client/indexer/stream_grpc/test_indexer_grpc_derivative_stream.py (1)
_api_instance(863-871)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: run-tests (3.11, windows-latest)
- GitHub Check: run-tests (3.10, windows-latest)
🔇 Additional comments (3)
tests/client/chain/grpc/test_chain_grpc_erc20_api.py (3)
1-11: LGTM! Clean and necessary imports.The import structure is well-organized and includes all the necessary components for testing the ERC20 API functionality.
14-16: LGTM! Simple and effective fixture.The fixture correctly provides the mock servicer instance needed for all tests.
108-116: LGTM! Consistent test setup pattern.The helper method follows the established pattern used across other test files in the codebase, ensuring consistency in test infrastructure setup.
…cuted in Windows machines
Solves CP-396
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests