From 6d574540d2c204de303dd375525b4441315e5a4e Mon Sep 17 00:00:00 2001 From: dizpers Date: Wed, 1 Apr 2026 20:05:45 +0700 Subject: [PATCH 1/7] Add correct contracts for testnet and mainnet; Generate ABI for testnet and mainnet --- src/decibel/abi/generate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decibel/abi/generate.py b/src/decibel/abi/generate.py index 32357e6..36c7821 100644 --- a/src/decibel/abi/generate.py +++ b/src/decibel/abi/generate.py @@ -177,7 +177,7 @@ def cli() -> None: "networks", nargs="*", default=["testnet"], - help="Networks to fetch ABIs for (testnet, testnet, mainnet, all). Default: testnet", + help="Networks to fetch ABIs for (testnet, mainnet, all). Default: testnet", ) args = parser.parse_args() From 00c7f7eaaf3b0f2ce97314b496ed5d5978e70413 Mon Sep 17 00:00:00 2001 From: dizpers Date: Wed, 1 Apr 2026 20:06:25 +0700 Subject: [PATCH 2/7] Extend .gitignore with .idea/ (PyCharm) --- .gitignore | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.gitignore b/.gitignore index b9fdcd0..1fefca8 100644 --- a/.gitignore +++ b/.gitignore @@ -168,11 +168,6 @@ dmypy.json # Cython debug symbols cython_debug/ -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. This file currently -# ignores the entire .idea folder as a more nuclear option (not recommended). .idea/ # Abstra From 2cb4541d8fcfda1834764169645e627bf94fa61c Mon Sep 17 00:00:00 2001 From: dizpers Date: Wed, 1 Apr 2026 23:40:42 +0700 Subject: [PATCH 3/7] Add mainnet to registry --- src/decibel/abi/_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decibel/abi/_registry.py b/src/decibel/abi/_registry.py index 47ccb9c..28638ee 100644 --- a/src/decibel/abi/_registry.py +++ b/src/decibel/abi/_registry.py @@ -34,7 +34,7 @@ def _load_abi_json(filename: str) -> ABIData: def get_abi_data(chain_id: int | None) -> ABIData: if chain_id == CHAIN_ID_MAINNET: return _load_abi_json("mainnet.json") - if chain_id == CHAIN_ID_NETNA: + elif chain_id == CHAIN_ID_NETNA: return _load_abi_json("netna.json") elif chain_id == CHAIN_ID_TESTNET: return _load_abi_json("testnet.json") From 241b9f0376c2908444a956fcd8e62d2620638426 Mon Sep 17 00:00:00 2001 From: dizpers Date: Wed, 1 Apr 2026 22:28:30 +0700 Subject: [PATCH 4/7] Add the support for custom timeouts (txn confirmation) --- src/decibel/_base.py | 15 +++-- src/decibel/_constants.py | 5 ++ src/decibel/write/__init__.py | 123 +++++++++++++++++++++++++++++----- 3 files changed, 122 insertions(+), 21 deletions(-) diff --git a/src/decibel/_base.py b/src/decibel/_base.py index de64cff..fdd7526 100644 --- a/src/decibel/_base.py +++ b/src/decibel/_base.py @@ -18,6 +18,7 @@ from aptos_sdk.ed25519 import Signature as Ed25519Signature from aptos_sdk.transactions import FeePayerRawTransaction, SignedTransaction +from ._constants import DEFAULT_TX_TIMEOUT_SECS from ._fee_pay import ( PendingTransactionResponse, submit_fee_paid_transaction, @@ -183,6 +184,7 @@ async def _send_tx( self, payload: InputEntryFunctionData, account_override: Account | None = None, + timeout_secs: float | None = None, # Uses DEFAULT_TX_TIMEOUT_SECS if None ) -> dict[str, Any]: signer = account_override if account_override is not None else self._account sender = signer.address() @@ -218,7 +220,7 @@ async def _send_tx( pending_tx = await self.submit_tx(transaction, sender_authenticator) - return await self._wait_for_transaction(pending_tx.hash) + return await self._wait_for_transaction(pending_tx.hash, timeout_secs=timeout_secs) def _sign_transaction( self, @@ -313,9 +315,11 @@ async def _submit_direct( async def _wait_for_transaction( self, tx_hash: str, - timeout_secs: float = 30.0, + timeout_secs: float | None = None, # Uses DEFAULT_TX_TIMEOUT_SECS if None poll_interval_secs: float = 1.0, ) -> dict[str, Any]: + if timeout_secs is None: + timeout_secs = DEFAULT_TX_TIMEOUT_SECS url = f"{self._config.fullnode_url}/transactions/by_hash/{tx_hash}" headers = self._build_node_headers() start_time = time.time() @@ -508,6 +512,7 @@ def _send_tx( self, payload: InputEntryFunctionData, account_override: Account | None = None, + timeout_secs: float | None = None, # Uses DEFAULT_TX_TIMEOUT_SECS if None ) -> dict[str, Any]: signer = account_override if account_override is not None else self._account sender = signer.address() @@ -543,7 +548,7 @@ def _send_tx( pending_tx = self.submit_tx(transaction, sender_authenticator) - return self._wait_for_transaction(pending_tx.hash) + return self._wait_for_transaction(pending_tx.hash, timeout_secs=timeout_secs) def _sign_transaction( self, @@ -645,9 +650,11 @@ def make_request(client: httpx.Client) -> PendingTransactionResponse: def _wait_for_transaction( self, tx_hash: str, - timeout_secs: float = 30.0, + timeout_secs: float | None = None, # Uses DEFAULT_TX_TIMEOUT_SECS if None poll_interval_secs: float = 1.0, ) -> dict[str, Any]: + if timeout_secs is None: + timeout_secs = DEFAULT_TX_TIMEOUT_SECS url = f"{self._config.fullnode_url}/transactions/by_hash/{tx_hash}" headers = self._build_node_headers() start_time = time.time() diff --git a/src/decibel/_constants.py b/src/decibel/_constants.py index da35fbd..70984c2 100644 --- a/src/decibel/_constants.py +++ b/src/decibel/_constants.py @@ -11,6 +11,7 @@ "Deployment", "DecibelConfig", "DEFAULT_COMPAT_VERSION", + "DEFAULT_TX_TIMEOUT_SECS", "MAINNET_CONFIG", "NETNA_CONFIG", "TESTNET_CONFIG", @@ -22,6 +23,10 @@ "get_perp_engine_global_address", ] +# Configurable timeout for transaction confirmation +# Default is 30 seconds +DEFAULT_TX_TIMEOUT_SECS = 30.0 + class Network(str, Enum): MAINNET = "mainnet" diff --git a/src/decibel/write/__init__.py b/src/decibel/write/__init__.py index ad9712a..ef96103 100644 --- a/src/decibel/write/__init__.py +++ b/src/decibel/write/__init__.py @@ -147,7 +147,12 @@ async def create_subaccount(self) -> dict[str, Any]: ) ) - async def deposit(self, amount: int, subaccount_addr: str | None = None) -> dict[str, Any]: + async def deposit( + self, + amount: int, + subaccount_addr: str | None = None, + timeout_secs: float | None = None, + ) -> dict[str, Any]: pkg = self._config.deployment.package usdc = self._config.deployment.usdc @@ -157,12 +162,18 @@ async def _send(addr: str) -> dict[str, Any]: function=f"{pkg}::dex_accounts_entry::deposit_to_subaccount_at", type_arguments=[], function_arguments=[addr, usdc, amount], - ) + ), + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) - async def withdraw(self, amount: int, subaccount_addr: str | None = None) -> dict[str, Any]: + async def withdraw( + self, + amount: int, + subaccount_addr: str | None = None, + timeout_secs: float | None = None, + ) -> dict[str, Any]: pkg = self._config.deployment.package usdc = self._config.deployment.usdc @@ -172,7 +183,8 @@ async def _send(addr: str) -> dict[str, Any]: function=f"{pkg}::dex_accounts_entry::withdraw_from_subaccount", type_arguments=[], function_arguments=[addr, usdc, amount], - ) + ), + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -184,6 +196,7 @@ async def configure_user_settings_for_market( subaccount_addr: str, is_cross: bool, user_leverage: int, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -193,7 +206,8 @@ async def _send(addr: str) -> dict[str, Any]: function=f"{pkg}::dex_accounts_entry::configure_user_settings_for_market", type_arguments=[], function_arguments=[addr, market_addr, is_cross, user_leverage], - ) + ), + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -218,6 +232,7 @@ async def place_order( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, + timeout_secs: float | None = None, ) -> PlaceOrderResult: try: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -275,6 +290,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) tx_response = await self.send_subaccount_tx(_send, subaccount_addr) @@ -298,6 +314,7 @@ async def trigger_matching( *, market_addr: str, max_work_unit: int, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package tx_response = await self._send_tx( @@ -305,7 +322,8 @@ async def trigger_matching( function=f"{pkg}::public_apis::process_perp_market_pending_requests", type_arguments=[], function_arguments=[market_addr, max_work_unit], - ) + ), + timeout_secs=timeout_secs, ) return { "success": True, @@ -326,6 +344,7 @@ async def place_twap_order( builder_fees: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> PlaceOrderResult: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -349,6 +368,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) tx_response = await self.send_subaccount_tx(_send, subaccount_addr) @@ -369,6 +389,7 @@ async def cancel_order( market_addr: str | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: if market_name is not None: resolved_market_addr = get_market_addr( @@ -389,6 +410,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, int(order_id), resolved_market_addr], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -406,6 +428,7 @@ async def place_bulk_orders( builder_fee: int | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> PlaceBulkOrdersResult: try: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -429,6 +452,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) tx_response = await self.send_subaccount_tx(_send, subaccount_addr) @@ -446,6 +470,7 @@ async def cancel_bulk_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -458,6 +483,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -469,6 +495,7 @@ async def cancel_client_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -481,6 +508,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, client_order_id, market_addr], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -491,6 +519,7 @@ async def delegate_trading_to_for_subaccount( subaccount_addr: str, account_to_delegate_to: str, expiration_timestamp_secs: int | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -504,7 +533,8 @@ async def _send(addr: str) -> dict[str, Any]: account_to_delegate_to, expiration_timestamp_secs, ], - ) + ), + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -514,6 +544,7 @@ async def revoke_delegation( *, account_to_revoke: str, subaccount_addr: str | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -523,7 +554,8 @@ async def _send(addr: str) -> dict[str, Any]: function=f"{pkg}::dex_accounts_entry::revoke_delegation", type_arguments=[], function_arguments=[addr, account_to_revoke], - ) + ), + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -541,6 +573,7 @@ async def place_tp_sl_order_for_position( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: final_tp_trigger = ( _round_to_tick_size(tp_trigger_price, tick_size) @@ -584,6 +617,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -598,6 +632,7 @@ async def update_tp_order_for_position( tp_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -616,6 +651,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -630,6 +666,7 @@ async def update_sl_order_for_position( sl_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -648,6 +685,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -659,6 +697,7 @@ async def cancel_tp_sl_order_for_position( order_id: int | str, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -670,6 +709,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, int(order_id)], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -681,6 +721,7 @@ async def cancel_twap_order( order_id: int | str, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -692,6 +733,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, int(order_id)], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -719,6 +761,7 @@ async def deactivate_subaccount( subaccount_addr: str, revoke_all_delegations: bool = True, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -730,6 +773,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, revoke_all_delegations], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -770,6 +814,7 @@ async def create_vault( *, account_override: Account | None = None, subaccount_addr: str | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -799,6 +844,7 @@ async def _send(_: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -1095,7 +1141,12 @@ def create_subaccount(self) -> dict[str, Any]: ) ) - def deposit(self, amount: int, subaccount_addr: str | None = None) -> dict[str, Any]: + def deposit( + self, + amount: int, + subaccount_addr: str | None = None, + timeout_secs: float | None = None, + ) -> dict[str, Any]: pkg = self._config.deployment.package usdc = self._config.deployment.usdc @@ -1105,12 +1156,18 @@ def _send(addr: str) -> dict[str, Any]: function=f"{pkg}::dex_accounts_entry::deposit_to_subaccount_at", type_arguments=[], function_arguments=[addr, usdc, amount], - ) + ), + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) - def withdraw(self, amount: int, subaccount_addr: str | None = None) -> dict[str, Any]: + def withdraw( + self, + amount: int, + subaccount_addr: str | None = None, + timeout_secs: float | None = None, + ) -> dict[str, Any]: pkg = self._config.deployment.package usdc = self._config.deployment.usdc @@ -1120,7 +1177,8 @@ def _send(addr: str) -> dict[str, Any]: function=f"{pkg}::dex_accounts_entry::withdraw_from_subaccount", type_arguments=[], function_arguments=[addr, usdc, amount], - ) + ), + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1132,6 +1190,7 @@ def configure_user_settings_for_market( subaccount_addr: str, is_cross: bool, user_leverage: int, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1141,7 +1200,8 @@ def _send(addr: str) -> dict[str, Any]: function=f"{pkg}::dex_accounts_entry::configure_user_settings_for_market", type_arguments=[], function_arguments=[addr, market_addr, is_cross, user_leverage], - ) + ), + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1166,6 +1226,7 @@ def place_order( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, + timeout_secs: float | None = None, ) -> PlaceOrderResult: try: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -1223,6 +1284,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) tx_response = self.send_subaccount_tx(_send, subaccount_addr) @@ -1246,6 +1308,7 @@ def trigger_matching( *, market_addr: str, max_work_unit: int, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package tx_response = self._send_tx( @@ -1253,7 +1316,8 @@ def trigger_matching( function=f"{pkg}::public_apis::process_perp_market_pending_requests", type_arguments=[], function_arguments=[market_addr, max_work_unit], - ) + ), + timeout_secs=timeout_secs, ) return { "success": True, @@ -1274,6 +1338,7 @@ def place_twap_order( builder_fees: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> PlaceOrderResult: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -1297,6 +1362,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) tx_response = self.send_subaccount_tx(_send, subaccount_addr) @@ -1317,6 +1383,7 @@ def cancel_order( market_addr: str | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: if market_name is not None: resolved_market_addr = get_market_addr( @@ -1337,6 +1404,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, int(order_id), resolved_market_addr], ), account_override, + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1354,6 +1422,7 @@ def place_bulk_orders( builder_fee: int | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> PlaceBulkOrdersResult: try: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -1377,6 +1446,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) tx_response = self.send_subaccount_tx(_send, subaccount_addr) @@ -1394,6 +1464,7 @@ def cancel_bulk_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -1406,6 +1477,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr], ), account_override, + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1417,6 +1489,7 @@ def cancel_client_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -1429,6 +1502,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, client_order_id, market_addr], ), account_override, + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1439,6 +1513,7 @@ def delegate_trading_to_for_subaccount( subaccount_addr: str, account_to_delegate_to: str, expiration_timestamp_secs: int | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1452,7 +1527,8 @@ def _send(addr: str) -> dict[str, Any]: account_to_delegate_to, expiration_timestamp_secs, ], - ) + ), + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1462,6 +1538,7 @@ def revoke_delegation( *, account_to_revoke: str, subaccount_addr: str | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1471,7 +1548,8 @@ def _send(addr: str) -> dict[str, Any]: function=f"{pkg}::dex_accounts_entry::revoke_delegation", type_arguments=[], function_arguments=[addr, account_to_revoke], - ) + ), + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1489,6 +1567,7 @@ def place_tp_sl_order_for_position( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: final_tp_trigger = ( _round_to_tick_size(tp_trigger_price, tick_size) @@ -1532,6 +1611,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1546,6 +1626,7 @@ def update_tp_order_for_position( tp_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1564,6 +1645,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1578,6 +1660,7 @@ def update_sl_order_for_position( sl_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1596,6 +1679,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1607,6 +1691,7 @@ def cancel_tp_sl_order_for_position( order_id: int | str, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1618,6 +1703,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, int(order_id)], ), account_override, + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1629,6 +1715,7 @@ def cancel_twap_order( market_addr: str, subaccount_addr: str | None = None, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1640,6 +1727,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, order_id], ), account_override, + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1667,6 +1755,7 @@ def deactivate_subaccount( subaccount_addr: str, revoke_all_delegations: bool = True, account_override: Account | None = None, + timeout_secs: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1677,7 +1766,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, revoke_all_delegations], ), - account_override, + timeout_secs=timeout_secs, ) return self.send_subaccount_tx(_send, subaccount_addr) From 59636736b83b96407405b75801de883ba90018fa Mon Sep 17 00:00:00 2001 From: dizpers Date: Fri, 3 Apr 2026 18:48:26 +0700 Subject: [PATCH 5/7] Custom excceptions / timeouts for txn submit / confirm --- src/decibel/__init__.py | 8 ++ src/decibel/_base.py | 120 ++++++++++++++++++++------- src/decibel/_constants.py | 9 ++- src/decibel/_exceptions.py | 51 ++++++++++++ src/decibel/_fee_pay.py | 32 ++++++-- src/decibel/write/__init__.py | 148 +++++++++++++++++----------------- 6 files changed, 257 insertions(+), 111 deletions(-) create mode 100644 src/decibel/_exceptions.py diff --git a/src/decibel/__init__.py b/src/decibel/__init__.py index 4fa5637..83374ec 100644 --- a/src/decibel/__init__.py +++ b/src/decibel/__init__.py @@ -2,8 +2,14 @@ BaseSDKOptions, BaseSDKOptionsSync, ) +from decibel._exceptions import ( + TxnConfirmError, + TxnSubmitError, +) from decibel._constants import ( DEFAULT_COMPAT_VERSION, + DEFAULT_TXN_CONFIRM_TIMEOUT, + DEFAULT_TXN_SUBMIT_TIMEOUT, DOCKER_CONFIG, LOCAL_CONFIG, MAINNET_CONFIG, @@ -143,6 +149,8 @@ "DecibelAdminDex", "DecibelAdminDexSync", "ABIErrorEntry", + "TxnConfirmError", + "TxnSubmitError", "ABISummary", "AbiRegistry", "amount_to_chain_units", diff --git a/src/decibel/_base.py b/src/decibel/_base.py index fdd7526..1df28dc 100644 --- a/src/decibel/_base.py +++ b/src/decibel/_base.py @@ -7,6 +7,8 @@ import httpx from aptos_sdk.async_client import RestClient + +from ._exceptions import TxnConfirmError, TxnSubmitError from aptos_sdk.authenticator import ( AccountAuthenticator, Authenticator, @@ -18,7 +20,7 @@ from aptos_sdk.ed25519 import Signature as Ed25519Signature from aptos_sdk.transactions import FeePayerRawTransaction, SignedTransaction -from ._constants import DEFAULT_TX_TIMEOUT_SECS +from ._constants import DEFAULT_TXN_CONFIRM_TIMEOUT, DEFAULT_TXN_SUBMIT_TIMEOUT from ._fee_pay import ( PendingTransactionResponse, submit_fee_paid_transaction, @@ -171,20 +173,27 @@ async def submit_tx( self, transaction: SimpleTransaction, sender_authenticator: AccountAuthenticator, + *, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: if self._no_fee_payer: - return await self._submit_direct(transaction, sender_authenticator) + return await self._submit_direct( + transaction, sender_authenticator, txn_submit_timeout + ) return await submit_fee_paid_transaction( self._config, transaction, sender_authenticator, + txn_submit_timeout=txn_submit_timeout, ) async def _send_tx( self, payload: InputEntryFunctionData, account_override: Account | None = None, - timeout_secs: float | None = None, # Uses DEFAULT_TX_TIMEOUT_SECS if None + *, + txn_submit_timeout: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: signer = account_override if account_override is not None else self._account sender = signer.address() @@ -218,9 +227,35 @@ async def _send_tx( sender_authenticator = self._sign_transaction(signer, transaction) - pending_tx = await self.submit_tx(transaction, sender_authenticator) + if txn_submit_timeout is None: + txn_submit_timeout = DEFAULT_TXN_SUBMIT_TIMEOUT + + try: + pending_tx = await self.submit_tx( + transaction, sender_authenticator, txn_submit_timeout=txn_submit_timeout + ) + except httpx.ConnectTimeout as e: + raise TxnSubmitError( + f"Failed to submit transaction: connection timeout to {self._config.fullnode_url}", + original_exception=e, + ) + except httpx.ConnectError as e: + raise TxnSubmitError( + f"Failed to submit transaction: connection error - {e}", + original_exception=e, + ) + except httpx.HTTPStatusError as e: + raise TxnSubmitError( + f"Failed to submit transaction: HTTP {e.response.status_code}", + original_exception=e, + ) + except Exception as e: + raise TxnSubmitError( + f"Failed to submit transaction: {e}", + original_exception=e, + ) - return await self._wait_for_transaction(pending_tx.hash, timeout_secs=timeout_secs) + return await self._wait_for_transaction(pending_tx.hash, txn_confirm_timeout=txn_confirm_timeout) def _sign_transaction( self, @@ -285,6 +320,7 @@ async def _submit_direct( self, transaction: SimpleTransaction, sender_authenticator: AccountAuthenticator, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: url = f"{self._config.fullnode_url}/transactions" headers = self._build_node_headers() @@ -293,7 +329,7 @@ async def _submit_direct( bcs_bytes = self._serialize_signed_transaction(transaction, sender_authenticator) async with httpx.AsyncClient() as client: - response = await client.post(url, content=bcs_bytes, headers=headers) + response = await client.post(url, content=bcs_bytes, headers=headers, timeout=txn_submit_timeout) if not response.is_success: raise ValueError( @@ -315,11 +351,11 @@ async def _submit_direct( async def _wait_for_transaction( self, tx_hash: str, - timeout_secs: float | None = None, # Uses DEFAULT_TX_TIMEOUT_SECS if None + txn_confirm_timeout: float | None = None, # Uses DEFAULT_TXN_CONFIRM_TIMEOUT if None poll_interval_secs: float = 1.0, ) -> dict[str, Any]: - if timeout_secs is None: - timeout_secs = DEFAULT_TX_TIMEOUT_SECS + if txn_confirm_timeout is None: + txn_confirm_timeout = DEFAULT_TXN_CONFIRM_TIMEOUT url = f"{self._config.fullnode_url}/transactions/by_hash/{tx_hash}" headers = self._build_node_headers() start_time = time.time() @@ -337,12 +373,10 @@ async def _wait_for_transaction( return data elif data.get("success") is False: vm_status = data.get("vm_status", "Unknown error") - raise ValueError(f"Transaction failed: {vm_status}") + raise TxnConfirmError(tx_hash, f"failed: {vm_status}") - if time.time() - start_time > timeout_secs: - raise TimeoutError( - f"Transaction {tx_hash} did not complete within {timeout_secs}s" - ) + if time.time() - start_time > txn_confirm_timeout: + raise TxnConfirmError(tx_hash, f"did not confirm within {txn_confirm_timeout}s") await self._async_sleep(poll_interval_secs) @@ -499,20 +533,27 @@ def submit_tx( self, transaction: SimpleTransaction, sender_authenticator: AccountAuthenticator, + *, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: if self._no_fee_payer: - return self._submit_direct(transaction, sender_authenticator) + return self._submit_direct( + transaction, sender_authenticator, txn_submit_timeout + ) return submit_fee_paid_transaction_sync( self._config, transaction, sender_authenticator, + txn_submit_timeout=txn_submit_timeout, ) def _send_tx( self, payload: InputEntryFunctionData, account_override: Account | None = None, - timeout_secs: float | None = None, # Uses DEFAULT_TX_TIMEOUT_SECS if None + *, + txn_submit_timeout: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: signer = account_override if account_override is not None else self._account sender = signer.address() @@ -546,9 +587,35 @@ def _send_tx( sender_authenticator = self._sign_transaction(signer, transaction) - pending_tx = self.submit_tx(transaction, sender_authenticator) + if txn_submit_timeout is None: + txn_submit_timeout = DEFAULT_TXN_SUBMIT_TIMEOUT + + try: + pending_tx = self.submit_tx( + transaction, sender_authenticator, txn_submit_timeout=txn_submit_timeout + ) + except httpx.ConnectTimeout as e: + raise TxnSubmitError( + f"Failed to submit transaction: connection timeout to {self._config.fullnode_url}", + original_exception=e, + ) + except httpx.ConnectError as e: + raise TxnSubmitError( + f"Failed to submit transaction: connection error - {e}", + original_exception=e, + ) + except httpx.HTTPStatusError as e: + raise TxnSubmitError( + f"Failed to submit transaction: HTTP {e.response.status_code}", + original_exception=e, + ) + except Exception as e: + raise TxnSubmitError( + f"Failed to submit transaction: {e}", + original_exception=e, + ) - return self._wait_for_transaction(pending_tx.hash, timeout_secs=timeout_secs) + return self._wait_for_transaction(pending_tx.hash, txn_confirm_timeout=txn_confirm_timeout) def _sign_transaction( self, @@ -619,6 +686,7 @@ def _submit_direct( self, transaction: SimpleTransaction, sender_authenticator: AccountAuthenticator, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: url = f"{self._config.fullnode_url}/transactions" headers = self._build_node_headers() @@ -626,7 +694,7 @@ def _submit_direct( bcs_bytes = self._serialize_signed_transaction(transaction, sender_authenticator) def make_request(client: httpx.Client) -> PendingTransactionResponse: - response = client.post(url, content=bcs_bytes, headers=headers) + response = client.post(url, content=bcs_bytes, headers=headers, timeout=txn_submit_timeout) if not response.is_success: raise ValueError( f"Transaction submission failed: {response.status_code} - {response.text}" @@ -650,11 +718,11 @@ def make_request(client: httpx.Client) -> PendingTransactionResponse: def _wait_for_transaction( self, tx_hash: str, - timeout_secs: float | None = None, # Uses DEFAULT_TX_TIMEOUT_SECS if None + txn_confirm_timeout: float | None = None, # Uses DEFAULT_TXN_CONFIRM_TIMEOUT if None poll_interval_secs: float = 1.0, ) -> dict[str, Any]: - if timeout_secs is None: - timeout_secs = DEFAULT_TX_TIMEOUT_SECS + if txn_confirm_timeout is None: + txn_confirm_timeout = DEFAULT_TXN_CONFIRM_TIMEOUT url = f"{self._config.fullnode_url}/transactions/by_hash/{tx_hash}" headers = self._build_node_headers() start_time = time.time() @@ -671,11 +739,9 @@ def poll_loop(client: httpx.Client) -> dict[str, Any]: return data elif data.get("success") is False: vm_status = data.get("vm_status", "Unknown error") - raise ValueError(f"Transaction failed: {vm_status}") - if time.time() - start_time > timeout_secs: - raise TimeoutError( - f"Transaction {tx_hash} did not complete within {timeout_secs}s" - ) + raise TxnConfirmError(tx_hash, f"failed: {vm_status}") + if time.time() - start_time > txn_confirm_timeout: + raise TxnConfirmError(tx_hash, f"did not confirm within {txn_confirm_timeout}s") time.sleep(poll_interval_secs) if self._http_client is not None: diff --git a/src/decibel/_constants.py b/src/decibel/_constants.py index 70984c2..ad7fa15 100644 --- a/src/decibel/_constants.py +++ b/src/decibel/_constants.py @@ -11,7 +11,8 @@ "Deployment", "DecibelConfig", "DEFAULT_COMPAT_VERSION", - "DEFAULT_TX_TIMEOUT_SECS", + "DEFAULT_TXN_CONFIRM_TIMEOUT", + "DEFAULT_TXN_SUBMIT_TIMEOUT", "MAINNET_CONFIG", "NETNA_CONFIG", "TESTNET_CONFIG", @@ -25,7 +26,11 @@ # Configurable timeout for transaction confirmation # Default is 30 seconds -DEFAULT_TX_TIMEOUT_SECS = 30.0 +DEFAULT_TXN_CONFIRM_TIMEOUT = 30.0 + +# Configurable timeout for transaction submission +# Default is 10 seconds (should be shorter than confirmation timeout) +DEFAULT_TXN_SUBMIT_TIMEOUT = 10.0 class Network(str, Enum): diff --git a/src/decibel/_exceptions.py b/src/decibel/_exceptions.py new file mode 100644 index 0000000..d8d92bc --- /dev/null +++ b/src/decibel/_exceptions.py @@ -0,0 +1,51 @@ +"""Custom exceptions for the Decibel SDK. + +These exceptions help callers distinguish between failures that are safe to retry +(submission errors) vs failures that require checking transaction status first +(confirmation errors). +""" + +from __future__ import annotations + + +class TxnConfirmError(Exception): + """ + Transaction was submitted but confirmation failed. + + Causes: + - Transaction did not confirm within timeout (still pending or dropped) + - Transaction executed but reverted (VM error) + - Transaction failed during execution + + CRITICAL: The transaction MAY be on-chain. Check tx_hash status before retrying + to avoid duplicate transactions. + + Attributes: + tx_hash: The transaction hash that was submitted + message: Description of what went wrong + """ + + def __init__(self, tx_hash: str, message: str) -> None: + self.tx_hash = tx_hash + super().__init__(f"Transaction {tx_hash}: {message}") + + +class TxnSubmitError(Exception): + """ + Transaction submission failed before reaching the blockchain. + + Causes: + - Network connectivity issues (timeout, connection refused) + - RPC endpoint unavailable + - HTTP errors (5xx, 429 rate limit) + - Serialization errors + + SAFE TO RETRY: The transaction was never submitted to the blockchain. + + Attributes: + original_exception: The underlying exception that caused the failure + """ + + def __init__(self, message: str, original_exception: Exception | None = None) -> None: + self.original_exception = original_exception + super().__init__(message) diff --git a/src/decibel/_fee_pay.py b/src/decibel/_fee_pay.py index 9d6a3fe..e864842 100644 --- a/src/decibel/_fee_pay.py +++ b/src/decibel/_fee_pay.py @@ -34,6 +34,7 @@ async def submit_fee_paid_transaction( sender_authenticator: AccountAuthenticator, *, client: httpx.AsyncClient | None = None, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: if config.gas_station_api_key: return await _submit_via_gas_station_api( @@ -41,6 +42,7 @@ async def submit_fee_paid_transaction( transaction, sender_authenticator, client=client, + txn_submit_timeout=txn_submit_timeout, ) if config.gas_station_url: @@ -49,6 +51,7 @@ async def submit_fee_paid_transaction( transaction, sender_authenticator, client=client, + txn_submit_timeout=txn_submit_timeout, ) raise ValueError("Either gas_station_api_key or gas_station_url must be provided") @@ -60,6 +63,7 @@ def submit_fee_paid_transaction_sync( sender_authenticator: AccountAuthenticator, *, client: httpx.Client | None = None, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: if config.gas_station_api_key: return _submit_via_gas_station_api_sync( @@ -67,6 +71,7 @@ def submit_fee_paid_transaction_sync( transaction, sender_authenticator, client=client, + txn_submit_timeout=txn_submit_timeout, ) if config.gas_station_url: @@ -75,6 +80,7 @@ def submit_fee_paid_transaction_sync( transaction, sender_authenticator, client=client, + txn_submit_timeout=txn_submit_timeout, ) raise ValueError("Either gas_station_api_key or gas_station_url must be provided") @@ -86,6 +92,7 @@ async def _submit_via_gas_station_api( sender_authenticator: AccountAuthenticator, *, client: httpx.AsyncClient | None = None, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: base_url = _get_default_gas_station_url(config) url = f"{base_url}/api/transaction/signAndSubmit" @@ -115,11 +122,14 @@ async def _submit_via_gas_station_api( "Authorization": f"Bearer {config.gas_station_api_key}", } + async def _do_submit(c: httpx.AsyncClient) -> httpx.Response: + return await c.post(url, json=body, headers=headers, timeout=txn_submit_timeout) + if client is not None: - response = await client.post(url, json=body, headers=headers) + response = await _do_submit(client) else: async with httpx.AsyncClient() as temp_client: - response = await temp_client.post(url, json=body, headers=headers) + response = await _do_submit(temp_client) if not response.is_success: raise ValueError(f"Gas station API error: {response.status_code} - {response.text}") @@ -143,6 +153,7 @@ def _submit_via_gas_station_api_sync( sender_authenticator: AccountAuthenticator, *, client: httpx.Client | None = None, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: base_url = _get_default_gas_station_url(config) url = f"{base_url}/api/transaction/signAndSubmit" @@ -172,11 +183,14 @@ def _submit_via_gas_station_api_sync( "Authorization": f"Bearer {config.gas_station_api_key}", } + def _do_submit(c: httpx.Client) -> httpx.Response: + return c.post(url, json=body, headers=headers, timeout=txn_submit_timeout) + if client is not None: - response = client.post(url, json=body, headers=headers) + response = _do_submit(client) else: with httpx.Client() as temp_client: - response = temp_client.post(url, json=body, headers=headers) + response = _do_submit(temp_client) if not response.is_success: raise ValueError(f"Gas station API error: {response.status_code} - {response.text}") @@ -200,6 +214,7 @@ async def _submit_via_legacy_fee_payer( sender_authenticator: AccountAuthenticator, *, client: httpx.AsyncClient | None = None, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: url = f"{config.gas_station_url}/transactions" @@ -219,10 +234,10 @@ async def _submit_via_legacy_fee_payer( headers = {"Content-Type": "application/json"} if client is not None: - response = await client.post(url, json=body, headers=headers) + response = await client.post(url, json=body, headers=headers, timeout=txn_submit_timeout) else: async with httpx.AsyncClient() as temp_client: - response = await temp_client.post(url, json=body, headers=headers) + response = await temp_client.post(url, json=body, headers=headers, timeout=txn_submit_timeout) # TODO: Improve error handling if not response.is_success: @@ -245,6 +260,7 @@ def _submit_via_legacy_fee_payer_sync( sender_authenticator: AccountAuthenticator, *, client: httpx.Client | None = None, + txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: url = f"{config.gas_station_url}/transactions" @@ -264,10 +280,10 @@ def _submit_via_legacy_fee_payer_sync( headers = {"Content-Type": "application/json"} if client is not None: - response = client.post(url, json=body, headers=headers) + response = client.post(url, json=body, headers=headers, timeout=txn_submit_timeout) else: with httpx.Client() as temp_client: - response = temp_client.post(url, json=body, headers=headers) + response = temp_client.post(url, json=body, headers=headers, timeout=txn_submit_timeout) # TODO: Improve error handling if not response.is_success: diff --git a/src/decibel/write/__init__.py b/src/decibel/write/__init__.py index ef96103..4fee0ad 100644 --- a/src/decibel/write/__init__.py +++ b/src/decibel/write/__init__.py @@ -151,7 +151,7 @@ async def deposit( self, amount: int, subaccount_addr: str | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package usdc = self._config.deployment.usdc @@ -163,7 +163,7 @@ async def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, usdc, amount], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -172,7 +172,7 @@ async def withdraw( self, amount: int, subaccount_addr: str | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package usdc = self._config.deployment.usdc @@ -184,7 +184,7 @@ async def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, usdc, amount], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -196,7 +196,7 @@ async def configure_user_settings_for_market( subaccount_addr: str, is_cross: bool, user_leverage: int, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -207,7 +207,7 @@ async def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, market_addr, is_cross, user_leverage], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -232,7 +232,7 @@ async def place_order( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> PlaceOrderResult: try: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -290,7 +290,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) tx_response = await self.send_subaccount_tx(_send, subaccount_addr) @@ -314,7 +314,7 @@ async def trigger_matching( *, market_addr: str, max_work_unit: int, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package tx_response = await self._send_tx( @@ -323,7 +323,7 @@ async def trigger_matching( type_arguments=[], function_arguments=[market_addr, max_work_unit], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return { "success": True, @@ -344,7 +344,7 @@ async def place_twap_order( builder_fees: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> PlaceOrderResult: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -368,7 +368,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) tx_response = await self.send_subaccount_tx(_send, subaccount_addr) @@ -389,7 +389,7 @@ async def cancel_order( market_addr: str | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: if market_name is not None: resolved_market_addr = get_market_addr( @@ -410,7 +410,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, int(order_id), resolved_market_addr], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -428,7 +428,7 @@ async def place_bulk_orders( builder_fee: int | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> PlaceBulkOrdersResult: try: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -452,7 +452,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) tx_response = await self.send_subaccount_tx(_send, subaccount_addr) @@ -470,7 +470,7 @@ async def cancel_bulk_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -483,7 +483,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -495,7 +495,7 @@ async def cancel_client_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -508,7 +508,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, client_order_id, market_addr], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -519,7 +519,7 @@ async def delegate_trading_to_for_subaccount( subaccount_addr: str, account_to_delegate_to: str, expiration_timestamp_secs: int | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -534,7 +534,7 @@ async def _send(addr: str) -> dict[str, Any]: expiration_timestamp_secs, ], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -544,7 +544,7 @@ async def revoke_delegation( *, account_to_revoke: str, subaccount_addr: str | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -555,7 +555,7 @@ async def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, account_to_revoke], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -573,7 +573,7 @@ async def place_tp_sl_order_for_position( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: final_tp_trigger = ( _round_to_tick_size(tp_trigger_price, tick_size) @@ -617,7 +617,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -632,7 +632,7 @@ async def update_tp_order_for_position( tp_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -651,7 +651,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -666,7 +666,7 @@ async def update_sl_order_for_position( sl_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -685,7 +685,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -697,7 +697,7 @@ async def cancel_tp_sl_order_for_position( order_id: int | str, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -709,7 +709,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, int(order_id)], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -721,7 +721,7 @@ async def cancel_twap_order( order_id: int | str, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -733,7 +733,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, int(order_id)], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -761,7 +761,7 @@ async def deactivate_subaccount( subaccount_addr: str, revoke_all_delegations: bool = True, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -773,7 +773,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, revoke_all_delegations], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -814,7 +814,7 @@ async def create_vault( *, account_override: Account | None = None, subaccount_addr: str | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -844,7 +844,7 @@ async def _send(_: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return await self.send_subaccount_tx(_send, subaccount_addr) @@ -1145,7 +1145,7 @@ def deposit( self, amount: int, subaccount_addr: str | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package usdc = self._config.deployment.usdc @@ -1157,7 +1157,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, usdc, amount], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1166,7 +1166,7 @@ def withdraw( self, amount: int, subaccount_addr: str | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package usdc = self._config.deployment.usdc @@ -1178,7 +1178,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, usdc, amount], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1190,7 +1190,7 @@ def configure_user_settings_for_market( subaccount_addr: str, is_cross: bool, user_leverage: int, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1201,7 +1201,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, market_addr, is_cross, user_leverage], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1226,7 +1226,7 @@ def place_order( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> PlaceOrderResult: try: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -1284,7 +1284,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) tx_response = self.send_subaccount_tx(_send, subaccount_addr) @@ -1308,7 +1308,7 @@ def trigger_matching( *, market_addr: str, max_work_unit: int, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package tx_response = self._send_tx( @@ -1317,7 +1317,7 @@ def trigger_matching( type_arguments=[], function_arguments=[market_addr, max_work_unit], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return { "success": True, @@ -1338,7 +1338,7 @@ def place_twap_order( builder_fees: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> PlaceOrderResult: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -1362,7 +1362,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) tx_response = self.send_subaccount_tx(_send, subaccount_addr) @@ -1383,7 +1383,7 @@ def cancel_order( market_addr: str | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: if market_name is not None: resolved_market_addr = get_market_addr( @@ -1404,7 +1404,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, int(order_id), resolved_market_addr], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1422,7 +1422,7 @@ def place_bulk_orders( builder_fee: int | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> PlaceBulkOrdersResult: try: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -1446,7 +1446,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) tx_response = self.send_subaccount_tx(_send, subaccount_addr) @@ -1464,7 +1464,7 @@ def cancel_bulk_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -1477,7 +1477,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1489,7 +1489,7 @@ def cancel_client_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) pkg = self._config.deployment.package @@ -1502,7 +1502,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, client_order_id, market_addr], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1513,7 +1513,7 @@ def delegate_trading_to_for_subaccount( subaccount_addr: str, account_to_delegate_to: str, expiration_timestamp_secs: int | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1528,7 +1528,7 @@ def _send(addr: str) -> dict[str, Any]: expiration_timestamp_secs, ], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1538,7 +1538,7 @@ def revoke_delegation( *, account_to_revoke: str, subaccount_addr: str | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1549,7 +1549,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, account_to_revoke], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1567,7 +1567,7 @@ def place_tp_sl_order_for_position( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: final_tp_trigger = ( _round_to_tick_size(tp_trigger_price, tick_size) @@ -1611,7 +1611,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1626,7 +1626,7 @@ def update_tp_order_for_position( tp_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1645,7 +1645,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1660,7 +1660,7 @@ def update_sl_order_for_position( sl_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1679,7 +1679,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1691,7 +1691,7 @@ def cancel_tp_sl_order_for_position( order_id: int | str, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1703,7 +1703,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, int(order_id)], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1715,7 +1715,7 @@ def cancel_twap_order( market_addr: str, subaccount_addr: str | None = None, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1727,7 +1727,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, order_id], ), account_override, - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) @@ -1755,7 +1755,7 @@ def deactivate_subaccount( subaccount_addr: str, revoke_all_delegations: bool = True, account_override: Account | None = None, - timeout_secs: float | None = None, + txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1766,7 +1766,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, revoke_all_delegations], ), - timeout_secs=timeout_secs, + txn_confirm_timeout=txn_confirm_timeout, ) return self.send_subaccount_tx(_send, subaccount_addr) From 1307a06d639e355b1d12099ed457e96d8431fe2e Mon Sep 17 00:00:00 2001 From: dizpers Date: Sun, 5 Apr 2026 15:32:48 +0700 Subject: [PATCH 6/7] Separate configurable timeouts for txn submit / confirm --- src/decibel/write/__init__.py | 77 ++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/decibel/write/__init__.py b/src/decibel/write/__init__.py index 4fee0ad..931a238 100644 --- a/src/decibel/write/__init__.py +++ b/src/decibel/write/__init__.py @@ -151,6 +151,7 @@ async def deposit( self, amount: int, subaccount_addr: str | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -163,6 +164,7 @@ async def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, usdc, amount], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -172,6 +174,7 @@ async def withdraw( self, amount: int, subaccount_addr: str | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -184,6 +187,7 @@ async def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, usdc, amount], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -196,6 +200,7 @@ async def configure_user_settings_for_market( subaccount_addr: str, is_cross: bool, user_leverage: int, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -207,6 +212,7 @@ async def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, market_addr, is_cross, user_leverage], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -232,6 +238,7 @@ async def place_order( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> PlaceOrderResult: try: @@ -290,6 +297,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -314,6 +322,7 @@ async def trigger_matching( *, market_addr: str, max_work_unit: int, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -323,6 +332,7 @@ async def trigger_matching( type_arguments=[], function_arguments=[market_addr, max_work_unit], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) return { @@ -344,6 +354,7 @@ async def place_twap_order( builder_fees: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> PlaceOrderResult: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -368,6 +379,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -389,6 +401,7 @@ async def cancel_order( market_addr: str | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: if market_name is not None: @@ -410,6 +423,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, int(order_id), resolved_market_addr], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -428,6 +442,7 @@ async def place_bulk_orders( builder_fee: int | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> PlaceBulkOrdersResult: try: @@ -452,6 +467,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -470,6 +486,7 @@ async def cancel_bulk_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -483,6 +500,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -495,6 +513,7 @@ async def cancel_client_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -508,6 +527,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, client_order_id, market_addr], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -519,6 +539,7 @@ async def delegate_trading_to_for_subaccount( subaccount_addr: str, account_to_delegate_to: str, expiration_timestamp_secs: int | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -534,6 +555,7 @@ async def _send(addr: str) -> dict[str, Any]: expiration_timestamp_secs, ], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -544,6 +566,7 @@ async def revoke_delegation( *, account_to_revoke: str, subaccount_addr: str | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -555,6 +578,7 @@ async def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, account_to_revoke], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -573,6 +597,7 @@ async def place_tp_sl_order_for_position( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: final_tp_trigger = ( @@ -617,6 +642,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -632,6 +658,7 @@ async def update_tp_order_for_position( tp_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -651,6 +678,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -666,6 +694,7 @@ async def update_sl_order_for_position( sl_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -685,6 +714,7 @@ async def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -697,6 +727,7 @@ async def cancel_tp_sl_order_for_position( order_id: int | str, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -709,6 +740,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, int(order_id)], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -721,6 +753,7 @@ async def cancel_twap_order( order_id: int | str, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -733,6 +766,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, int(order_id)], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -761,6 +795,7 @@ async def deactivate_subaccount( subaccount_addr: str, revoke_all_delegations: bool = True, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -773,6 +808,7 @@ async def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, revoke_all_delegations], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -814,6 +850,7 @@ async def create_vault( *, account_override: Account | None = None, subaccount_addr: str | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -844,6 +881,7 @@ async def _send(_: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1145,6 +1183,7 @@ def deposit( self, amount: int, subaccount_addr: str | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1157,6 +1196,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, usdc, amount], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1166,6 +1206,7 @@ def withdraw( self, amount: int, subaccount_addr: str | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1178,6 +1219,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, usdc, amount], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1190,6 +1232,7 @@ def configure_user_settings_for_market( subaccount_addr: str, is_cross: bool, user_leverage: int, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1201,6 +1244,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, market_addr, is_cross, user_leverage], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1226,6 +1270,7 @@ def place_order( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> PlaceOrderResult: try: @@ -1284,6 +1329,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1308,6 +1354,7 @@ def trigger_matching( *, market_addr: str, max_work_unit: int, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1317,6 +1364,7 @@ def trigger_matching( type_arguments=[], function_arguments=[market_addr, max_work_unit], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) return { @@ -1338,6 +1386,7 @@ def place_twap_order( builder_fees: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> PlaceOrderResult: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -1362,6 +1411,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1383,6 +1433,7 @@ def cancel_order( market_addr: str | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: if market_name is not None: @@ -1404,6 +1455,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, int(order_id), resolved_market_addr], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1422,6 +1474,7 @@ def place_bulk_orders( builder_fee: int | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> PlaceBulkOrdersResult: try: @@ -1446,6 +1499,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1464,6 +1518,7 @@ def cancel_bulk_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -1477,6 +1532,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1489,6 +1545,7 @@ def cancel_client_order( market_name: str, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: market_addr = get_market_addr(market_name, self._config.deployment.perp_engine_global) @@ -1502,6 +1559,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, client_order_id, market_addr], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1513,6 +1571,7 @@ def delegate_trading_to_for_subaccount( subaccount_addr: str, account_to_delegate_to: str, expiration_timestamp_secs: int | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1528,6 +1587,7 @@ def _send(addr: str) -> dict[str, Any]: expiration_timestamp_secs, ], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1538,6 +1598,7 @@ def revoke_delegation( *, account_to_revoke: str, subaccount_addr: str | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1549,6 +1610,7 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, account_to_revoke], ), + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1567,6 +1629,7 @@ def place_tp_sl_order_for_position( subaccount_addr: str | None = None, account_override: Account | None = None, tick_size: int | float | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: final_tp_trigger = ( @@ -1611,6 +1674,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1626,6 +1690,7 @@ def update_tp_order_for_position( tp_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1645,6 +1710,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1660,6 +1726,7 @@ def update_sl_order_for_position( sl_size: float | None = None, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1679,6 +1746,7 @@ def _send(addr: str) -> dict[str, Any]: ], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1691,6 +1759,7 @@ def cancel_tp_sl_order_for_position( order_id: int | str, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1703,6 +1772,7 @@ def _send(addr: str) -> dict[str, Any]: function_arguments=[addr, market_addr, int(order_id)], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1715,6 +1785,7 @@ def cancel_twap_order( market_addr: str, subaccount_addr: str | None = None, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1724,9 +1795,10 @@ def _send(addr: str) -> dict[str, Any]: InputEntryFunctionData( function=f"{pkg}::dex_accounts_entry::cancel_twap_orders_to_subaccount", type_arguments=[], - function_arguments=[addr, market_addr, order_id], + function_arguments=[addr, market_addr, int(order_id)], ), account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) @@ -1755,6 +1827,7 @@ def deactivate_subaccount( subaccount_addr: str, revoke_all_delegations: bool = True, account_override: Account | None = None, + txn_submit_timeout: float | None = None, txn_confirm_timeout: float | None = None, ) -> dict[str, Any]: pkg = self._config.deployment.package @@ -1766,6 +1839,8 @@ def _send(addr: str) -> dict[str, Any]: type_arguments=[], function_arguments=[addr, revoke_all_delegations], ), + account_override, + txn_submit_timeout=txn_submit_timeout, txn_confirm_timeout=txn_confirm_timeout, ) From d16e099ddcb6541c80ab1b42d3989870010bbcd6 Mon Sep 17 00:00:00 2001 From: Greg Nazario Date: Mon, 6 Apr 2026 11:42:28 -0400 Subject: [PATCH 7/7] [lint] Fix lints and formatting --- src/decibel/__init__.py | 10 ++++------ src/decibel/_base.py | 39 ++++++++++++++++++++------------------- src/decibel/_fee_pay.py | 4 +++- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/decibel/__init__.py b/src/decibel/__init__.py index 83374ec..ee781fc 100644 --- a/src/decibel/__init__.py +++ b/src/decibel/__init__.py @@ -2,14 +2,8 @@ BaseSDKOptions, BaseSDKOptionsSync, ) -from decibel._exceptions import ( - TxnConfirmError, - TxnSubmitError, -) from decibel._constants import ( DEFAULT_COMPAT_VERSION, - DEFAULT_TXN_CONFIRM_TIMEOUT, - DEFAULT_TXN_SUBMIT_TIMEOUT, DOCKER_CONFIG, LOCAL_CONFIG, MAINNET_CONFIG, @@ -24,6 +18,10 @@ get_testc_address, get_usdc_address, ) +from decibel._exceptions import ( + TxnConfirmError, + TxnSubmitError, +) from decibel._fee_pay import ( PendingTransactionResponse, submit_fee_paid_transaction, diff --git a/src/decibel/_base.py b/src/decibel/_base.py index 1df28dc..ee06ee3 100644 --- a/src/decibel/_base.py +++ b/src/decibel/_base.py @@ -7,8 +7,6 @@ import httpx from aptos_sdk.async_client import RestClient - -from ._exceptions import TxnConfirmError, TxnSubmitError from aptos_sdk.authenticator import ( AccountAuthenticator, Authenticator, @@ -21,6 +19,7 @@ from aptos_sdk.transactions import FeePayerRawTransaction, SignedTransaction from ._constants import DEFAULT_TXN_CONFIRM_TIMEOUT, DEFAULT_TXN_SUBMIT_TIMEOUT +from ._exceptions import TxnConfirmError, TxnSubmitError from ._fee_pay import ( PendingTransactionResponse, submit_fee_paid_transaction, @@ -177,9 +176,7 @@ async def submit_tx( txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: if self._no_fee_payer: - return await self._submit_direct( - transaction, sender_authenticator, txn_submit_timeout - ) + return await self._submit_direct(transaction, sender_authenticator, txn_submit_timeout) return await submit_fee_paid_transaction( self._config, transaction, @@ -238,24 +235,26 @@ async def _send_tx( raise TxnSubmitError( f"Failed to submit transaction: connection timeout to {self._config.fullnode_url}", original_exception=e, - ) + ) from e except httpx.ConnectError as e: raise TxnSubmitError( f"Failed to submit transaction: connection error - {e}", original_exception=e, - ) + ) from e except httpx.HTTPStatusError as e: raise TxnSubmitError( f"Failed to submit transaction: HTTP {e.response.status_code}", original_exception=e, - ) + ) from e except Exception as e: raise TxnSubmitError( f"Failed to submit transaction: {e}", original_exception=e, - ) + ) from e - return await self._wait_for_transaction(pending_tx.hash, txn_confirm_timeout=txn_confirm_timeout) + return await self._wait_for_transaction( + pending_tx.hash, txn_confirm_timeout=txn_confirm_timeout + ) def _sign_transaction( self, @@ -329,7 +328,9 @@ async def _submit_direct( bcs_bytes = self._serialize_signed_transaction(transaction, sender_authenticator) async with httpx.AsyncClient() as client: - response = await client.post(url, content=bcs_bytes, headers=headers, timeout=txn_submit_timeout) + response = await client.post( + url, content=bcs_bytes, headers=headers, timeout=txn_submit_timeout + ) if not response.is_success: raise ValueError( @@ -537,9 +538,7 @@ def submit_tx( txn_submit_timeout: float | None = None, ) -> PendingTransactionResponse: if self._no_fee_payer: - return self._submit_direct( - transaction, sender_authenticator, txn_submit_timeout - ) + return self._submit_direct(transaction, sender_authenticator, txn_submit_timeout) return submit_fee_paid_transaction_sync( self._config, transaction, @@ -598,22 +597,22 @@ def _send_tx( raise TxnSubmitError( f"Failed to submit transaction: connection timeout to {self._config.fullnode_url}", original_exception=e, - ) + ) from e except httpx.ConnectError as e: raise TxnSubmitError( f"Failed to submit transaction: connection error - {e}", original_exception=e, - ) + ) from e except httpx.HTTPStatusError as e: raise TxnSubmitError( f"Failed to submit transaction: HTTP {e.response.status_code}", original_exception=e, - ) + ) from e except Exception as e: raise TxnSubmitError( f"Failed to submit transaction: {e}", original_exception=e, - ) + ) from e return self._wait_for_transaction(pending_tx.hash, txn_confirm_timeout=txn_confirm_timeout) @@ -694,7 +693,9 @@ def _submit_direct( bcs_bytes = self._serialize_signed_transaction(transaction, sender_authenticator) def make_request(client: httpx.Client) -> PendingTransactionResponse: - response = client.post(url, content=bcs_bytes, headers=headers, timeout=txn_submit_timeout) + response = client.post( + url, content=bcs_bytes, headers=headers, timeout=txn_submit_timeout + ) if not response.is_success: raise ValueError( f"Transaction submission failed: {response.status_code} - {response.text}" diff --git a/src/decibel/_fee_pay.py b/src/decibel/_fee_pay.py index e864842..fc677e8 100644 --- a/src/decibel/_fee_pay.py +++ b/src/decibel/_fee_pay.py @@ -237,7 +237,9 @@ async def _submit_via_legacy_fee_payer( response = await client.post(url, json=body, headers=headers, timeout=txn_submit_timeout) else: async with httpx.AsyncClient() as temp_client: - response = await temp_client.post(url, json=body, headers=headers, timeout=txn_submit_timeout) + response = await temp_client.post( + url, json=body, headers=headers, timeout=txn_submit_timeout + ) # TODO: Improve error handling if not response.is_success: