From dcd2b661740abf434edb0090f6dbd298d8398c01 Mon Sep 17 00:00:00 2001 From: jeuryink Date: Tue, 9 Dec 2025 14:22:26 -0500 Subject: [PATCH 1/5] update subaccount_info query --- nado_protocol/engine_client/query.py | 18 +++++++++++++-- nado_protocol/engine_client/types/__init__.py | 1 + nado_protocol/engine_client/types/query.py | 19 +++++++++++++++ sanity/engine_client.py | 23 +++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/nado_protocol/engine_client/query.py b/nado_protocol/engine_client/query.py index 55c238e..7d604e4 100644 --- a/nado_protocol/engine_client/query.py +++ b/nado_protocol/engine_client/query.py @@ -182,7 +182,10 @@ def get_order(self, product_id: int, digest: str) -> OrderData: ) def get_subaccount_info( - self, subaccount: str, txs: Optional[list[QuerySubaccountInfoTx]] = None + self, + subaccount: str, + txs: Optional[list[QuerySubaccountInfoTx]] = None, + pre_state: Optional[bool] = None, ) -> SubaccountInfoData: """ Query the engine for the state of a subaccount, including balances. @@ -193,11 +196,22 @@ def get_subaccount_info( txs (list[QuerySubaccountInfoTx], optional): You can optionally provide a list of txs, to get an estimated view of what the subaccount state would look like if the transactions were applied. + pre_state (bool, optional): When True and txs are provided, returns the subaccount state before the + transactions were applied in the pre_state field. Defaults to False. + Returns: SubaccountInfoData: Information about the specified subaccount. """ + pre_state_str = None + if pre_state is not None: + pre_state_str = str(pre_state).lower() + return ensure_data_type( - self.query(QuerySubaccountInfoParams(subaccount=subaccount, txs=txs)).data, + self.query( + QuerySubaccountInfoParams( + subaccount=subaccount, txs=txs, pre_state=pre_state_str + ) + ).data, SubaccountInfoData, ) diff --git a/nado_protocol/engine_client/types/__init__.py b/nado_protocol/engine_client/types/__init__.py index 77fd199..5c60eb3 100644 --- a/nado_protocol/engine_client/types/__init__.py +++ b/nado_protocol/engine_client/types/__init__.py @@ -60,6 +60,7 @@ class EngineClientOpts(NadoClientOpts): "ContractsData", "NoncesData", "OrderData", + "PreState", "SubaccountInfoData", "SubaccountOpenOrdersData", "MarketLiquidityData", diff --git a/nado_protocol/engine_client/types/query.py b/nado_protocol/engine_client/types/query.py index bea7cb2..339dd4d 100644 --- a/nado_protocol/engine_client/types/query.py +++ b/nado_protocol/engine_client/types/query.py @@ -102,6 +102,13 @@ class QuerySubaccountInfoParams(NadoBaseModel): type = EngineQueryType.SUBACCOUNT_INFO.value subaccount: str txs: Optional[list[QuerySubaccountInfoTx]] + pre_state: Optional[str] + + @validator("pre_state") + def pre_state_to_str(cls, v: Optional[bool]) -> Optional[str]: + if v is None: + return v + return str(v).lower() if isinstance(v, bool) else v class QuerySubaccountOpenOrdersParams(NadoBaseModel): @@ -299,6 +306,17 @@ class OrderData(NadoBaseModel): placed_at: str +class PreState(NadoBaseModel): + """ + Model for subaccount state before simulated transactions were applied. + """ + + healths: list[SubaccountHealth] + health_contributions: list[list[str]] + spot_balances: list[SpotProductBalance] + perp_balances: list[PerpProductBalance] + + class SubaccountInfoData(NadoBaseModel): """ Model for detailed info about a subaccount, including balances. @@ -314,6 +332,7 @@ class SubaccountInfoData(NadoBaseModel): perp_balances: list[PerpProductBalance] spot_products: list[SpotProduct] perp_products: list[PerpProduct] + pre_state: Optional[PreState] def parse_subaccount_balance( self, product_id: int diff --git a/sanity/engine_client.py b/sanity/engine_client.py index 6be0cb8..582af3e 100644 --- a/sanity/engine_client.py +++ b/sanity/engine_client.py @@ -18,7 +18,9 @@ ) from nado_protocol.engine_client.types.query import ( QueryMaxOrderSizeParams, + QuerySubaccountInfoTx, ) +from nado_protocol.engine_client.types.models import ApplyDelta from nado_protocol.utils.bytes32 import ( bytes32_to_hex, str_to_hex, @@ -132,6 +134,27 @@ def run(): subaccount_info = client.get_subaccount_info(sender) print("subaccount info:", subaccount_info.json(indent=2)) + print("querying subaccount info with simulated transaction and pre_state...") + # Simulate applying a delta to a perp product + simulated_tx = ApplyDelta( + apply_delta={ + "product_id": 2, + "subaccount": sender, + "amount_delta": "100000000000000000", + "v_quote_delta": "3033500000000000000000" + } + ) + subaccount_info_with_pre_state = client.get_subaccount_info( + sender, + txs=[simulated_tx], + pre_state=True + ) + print("subaccount info with pre_state:", subaccount_info_with_pre_state.json(indent=2)) + if subaccount_info_with_pre_state.pre_state: + print("pre_state exists:", subaccount_info_with_pre_state.pre_state.json(indent=2)) + else: + print("Warning: pre_state was not returned") + print("querying subaccount open orders...") subaccount_open_orders = client.get_subaccount_open_orders(product_id, sender) print("subaccount open orders:", subaccount_open_orders.json(indent=2)) From cdfcc9caab6eb8774ddddc9838003fe2c96fa8f9 Mon Sep 17 00:00:00 2001 From: jeuryink Date: Tue, 9 Dec 2025 15:05:28 -0500 Subject: [PATCH 2/5] fixes --- nado_protocol/engine_client/query.py | 2 +- nado_protocol/engine_client/types/query.py | 15 +++++++++- sanity/engine_client.py | 33 +++++++++++----------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/nado_protocol/engine_client/query.py b/nado_protocol/engine_client/query.py index 7d604e4..e20b419 100644 --- a/nado_protocol/engine_client/query.py +++ b/nado_protocol/engine_client/query.py @@ -209,7 +209,7 @@ def get_subaccount_info( return ensure_data_type( self.query( QuerySubaccountInfoParams( - subaccount=subaccount, txs=txs, pre_state=pre_state_str + subaccount=subaccount, txns=txs, pre_state=pre_state_str ) ).data, SubaccountInfoData, diff --git a/nado_protocol/engine_client/types/query.py b/nado_protocol/engine_client/types/query.py index 339dd4d..1f42da2 100644 --- a/nado_protocol/engine_client/types/query.py +++ b/nado_protocol/engine_client/types/query.py @@ -101,9 +101,22 @@ class QuerySubaccountInfoParams(NadoBaseModel): type = EngineQueryType.SUBACCOUNT_INFO.value subaccount: str - txs: Optional[list[QuerySubaccountInfoTx]] + txns: Optional[str] pre_state: Optional[str] + @validator("txns", pre=True) + def txns_to_json_str( + cls, v: Optional[list[QuerySubaccountInfoTx]] + ) -> Optional[str]: + if v is None: + return v + if isinstance(v, str): + return v + # Convert list of transactions to JSON string + import json + + return json.dumps([tx.dict() for tx in v]) + @validator("pre_state") def pre_state_to_str(cls, v: Optional[bool]) -> Optional[str]: if v is None: diff --git a/sanity/engine_client.py b/sanity/engine_client.py index 582af3e..ebf76ee 100644 --- a/sanity/engine_client.py +++ b/sanity/engine_client.py @@ -18,9 +18,8 @@ ) from nado_protocol.engine_client.types.query import ( QueryMaxOrderSizeParams, - QuerySubaccountInfoTx, ) -from nado_protocol.engine_client.types.models import ApplyDelta +from nado_protocol.engine_client.types.models import ApplyDelta, ApplyDeltaTx from nado_protocol.utils.bytes32 import ( bytes32_to_hex, str_to_hex, @@ -81,7 +80,7 @@ def run(): pprint(spots_apr) print("querying orderbook for BTC-PERP pair...") - btc_perp_book = client.get_orderbook("BTC-PERP_USDT", 10) + btc_perp_book = client.get_orderbook("BTC-PERP_USDT0", 10) pprint(btc_perp_book) order_price = 100_000 @@ -136,24 +135,26 @@ def run(): print("querying subaccount info with simulated transaction and pre_state...") # Simulate applying a delta to a perp product - simulated_tx = ApplyDelta( - apply_delta={ - "product_id": 2, - "subaccount": sender, - "amount_delta": "100000000000000000", - "v_quote_delta": "3033500000000000000000" - } + simulated_tx = ApplyDeltaTx( + apply_delta=ApplyDelta( + product_id=2, + subaccount=sender, + amount_delta="100000000000000000", + v_quote_delta="3033500000000000000000", + ) ) subaccount_info_with_pre_state = client.get_subaccount_info( - sender, - txs=[simulated_tx], - pre_state=True + sender, txs=[simulated_tx], pre_state=True + ) + print( + "subaccount info with simulation:", + subaccount_info_with_pre_state.json(indent=2), ) - print("subaccount info with pre_state:", subaccount_info_with_pre_state.json(indent=2)) if subaccount_info_with_pre_state.pre_state: - print("pre_state exists:", subaccount_info_with_pre_state.pre_state.json(indent=2)) + print("✓ pre_state returned successfully") + print("pre_state healths:", subaccount_info_with_pre_state.pre_state.healths) else: - print("Warning: pre_state was not returned") + print("✗ Warning: pre_state was not returned") print("querying subaccount open orders...") subaccount_open_orders = client.get_subaccount_open_orders(product_id, sender) From f56558e66ad24f70826c4911887ca321cd30848d Mon Sep 17 00:00:00 2001 From: jeuryink Date: Tue, 9 Dec 2025 15:06:38 -0500 Subject: [PATCH 3/5] cleaunps --- nado_protocol/engine_client/types/query.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nado_protocol/engine_client/types/query.py b/nado_protocol/engine_client/types/query.py index 1f42da2..0d34d79 100644 --- a/nado_protocol/engine_client/types/query.py +++ b/nado_protocol/engine_client/types/query.py @@ -1,3 +1,4 @@ +import json from nado_protocol.utils.enum import StrEnum from typing import Optional, Union from pydantic import validator @@ -113,8 +114,6 @@ def txns_to_json_str( if isinstance(v, str): return v # Convert list of transactions to JSON string - import json - return json.dumps([tx.dict() for tx in v]) @validator("pre_state") From 99600a51dca0a5708b3c8fa9eda785166adc122d Mon Sep 17 00:00:00 2001 From: jeuryink Date: Tue, 9 Dec 2025 15:08:27 -0500 Subject: [PATCH 4/5] bump version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index df25ab7..ad0386e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nado-protocol" -version = "0.2.7" +version = "0.2.8" description = "Nado Protocol SDK" authors = ["Jeury Mejia "] homepage = "https://nado.xyz" From bf88fe09b61a276d068856a9315d2017707227cb Mon Sep 17 00:00:00 2001 From: jeuryink Date: Tue, 9 Dec 2025 15:11:24 -0500 Subject: [PATCH 5/5] fix ci --- nado_protocol/engine_client/query.py | 7 ++++++- nado_protocol/engine_client/types/query.py | 18 ------------------ 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/nado_protocol/engine_client/query.py b/nado_protocol/engine_client/query.py index e20b419..b85f087 100644 --- a/nado_protocol/engine_client/query.py +++ b/nado_protocol/engine_client/query.py @@ -1,3 +1,4 @@ +import json from typing import Optional import requests @@ -202,6 +203,10 @@ def get_subaccount_info( Returns: SubaccountInfoData: Information about the specified subaccount. """ + txns_str = None + if txs is not None: + txns_str = json.dumps([tx.dict() for tx in txs]) + pre_state_str = None if pre_state is not None: pre_state_str = str(pre_state).lower() @@ -209,7 +214,7 @@ def get_subaccount_info( return ensure_data_type( self.query( QuerySubaccountInfoParams( - subaccount=subaccount, txns=txs, pre_state=pre_state_str + subaccount=subaccount, txns=txns_str, pre_state=pre_state_str ) ).data, SubaccountInfoData, diff --git a/nado_protocol/engine_client/types/query.py b/nado_protocol/engine_client/types/query.py index 0d34d79..90e7553 100644 --- a/nado_protocol/engine_client/types/query.py +++ b/nado_protocol/engine_client/types/query.py @@ -1,4 +1,3 @@ -import json from nado_protocol.utils.enum import StrEnum from typing import Optional, Union from pydantic import validator @@ -105,23 +104,6 @@ class QuerySubaccountInfoParams(NadoBaseModel): txns: Optional[str] pre_state: Optional[str] - @validator("txns", pre=True) - def txns_to_json_str( - cls, v: Optional[list[QuerySubaccountInfoTx]] - ) -> Optional[str]: - if v is None: - return v - if isinstance(v, str): - return v - # Convert list of transactions to JSON string - return json.dumps([tx.dict() for tx in v]) - - @validator("pre_state") - def pre_state_to_str(cls, v: Optional[bool]) -> Optional[str]: - if v is None: - return v - return str(v).lower() if isinstance(v, bool) else v - class QuerySubaccountOpenOrdersParams(NadoBaseModel): """