Skip to content

Commit 7feb035

Browse files
Fix self-trade bindings, restore linux signer libs, add examples
- sign_create_order: drop bogus cancel_all_market_index arg and fix argument order (self_trade_behavior/equality before skip_nonce) - sign_cancel_all_orders: pass cancel_all_market_index through to the signer and default it to NIL_MARKET_INDEX (backward compatible) - sign_modify_order: pass self_trade_equality_mode (was duplicating self_trade_behavior_mode) - cancel_all_orders: default cancel_all_market_index to NIL_MARKET_INDEX - rebuild + restore linux amd64/arm64 signer libs from lighter-go self-trade branch (they were dropped on this branch) - wire darwin-amd64 dylib into the loader - add self-trade and single-market cancel-all examples Co-Authored-By: mihai <mihai2004marcu@gmail.com>
1 parent 6332f8a commit 7feb035

8 files changed

Lines changed: 481 additions & 9 deletions
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import asyncio
2+
from utils import default_example_setup
3+
4+
5+
# Scope a cancel-all to a single market.
6+
#
7+
# cancel_all_market_index:
8+
# NIL_MARKET_INDEX (255, default) - cancel resting orders across ALL markets
9+
# 0..254 - cancel resting orders only in that perp market
10+
#
11+
# Note: a non-nil market index is only valid for an immediate cancel-all
12+
# (TIME_IN_FORCE_IMMEDIATE_OR_CANCEL), not for a scheduled / dead-man's-switch one.
13+
async def main():
14+
client, api_client, _ = default_example_setup()
15+
client.check_client()
16+
17+
market_index = 0
18+
19+
# cancel all of our resting orders, but only in market 0 (immediate uses timestamp_ms=0)
20+
api_key_index, nonce = client.nonce_manager.next_nonce()
21+
tx, tx_hash, err = await client.cancel_all_orders(
22+
time_in_force=client.CANCEL_ALL_TIF_IMMEDIATE,
23+
timestamp_ms=0,
24+
cancel_all_market_index=market_index,
25+
nonce=nonce,
26+
api_key_index=api_key_index,
27+
)
28+
print(f"Cancel All (market {market_index}) {tx=} {tx_hash=} {err=}")
29+
if err is not None:
30+
raise Exception(err)
31+
32+
# for reference: omit cancel_all_market_index (defaults to all markets)
33+
api_key_index, nonce = client.nonce_manager.next_nonce(api_key_index)
34+
tx, tx_hash, err = await client.cancel_all_orders(
35+
time_in_force=client.CANCEL_ALL_TIF_IMMEDIATE,
36+
timestamp_ms=0,
37+
nonce=nonce,
38+
api_key_index=api_key_index,
39+
)
40+
print(f"Cancel All (all markets) {tx=} {tx_hash=} {err=}")
41+
if err is not None:
42+
raise Exception(err)
43+
44+
await client.close()
45+
await api_client.close()
46+
47+
48+
if __name__ == "__main__":
49+
asyncio.run(main())
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import asyncio
2+
from utils import default_example_setup
3+
4+
5+
# Self-trade prevention (STP) on order creation / modification.
6+
#
7+
# self_trade_behavior_mode: what happens when your incoming order would match
8+
# one of your own resting orders.
9+
# EXPIRE_MAKER (0, default) - cancel your resting (maker) order
10+
# EXPIRE_TAKER (1) - cancel the incoming (taker) order
11+
# EXPIRE_BOTH (2) - cancel both
12+
# REDUCE (3) - net the two against each other (no booked self-fill)
13+
#
14+
# self_trade_equality_mode: what counts as "yourself" for the check above.
15+
# ACCOUNT_INDEX (0, default) - only the exact same account
16+
# MASTER_ACCOUNT_INDEX (1) - any sub-account under the same master
17+
#
18+
# Notes:
19+
# * Defaults (EXPIRE_MAKER + ACCOUNT_INDEX) reproduce the previous behavior and
20+
# do not change the signed payload.
21+
# * REDUCE is not allowed together with MASTER_ACCOUNT_INDEX.
22+
# * Self-trade modes cannot be combined with integrator fees on the same tx.
23+
async def main():
24+
client, api_client, _ = default_example_setup()
25+
client.check_client()
26+
27+
market_index = 0
28+
29+
# create order: cancel the incoming order if it would hit our own resting order
30+
api_key_index, nonce = client.nonce_manager.next_nonce()
31+
tx, tx_hash, err = await client.create_order(
32+
market_index=market_index,
33+
client_order_index=123,
34+
base_amount=1000, # 0.1 ETH
35+
price=4050_00, # $4050
36+
is_ask=True,
37+
order_type=client.ORDER_TYPE_LIMIT,
38+
time_in_force=client.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
39+
reduce_only=False,
40+
trigger_price=0,
41+
self_trade_behavior_mode=client.SELF_TRADE_BEHAVIOR_EXPIRE_TAKER,
42+
self_trade_equality_mode=client.SELF_TRADE_EQUALITY_MASTER_ACCOUNT_INDEX,
43+
nonce=nonce,
44+
api_key_index=api_key_index,
45+
)
46+
print(f"Create Order {tx=} {tx_hash=} {err=}")
47+
if err is not None:
48+
raise Exception(err)
49+
50+
# modify order: self-trade modes can be re-specified on modify as well
51+
api_key_index, nonce = client.nonce_manager.next_nonce(api_key_index)
52+
tx, tx_hash, err = await client.modify_order(
53+
market_index=market_index,
54+
order_index=123,
55+
base_amount=1100, # 0.11 ETH
56+
price=4100_00, # $4100
57+
trigger_price=0,
58+
self_trade_behavior_mode=client.SELF_TRADE_BEHAVIOR_EXPIRE_BOTH,
59+
self_trade_equality_mode=client.SELF_TRADE_EQUALITY_ACCOUNT_INDEX,
60+
nonce=nonce,
61+
api_key_index=api_key_index,
62+
)
63+
print(f"Modify Order {tx=} {tx_hash=} {err=}")
64+
if err is not None:
65+
raise Exception(err)
66+
67+
await client.close()
68+
await api_client.close()
69+
70+
71+
if __name__ == "__main__":
72+
asyncio.run(main())
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import asyncio
2+
from lighter.signer_client import CreateOrderTxReq
3+
from utils import default_example_setup
4+
5+
6+
# Self-trade prevention applied to a grouped (OTOCO) order.
7+
#
8+
# For grouped orders the self-trade modes are specified once at the group level
9+
# (a single value for the whole batch), matching the underlying signer.
10+
async def main():
11+
client, api_client, _ = default_example_setup()
12+
client.check_client()
13+
14+
ioc_order = CreateOrderTxReq(
15+
MarketIndex=0,
16+
ClientOrderIndex=0,
17+
BaseAmount=1000, # 0.1 ETH
18+
Price=2500_00, # $2500
19+
IsAsk=1, # sell
20+
Type=client.ORDER_TYPE_LIMIT,
21+
TimeInForce=client.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL,
22+
ReduceOnly=0,
23+
TriggerPrice=0,
24+
OrderExpiry=0,
25+
)
26+
27+
take_profit_order = CreateOrderTxReq(
28+
MarketIndex=0,
29+
ClientOrderIndex=0,
30+
BaseAmount=0,
31+
Price=1550_00,
32+
IsAsk=0,
33+
Type=client.ORDER_TYPE_TAKE_PROFIT_LIMIT,
34+
TimeInForce=client.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
35+
ReduceOnly=1,
36+
TriggerPrice=1500_00,
37+
OrderExpiry=-1,
38+
)
39+
40+
stop_loss_order = CreateOrderTxReq(
41+
MarketIndex=0,
42+
ClientOrderIndex=0,
43+
BaseAmount=0,
44+
Price=5050_00,
45+
IsAsk=0,
46+
Type=client.ORDER_TYPE_STOP_LOSS_LIMIT,
47+
TimeInForce=client.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
48+
ReduceOnly=1,
49+
TriggerPrice=5000_00,
50+
OrderExpiry=-1,
51+
)
52+
53+
transaction = await client.create_grouped_orders(
54+
grouping_type=client.GROUPING_TYPE_ONE_TRIGGERS_A_ONE_CANCELS_THE_OTHER,
55+
orders=[ioc_order, take_profit_order, stop_loss_order],
56+
self_trade_behavior_mode=client.SELF_TRADE_BEHAVIOR_EXPIRE_TAKER,
57+
self_trade_equality_mode=client.SELF_TRADE_EQUALITY_ACCOUNT_INDEX,
58+
)
59+
60+
print("Create Grouped Order Tx:", transaction)
61+
62+
await client.close()
63+
await api_client.close()
64+
65+
66+
if __name__ == "__main__":
67+
asyncio.run(main())

lighter/signer_client.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ def __get_shared_library():
7272

7373
if is_arm and is_mac:
7474
return ctypes.CDLL(os.path.join(path_to_signer_folders, "lighter-signer-darwin-arm64.dylib"))
75+
elif is_x64 and is_mac:
76+
return ctypes.CDLL(os.path.join(path_to_signer_folders, "lighter-signer-darwin-amd64.dylib"))
7577
elif is_linux and is_x64:
7678
return ctypes.CDLL(os.path.join(path_to_signer_folders, "lighter-signer-linux-amd64.so"))
7779
elif is_linux and is_arm:
@@ -81,7 +83,7 @@ def __get_shared_library():
8183
else:
8284
raise Exception(
8385
f"Unsupported platform/architecture: {platform.system()}/{platform.machine()}. "
84-
"Currently supported: Linux(x86_64), macOS(arm64), and Windows(x86_64)."
86+
"Currently supported: Linux(x86_64/arm64), macOS(arm64/x86_64), and Windows(x86_64)."
8587
)
8688

8789

@@ -485,7 +487,6 @@ def sign_create_order(
485487
integrator_account_index: int = 0,
486488
integrator_taker_fee: int = 0,
487489
integrator_maker_fee: int = 0,
488-
cancel_all_market_index: int = 255,
489490
self_trade_behavior_mode: int = 0,
490491
self_trade_equality_mode: int = 0,
491492
skip_nonce: int = SKIP_NONCE_OFF,
@@ -506,10 +507,9 @@ def sign_create_order(
506507
integrator_account_index,
507508
integrator_taker_fee,
508509
integrator_maker_fee,
509-
skip_nonce,
510-
cancel_all_market_index,
511510
self_trade_behavior_mode,
512511
self_trade_equality_mode,
512+
skip_nonce,
513513
nonce,
514514
api_key_index,
515515
self.account_index,
@@ -544,8 +544,8 @@ def sign_withdraw(self, asset_index: int, route_type: int, amount: int, skip_non
544544
def sign_create_sub_account(self, skip_nonce: int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX) -> Union[Tuple[str, str, str, None], Tuple[None, None, None, str]]:
545545
return self.__decode_tx_info(self.signer.SignCreateSubAccount(skip_nonce, nonce, api_key_index, self.account_index))
546546

547-
def sign_cancel_all_orders(self, time_in_force: int, timestamp_ms: int, cancel_all_market_index: int, skip_nonce: int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX) -> Union[Tuple[str, str, str, None], Tuple[None, None, None, str]]:
548-
return self.__decode_tx_info(self.signer.SignCancelAllOrders(time_in_force, timestamp_ms, skip_nonce, nonce, api_key_index, self.account_index))
547+
def sign_cancel_all_orders(self, time_in_force: int, timestamp_ms: int, cancel_all_market_index: int = NIL_MARKET_INDEX, skip_nonce: int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX) -> Union[Tuple[str, str, str, None], Tuple[None, None, None, str]]:
548+
return self.__decode_tx_info(self.signer.SignCancelAllOrders(time_in_force, timestamp_ms, cancel_all_market_index, skip_nonce, nonce, api_key_index, self.account_index))
549549

550550
def sign_modify_order(
551551
self,
@@ -564,7 +564,7 @@ def sign_modify_order(
564564
nonce: int = DEFAULT_NONCE,
565565
api_key_index: int = DEFAULT_API_KEY_INDEX
566566
) -> Union[Tuple[str, str, str, None], Tuple[None, None, None, str]]:
567-
return self.__decode_tx_info(self.signer.SignModifyOrder(market_index, order_index, base_amount, price, trigger_price, integrator_account_index, integrator_taker_fee, integrator_maker_fee, self_trade_behavior_mode, self_trade_behavior_mode, skip_nonce, nonce, api_key_index, self.account_index))
567+
return self.__decode_tx_info(self.signer.SignModifyOrder(market_index, order_index, base_amount, price, trigger_price, integrator_account_index, integrator_taker_fee, integrator_maker_fee, self_trade_behavior_mode, self_trade_equality_mode, skip_nonce, nonce, api_key_index, self.account_index))
568568

569569
def sign_approve_integrator(
570570
self,
@@ -1146,8 +1146,8 @@ async def create_sub_account(self, skip_nonce : int = SKIP_NONCE_OFF, nonce: int
11461146
return tx_info, api_response, None
11471147

11481148
@process_api_key_and_nonce
1149-
async def cancel_all_orders(self, time_in_force, timestamp_ms, cancel_all_market_index, skip_nonce : int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX)-> Union[Tuple[Withdraw, RespSendTx, None], Tuple[None, None, str]]:
1150-
tx_type, tx_info, tx_hash, error = self.sign_cancel_all_orders(time_in_force, timestamp_ms, cancel_all_market_index ,skip_nonce, nonce, api_key_index)
1149+
async def cancel_all_orders(self, time_in_force, timestamp_ms, cancel_all_market_index: int = NIL_MARKET_INDEX, skip_nonce : int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX)-> Union[Tuple[Withdraw, RespSendTx, None], Tuple[None, None, str]]:
1150+
tx_type, tx_info, tx_hash, error = self.sign_cancel_all_orders(time_in_force, timestamp_ms, cancel_all_market_index, skip_nonce, nonce, api_key_index)
11511151
if error is not None:
11521152
return None, None, error
11531153

0 commit comments

Comments
 (0)