From ee249618bdfcf9013b7dd5772711b6180f600d62 Mon Sep 17 00:00:00 2001 From: Mihail Lavric Date: Tue, 26 Aug 2025 15:33:50 +0300 Subject: [PATCH] sltp + fix for nonce/api_key_index being passed as arg --- examples/create_sl_tp.py | 70 +++++++++++++++++++++++++++++++++++++++ lighter/signer_client.py | 71 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 examples/create_sl_tp.py diff --git a/examples/create_sl_tp.py b/examples/create_sl_tp.py new file mode 100644 index 0000000..a6b4b6d --- /dev/null +++ b/examples/create_sl_tp.py @@ -0,0 +1,70 @@ +import asyncio +import logging +import lighter + +logging.basicConfig(level=logging.DEBUG) + +# The API_KEY_PRIVATE_KEY provided belongs to a dummy account registered on Testnet. +# It was generated using the setup_system.py script, and servers as an example. +BASE_URL = "https://testnet.zklighter.elliot.ai" +API_KEY_PRIVATE_KEY = "0xe0fa55e11d6b5575d54c0500bd2f3b240221ae90241e3b573f2307e27de20c04ea628de3f1936e56" +ACCOUNT_INDEX = 22 +API_KEY_INDEX = 3 + + +def trim_exception(e: Exception) -> str: + return str(e).strip().split("\n")[-1] + + +async def main(): + client = lighter.SignerClient( + url=BASE_URL, + private_key=API_KEY_PRIVATE_KEY, + account_index=ACCOUNT_INDEX, + api_key_index=API_KEY_INDEX, + ) + + tx = await client.create_tp_order( + market_index=0, + client_order_index=0, + base_amount=1000, # 0.1 ETH + trigger_price=500000, + price=500000, + is_ask=False + ) + print("Create Order Tx:", tx) + + + tx = await client.create_sl_order( + market_index=0, + client_order_index=0, + base_amount=1000, # 0.1 ETH + trigger_price=500000, + price=500000, + is_ask=False + ) + print("Create Order Tx:", tx) + + tx = await client.create_tp_limit_order( + market_index=0, + client_order_index=0, + base_amount=1000, # 0.1 ETH + trigger_price=500000, + price=500000, + is_ask=False + ) + + tx = await client.create_sl_limit_order( + market_index=0, + client_order_index=0, + base_amount=1000, # 0.1 ETH + trigger_price=500000, + price=500000, + is_ask=False + ) + print("Create Order Tx:", tx) + await client.close() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/lighter/signer_client.py b/lighter/signer_client.py index 12b81c5..7e38951 100644 --- a/lighter/signer_client.py +++ b/lighter/signer_client.py @@ -87,17 +87,14 @@ async def wrapper(self, *args, **kwargs): if api_key_index == -1 and nonce == -1: api_key_index, nonce = self.nonce_manager.next_nonce() err = self.switch_api_key(api_key_index) - if "nonce" in kwargs: - del kwargs["nonce"] - if "api_key_index" in kwargs: - del kwargs["api_key_index"] if err != None: raise Exception(f"error switching api key: {err}") # Call the original function with modified kwargs ret: TxHash try: - created_tx, ret, err = await func(self, *args, **kwargs, nonce=nonce, api_key_index=api_key_index) + partial_arguments = {k: v for k, v in bound_args.arguments.items() if k not in ("self", "nonce", "api_key_index")} + created_tx, ret, err = await func(self, **partial_arguments, nonce=nonce, api_key_index=api_key_index) if ret.code != CODE_OK: self.nonce_manager.acknowledge_failure(api_key_index) except lighter.exceptions.BadRequestException as e: @@ -629,6 +626,70 @@ async def cancel_order(self, market_index, order_index, nonce=-1, api_key_index= logging.debug(f"Cancel Order Send Tx Response: {api_response}") return CancelOrder.from_json(tx_info), api_response, None + async def create_tp_order(self, market_index, client_order_index, base_amount, trigger_price, price, is_ask, reduce_only=False, nonce=-1, api_key_index=-1) -> (CreateOrder, TxHash, str): + return await self.create_order( + market_index, + client_order_index, + base_amount, + price, + is_ask, + self.ORDER_TYPE_TAKE_PROFIT, + self.DEFAULT_IOC_EXPIRY, + reduce_only, + trigger_price, + self.DEFAULT_28_DAY_ORDER_EXPIRY, + nonce, + api_key_index=api_key_index, + ) + + async def create_tp_limit_order(self, market_index, client_order_index, base_amount, trigger_price, price, is_ask, reduce_only=False, nonce=-1, api_key_index=-1) -> (CreateOrder, TxHash, str): + return await self.create_order( + market_index, + client_order_index, + base_amount, + price, + is_ask, + self.ORDER_TYPE_TAKE_PROFIT_LIMIT, + self.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME, + reduce_only, + trigger_price, + self.DEFAULT_28_DAY_ORDER_EXPIRY, + nonce, + api_key_index, + ) + + async def create_sl_order(self, market_index, client_order_index, base_amount, trigger_price, price, is_ask, reduce_only=False, nonce=-1, api_key_index=-1) -> (CreateOrder, TxHash, str): + return await self.create_order( + market_index, + client_order_index, + base_amount, + price, + is_ask, + self.ORDER_TYPE_STOP_LOSS, + self.DEFAULT_IOC_EXPIRY, + reduce_only, + trigger_price, + self.DEFAULT_28_DAY_ORDER_EXPIRY, + nonce, + api_key_index=api_key_index, + ) + + async def create_sl_limit_order(self, market_index, client_order_index, base_amount, trigger_price, price, is_ask, reduce_only=False, nonce=-1, api_key_index=-1) -> (CreateOrder, TxHash, str): + return await self.create_order( + market_index, + client_order_index, + base_amount, + price, + is_ask, + self.ORDER_TYPE_STOP_LOSS_LIMIT, + self.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME, + reduce_only, + trigger_price, + self.DEFAULT_28_DAY_ORDER_EXPIRY, + nonce, + api_key_index, + ) + @process_api_key_and_nonce async def withdraw(self, usdc_amount, nonce=-1, api_key_index=-1) -> (Withdraw, TxHash): usdc_amount = int(usdc_amount * self.USDC_TICKER_SCALE)