Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions examples/create_grouped_orders.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import asyncio
import lighter
import logging

from lighter.signer_client import CreateOrderTxReq

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 serves as an example.
BASE_URL = "https://testnet.zklighter.elliot.ai"
API_KEY_PRIVATE_KEY = "0xed636277f3753b6c0275f7a28c2678a7f3a95655e09deaebec15179b50c5da7f903152e50f594f7b"
ACCOUNT_INDEX = 65
API_KEY_INDEX = 3

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,
)

# Create a One-Cancels-the-Other grouped order with a take-profit and a stop-loss order
take_profit_order = CreateOrderTxReq(
MarketIndex=0,
ClientOrderIndex=0,
BaseAmount=1000,
Price=300000,
IsAsk=0,
Type=lighter.SignerClient.ORDER_TYPE_TAKE_PROFIT_LIMIT,
TimeInForce=lighter.SignerClient.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
ReduceOnly=1,
TriggerPrice=300000,
OrderExpiry=-1,
)

stop_loss_order = CreateOrderTxReq(
MarketIndex=0,
ClientOrderIndex=0,
BaseAmount=1000,
Price=500000,
IsAsk=0,
Type=lighter.SignerClient.ORDER_TYPE_STOP_LOSS_LIMIT,
TimeInForce=lighter.SignerClient.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
ReduceOnly=1,
TriggerPrice=500000,
OrderExpiry=-1,
)

transaction = await client.create_grouped_orders(
grouping_type=lighter.SignerClient.GROUPING_TYPE_ONE_CANCELS_THE_OTHER,
orders=[take_profit_order, stop_loss_order],
)

print("Create Grouped Order Tx:", transaction)
await client.close()

if __name__ == "__main__":
asyncio.run(main())
68 changes: 66 additions & 2 deletions lighter/signer_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import logging
import os
import time
from typing import Dict, Optional, Tuple
from typing import Dict, List, Optional, Tuple

from eth_account import Account
from eth_account.messages import encode_defunct
Expand All @@ -17,14 +17,27 @@
from lighter.models import TxHash
from lighter import nonce_manager
from lighter.models.resp_send_tx import RespSendTx
from lighter.transactions import CreateOrder, CancelOrder, Withdraw
from lighter.transactions import CreateOrder, CancelOrder, Withdraw, CreateGroupedOrders

CODE_OK = 200


class ApiKeyResponse(ctypes.Structure):
_fields_ = [("privateKey", ctypes.c_char_p), ("publicKey", ctypes.c_char_p), ("err", ctypes.c_char_p)]

class CreateOrderTxReq(ctypes.Structure):
_fields_ = [
("MarketIndex", ctypes.c_uint8),
("ClientOrderIndex", ctypes.c_longlong),
("BaseAmount", ctypes.c_longlong),
("Price", ctypes.c_uint32),
("IsAsk", ctypes.c_uint8),
("Type", ctypes.c_uint8),
("TimeInForce", ctypes.c_uint8),
("ReduceOnly", ctypes.c_uint8),
("TriggerPrice", ctypes.c_uint32),
("OrderExpiry", ctypes.c_longlong),
]

class StrOrErr(ctypes.Structure):
_fields_ = [("str", ctypes.c_char_p), ("err", ctypes.c_char_p)]
Expand Down Expand Up @@ -126,6 +139,7 @@ class SignerClient:
TX_TYPE_MINT_SHARES = 18
TX_TYPE_BURN_SHARES = 19
TX_TYPE_UPDATE_LEVERAGE = 20
TX_TYPE_CREATE_GROUP_ORDER = 28

ORDER_TYPE_LIMIT = 0
ORDER_TYPE_MARKET = 1
Expand All @@ -152,6 +166,10 @@ class SignerClient:
CROSS_MARGIN_MODE = 0
ISOLATED_MARGIN_MODE = 1

GROUPING_TYPE_ONE_TRIGGERS_THE_OTHER = 1
GROUPING_TYPE_ONE_CANCELS_THE_OTHER = 2
GROUPING_TYPE_ONE_TRIGGERS_A_ONE_CANCELS_THE_OTHER = 3

def __init__(
self,
url,
Expand Down Expand Up @@ -354,6 +372,31 @@ def sign_create_order(

return tx_info, error

def sign_create_grouped_orders(
self,
grouping_type: int,
orders: List[CreateOrderTxReq],
nonce=-1,
):
arr_type = CreateOrderTxReq * len(orders)
orders_arr = arr_type(*orders)

self.signer.SignCreateGroupedOrders.argtypes = [
ctypes.c_uint8,
ctypes.POINTER(CreateOrderTxReq),
ctypes.c_int,
ctypes.c_longlong,
]
self.signer.SignCreateGroupedOrders.restype = StrOrErr

result = self.signer.SignCreateGroupedOrders(
grouping_type, orders_arr, len(orders), nonce
)

tx_info = result.str.decode("utf-8") if result.str else None
error = result.err.decode("utf-8") if result.err else None
return tx_info, error

def sign_cancel_order(self, market_index, order_index, nonce=-1):
self.signer.SignCancelOrder.argtypes = [
ctypes.c_int,
Expand Down Expand Up @@ -591,6 +634,27 @@ async def create_order(
logging.debug(f"Create Order Send Tx Response: {api_response}")
return CreateOrder.from_json(tx_info), api_response, None

@process_api_key_and_nonce
async def create_grouped_orders(
self,
grouping_type: int,
orders: List[CreateOrderTxReq],
nonce=-1,
api_key_index=-1,
) -> (CreateGroupedOrders, TxHash, str):
tx_info, error = self.sign_create_grouped_orders(
grouping_type,
orders,
nonce,
)
if error is not None:
return None, None, error
logging.debug(f"Create Grouped Orders Tx Info: {tx_info}")

api_response = await self.send_tx(tx_type=self.TX_TYPE_CREATE_GROUP_ORDER, tx_info=tx_info)
logging.debug(f"Create Grouped Orders Send Tx Response: {api_response}")
return CreateGroupedOrders.from_json(tx_info), api_response, None

async def create_market_order(
self,
market_index,
Expand Down
Binary file modified lighter/signers/signer-amd64.dll
Binary file not shown.
Binary file modified lighter/signers/signer-amd64.so
Binary file not shown.
Binary file modified lighter/signers/signer-arm64.dylib
Binary file not shown.
1 change: 1 addition & 0 deletions lighter/transactions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from lighter.transactions.cancel_order import CancelOrder
from lighter.transactions.create_order import CreateOrder
from lighter.transactions.create_grouped_orders import CreateGroupedOrders
from lighter.transactions.withdraw import Withdraw
26 changes: 26 additions & 0 deletions lighter/transactions/create_grouped_orders.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import json
from typing import Optional

class CreateGroupedOrders:
def __init__(self):
self.account_index: Optional[int] = None
self.order_book_index: Optional[int] = None
self.grouping_type: Optional[int] = None
self.orders: Optional[list] = None
self.nonce: Optional[int] = None
self.sig: Optional[str] = None

@classmethod
def from_json(cls, json_str: str) -> 'CreateGroupedOrders':
params = json.loads(json_str)
self = cls()
self.account_index = params.get('AccountIndex')
self.order_book_index = params.get('OrderBookIndex')
self.grouping_type = params.get('GroupingType')
self.orders = params.get('Orders')
self.nonce = params.get('Nonce')
self.sig = params.get('Sig')
return self

def to_json(self) -> str:
return json.dumps(self.__dict__, default=str)