diff --git a/src/driftpy/accounts/bulk_account_loader.py b/src/driftpy/accounts/bulk_account_loader.py index 8b64414c..1aeae386 100644 --- a/src/driftpy/accounts/bulk_account_loader.py +++ b/src/driftpy/accounts/bulk_account_loader.py @@ -126,10 +126,10 @@ async def load_chunk(self, chunk: List[List[AccountToLoad]]): ] rpc_request = jsonrpcclient.request( "getMultipleAccounts", - params=[ + params=( pubkeys_to_send, {"encoding": "base64", "commitment": self.commitment}, - ], + ), ) rpc_requests.append(rpc_request) @@ -146,6 +146,11 @@ async def load_chunk(self, chunk: List[List[AccountToLoad]]): parsed_resp = jsonrpcclient.parse(resp.json()) + if isinstance(parsed_resp, jsonrpcclient.Error): + raise ValueError(f"Error fetching accounts: {parsed_resp.message}") + if not isinstance(parsed_resp, jsonrpcclient.Ok): + raise ValueError(f"Error fetching accounts - not ok: {parsed_resp}") + for rpc_result, chunk_accounts in zip(parsed_resp, chunk): if isinstance(rpc_result, jsonrpcclient.Error): print(f"Failed to get info about accounts: {rpc_result.message}") diff --git a/src/driftpy/accounts/ws/drift_client.py b/src/driftpy/accounts/ws/drift_client.py index 0543d7e7..fa64d09e 100644 --- a/src/driftpy/accounts/ws/drift_client.py +++ b/src/driftpy/accounts/ws/drift_client.py @@ -13,6 +13,7 @@ from driftpy.accounts.ws.account_subscriber import WebsocketAccountSubscriber from driftpy.addresses import * from driftpy.constants.config import find_all_market_and_oracles +from driftpy.constants.perp_markets import mainnet_perp_market_configs from driftpy.market_map.market_map import MarketMap from driftpy.market_map.market_map_config import MarketMapConfig, WebsocketConfig from driftpy.oracles.oracle_id import get_oracle_id @@ -331,7 +332,19 @@ def get_oracle_price_data_and_slot_for_perp_market( oracle = self.perp_market_oracle_map.get(market_index) oracle_id = self.perp_market_oracle_strings_map.get(market_index) - if not perp_market_account or not oracle: + if not perp_market_account: + if any( + market_index == market.market_index + for market in mainnet_perp_market_configs + ): + raise ValueError( + f"No perp market account found for market index {market_index} but market should exist. This may be an issue with your RPC?" + ) + + if not oracle: + print(f"No oracle found for market index {market_index}") + + if not perp_market_account or not oracle or not oracle_id: return None if perp_market_account.data.amm.oracle != oracle: diff --git a/src/driftpy/constants/config.py b/src/driftpy/constants/config.py index fa0cbde4..3dc6ba58 100644 --- a/src/driftpy/constants/config.py +++ b/src/driftpy/constants/config.py @@ -1,26 +1,24 @@ import asyncio from base64 import b64decode +from dataclasses import dataclass from typing import Literal, Optional, Sequence, Tuple, Union import jsonrpcclient +from anchorpy import Program +from solders.pubkey import Pubkey + from driftpy.accounts.oracle import decode_oracle from driftpy.accounts.types import DataAndSlot, FullOracleWrapper - -from driftpy.constants.spot_markets import ( - devnet_spot_market_configs, - mainnet_spot_market_configs, - SpotMarketConfig, -) from driftpy.constants.perp_markets import ( + PerpMarketConfig, devnet_perp_market_configs, mainnet_perp_market_configs, - PerpMarketConfig, ) -from dataclasses import dataclass -from solders.pubkey import Pubkey - -from anchorpy import Program - +from driftpy.constants.spot_markets import ( + SpotMarketConfig, + devnet_spot_market_configs, + mainnet_spot_market_configs, +) from driftpy.types import ( OracleInfo, PerpMarketAccount, @@ -123,10 +121,10 @@ async def find_all_market_and_oracles( perp_request = jsonrpcclient.request( "getProgramAccounts", - [ + ( str(program.program_id), {"filters": perp_filters, "encoding": "base64", "withContext": True}, - ], + ), ) post = program.provider.connection._provider.session.post( @@ -139,6 +137,12 @@ async def find_all_market_and_oracles( parsed_resp = jsonrpcclient.parse(resp.json()) + if isinstance(parsed_resp, jsonrpcclient.Error): + raise ValueError(f"Error fetching perp markets: {parsed_resp.message}") + + if not isinstance(parsed_resp, jsonrpcclient.Ok): + raise ValueError(f"Error fetching perp markets - not ok: {parsed_resp}") + perp_slot = int(parsed_resp.result["context"]["slot"]) perp_markets: list[PerpMarketAccount] = [ @@ -152,10 +156,10 @@ async def find_all_market_and_oracles( spot_request = jsonrpcclient.request( "getProgramAccounts", - [ + ( str(program.program_id), {"filters": spot_filters, "encoding": "base64", "withContext": True}, - ], + ), ) post = program.provider.connection._provider.session.post( @@ -168,6 +172,11 @@ async def find_all_market_and_oracles( parsed_resp = jsonrpcclient.parse(resp.json()) + if isinstance(parsed_resp, jsonrpcclient.Error): + raise ValueError(f"Error fetching spot markets: {parsed_resp.message}") + if not isinstance(parsed_resp, jsonrpcclient.Ok): + raise ValueError(f"Error fetching spot markets - not ok: {parsed_resp}") + spot_slot = int(parsed_resp.result["context"]["slot"]) spot_markets: list[SpotMarketAccount] = [ diff --git a/src/driftpy/events/fetch_logs.py b/src/driftpy/events/fetch_logs.py index c056096e..406e98d2 100644 --- a/src/driftpy/events/fetch_logs.py +++ b/src/driftpy/events/fetch_logs.py @@ -1,13 +1,13 @@ import asyncio + +import jsonrpcclient from solana.rpc.async_api import AsyncClient from solana.rpc.commitment import Commitment +from solana.transaction import Signature from solders.pubkey import Pubkey from solders.rpc.responses import ( RpcConfirmedTransactionStatusWithSignature, ) -import jsonrpcclient - -from solana.transaction import Signature async def fetch_logs( @@ -63,10 +63,10 @@ async def fetch_transactions( for signature in signatures: rpc_request = jsonrpcclient.request( "getTransaction", - [ + ( str(signature.signature), {"commitment": commitment, "maxSupportedTransactionVersion": 0}, - ], + ), ) rpc_requests.append(rpc_request) @@ -83,6 +83,11 @@ async def fetch_transactions( parsed_resp = jsonrpcclient.parse(resp.json()) + if isinstance(parsed_resp, jsonrpcclient.Error): + raise ValueError(f"Error fetching transactions: {parsed_resp.message}") + if not isinstance(parsed_resp, jsonrpcclient.Ok): + raise ValueError(f"Error fetching transactions - not ok: {parsed_resp}") + response = [] for rpc_result in parsed_resp: if rpc_result.result: diff --git a/src/driftpy/market_map/market_map.py b/src/driftpy/market_map/market_map.py index a4cc3eeb..5fd42514 100644 --- a/src/driftpy/market_map/market_map.py +++ b/src/driftpy/market_map/market_map.py @@ -2,22 +2,21 @@ import base64 import os import pickle - from typing import Dict, Optional, Union -import jsonrpcclient +import jsonrpcclient from solana.rpc.commitment import Confirmed -from driftpy.accounts.types import DataAndSlot +from driftpy.accounts.types import DataAndSlot from driftpy.market_map.market_map_config import MarketMapConfig from driftpy.market_map.websocket_sub import WebsocketSubscription from driftpy.types import ( PerpMarketAccount, PickledData, SpotMarketAccount, - is_variant, compress, decompress, + is_variant, market_type_to_string, ) @@ -112,10 +111,10 @@ async def pre_dump(self) -> dict[str, bytes]: rpc_request = jsonrpcclient.request( "getProgramAccounts", - [ + ( str(self.program.program_id), {"filters": filters, "encoding": "base64", "withContext": True}, - ], + ), ) post = self.connection._provider.session.post( @@ -128,6 +127,11 @@ async def pre_dump(self) -> dict[str, bytes]: parsed_resp = jsonrpcclient.parse(resp.json()) + if isinstance(parsed_resp, jsonrpcclient.Error): + raise ValueError(f"Error fetching market map: {parsed_resp.message}") + if not isinstance(parsed_resp, jsonrpcclient.Ok): + raise ValueError(f"Error fetching market map - not ok: {parsed_resp}") + slot = int(parsed_resp.result["context"]["slot"]) self.latest_slot = slot diff --git a/src/driftpy/priority_fees/priority_fee_subscriber.py b/src/driftpy/priority_fees/priority_fee_subscriber.py index 7d703203..3c780653 100644 --- a/src/driftpy/priority_fees/priority_fee_subscriber.py +++ b/src/driftpy/priority_fees/priority_fee_subscriber.py @@ -1,8 +1,7 @@ import asyncio -import jsonrpcclient - from dataclasses import dataclass +import jsonrpcclient from solana.rpc.async_api import AsyncClient @@ -55,6 +54,12 @@ async def load(self): parsed_resp = jsonrpcclient.parse(resp.json()) + if isinstance(parsed_resp, jsonrpcclient.Error): + raise ValueError(f"Error fetching priority fees: {parsed_resp.message}") + + if not isinstance(parsed_resp, jsonrpcclient.Ok): + raise ValueError(f"Error fetching priority fees - not ok: {parsed_resp}") + result = parsed_resp.result desc_results = sorted(result, key=lambda x: x["slot"], reverse=True)[ diff --git a/src/driftpy/user_map/user_map.py b/src/driftpy/user_map/user_map.py index 7f9f17de..a55bc88d 100644 --- a/src/driftpy/user_map/user_map.py +++ b/src/driftpy/user_map/user_map.py @@ -1,31 +1,24 @@ import asyncio +import base64 import os -import jsonrpcclient import pickle -import base64 - -from typing import Any, Container, Optional, Dict +from typing import Any, Container, Dict, Optional +import jsonrpcclient +from solana.rpc.commitment import Confirmed from solders.pubkey import Pubkey -from solana.rpc.commitment import Confirmed +from driftpy.account_subscription_config import AccountSubscriptionConfig +from driftpy.accounts.types import DataAndSlot +from driftpy.decode.user import decode_user from driftpy.dlob.client_types import DLOBSource - from driftpy.drift_client import DriftClient from driftpy.drift_user import DriftUser -from driftpy.account_subscription_config import AccountSubscriptionConfig - from driftpy.types import OrderRecord, PickledData, UserAccount, compress, decompress - -from driftpy.user_map.user_map_config import UserMapConfig, PollingConfig -from driftpy.user_map.websocket_sub import WebsocketSubscription from driftpy.user_map.polling_sub import PollingSubscription - - from driftpy.user_map.types import UserMapInterface -from driftpy.accounts.types import DataAndSlot - -from driftpy.decode.user import decode_user +from driftpy.user_map.user_map_config import PollingConfig, UserMapConfig +from driftpy.user_map.websocket_sub import WebsocketSubscription class UserMap(UserMapInterface, DLOBSource): @@ -144,10 +137,10 @@ async def sync(self) -> None: rpc_request = jsonrpcclient.request( "getProgramAccounts", - [ + ( str(self.drift_client.program_id), {"filters": filters, "encoding": "base64", "withContext": True}, - ], + ), ) post = self.drift_client.connection._provider.session.post( @@ -160,6 +153,12 @@ async def sync(self) -> None: parsed_resp = jsonrpcclient.parse(resp.json()) + if isinstance(parsed_resp, jsonrpcclient.Error): + raise ValueError(f"Error fetching user map: {parsed_resp.message}") + + if not isinstance(parsed_resp, jsonrpcclient.Ok): + raise ValueError(f"Error fetching user map - not ok: {parsed_resp}") + slot = int(parsed_resp.result["context"]["slot"]) self.latest_slot = slot diff --git a/src/driftpy/user_map/userstats_map.py b/src/driftpy/user_map/userstats_map.py index 970ea9f5..c2f040ad 100644 --- a/src/driftpy/user_map/userstats_map.py +++ b/src/driftpy/user_map/userstats_map.py @@ -5,30 +5,32 @@ import traceback from typing import Dict, Optional +import jsonrpcclient +from solders.pubkey import Pubkey + from driftpy.accounts.types import DataAndSlot from driftpy.addresses import get_user_stats_account_public_key from driftpy.decode.user_stat import decode_user_stat -from driftpy.drift_user_stats import DriftUserStats -from driftpy.drift_user_stats import UserStatsSubscriptionConfig +from driftpy.drift_user_stats import DriftUserStats, UserStatsSubscriptionConfig from driftpy.events.types import WrappedEvent from driftpy.memcmp import get_user_stats_filter -from driftpy.types import compress -from driftpy.types import decompress -from driftpy.types import DepositRecord -from driftpy.types import FundingPaymentRecord -from driftpy.types import InsuranceFundStakeRecord -from driftpy.types import LiquidationRecord -from driftpy.types import LPRecord -from driftpy.types import NewUserRecord -from driftpy.types import OrderActionRecord -from driftpy.types import OrderRecord -from driftpy.types import PickledData -from driftpy.types import SettlePnlRecord -from driftpy.types import UserStatsAccount +from driftpy.types import ( + DepositRecord, + FundingPaymentRecord, + InsuranceFundStakeRecord, + LiquidationRecord, + LPRecord, + NewUserRecord, + OrderActionRecord, + OrderRecord, + PickledData, + SettlePnlRecord, + UserStatsAccount, + compress, + decompress, +) from driftpy.user_map.user_map import UserMap from driftpy.user_map.user_map_config import UserStatsMapConfig -import jsonrpcclient -from solders.pubkey import Pubkey class UserStatsMap: @@ -64,10 +66,10 @@ async def sync(self): rpc_request = jsonrpcclient.request( "getProgramAccounts", - [ + ( str(self.drift_client.program_id), {"filters": filters, "encoding": "base64", "withContext": True}, - ], + ), ) post = self.connection._provider.session.post( @@ -79,6 +81,15 @@ async def sync(self): resp = await asyncio.wait_for(post, timeout=120) parsed_resp = jsonrpcclient.parse(resp.json()) + if isinstance(parsed_resp, jsonrpcclient.Error): + raise ValueError( + f"Error fetching user stats: {parsed_resp.message}" + ) + + if not isinstance(parsed_resp, jsonrpcclient.Ok): + raise ValueError( + f"Error fetching user stats - not ok: {parsed_resp}" + ) slot = int(parsed_resp.result["context"]["slot"])