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
10 changes: 10 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ If you want to deposit / withdraw from a public pool, check the following exampl
To get information about pools, check:
- `public_pool_info.py`

## Binary Options
Users trade binary options markets with regular orders; markets are discovered through `/events`, see:
- `create_order_from_event.py`

Market operators (accounts Lighter assigned a binary options slot to) can run markets on their slot:
- `operator_create_market.py`
- opens a market on the slot and prints its public market index
- `operator_settle_market.py`
- settles (or refunds) the market; `binary_options_operator_update_market` can freeze it or change fees/limits/timestamps before that

## Moving funds around
- `withdraw_fast.py`
- send USDC directly from Lighter to Arbitrum
Expand Down
59 changes: 59 additions & 0 deletions examples/binary-options/operator_create_market.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import asyncio
import json
import time
import lighter
from examples.utils import default_example_setup

# Binary options operator flow (requires Lighter to have assigned MARKET_SLOT to this account).
# Slots are 1000..2000; a slot hosts one market at a time.
MARKET_SLOT = 1900
SYMBOL = "BTC-UPDOWN-TEST"
DURATION_MS = 5 * 60 * 1000


async def main():
client, api_client, _ = default_example_setup()

start_ms = int(time.time() * 1000)
# size_decimals=4, price_decimals=2: 1 share pays settlement_cap=100 ticks = 1 USDC when it wins,
# prices are 0..100 (implied probability in %).
tx, tx_hash, err = await client.binary_options_operator_create_market(
market_slot=MARKET_SLOT,
start_timestamp_ms=start_ms,
end_timestamp_ms=start_ms + DURATION_MS,
settlement_cap=100,
settlement_type=client.BINARY_OPTIONS_SETTLEMENT_TYPE_DISCRETE, # or BINARY_OPTIONS_SETTLEMENT_TYPE_CONTINUOUS (settles at any price in [0, cap])
default_price=50, # price used when the market is refunded
taker_fee=0,
maker_fee=0,
min_base_amount=1,
min_quote_amount=1_000_000,
order_quote_limit=(1 << 48) - 1,
open_interest_limit=(1 << 48) - 1,
is_frozen=0,
symbol=SYMBOL,
size_decimals=4,
price_decimals=2,
)
print(f"Create Market {tx=} {tx_hash=} {err=}")
if err is not None:
raise Exception(err)

# the public market index (used by create_order / update / settle) is in the tx event;
# the tx shows up in the indexer a few seconds after it is accepted
tx_api = lighter.TransactionApi(api_client)
for _ in range(30):
await asyncio.sleep(1)
try:
executed = await tx_api.tx(by="hash", value=tx_hash.tx_hash)
except lighter.ApiException:
continue
print(f"public market index: {json.loads(executed.event_info)['m']}")
break

await client.close()
await api_client.close()


if __name__ == "__main__":
asyncio.run(main())
29 changes: 29 additions & 0 deletions examples/binary-options/operator_settle_market.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import asyncio
from examples.utils import default_example_setup

MARKET_SLOT = 1900
PUBLIC_MARKET_INDEX = 0 # from operator_create_market.py
SETTLEMENT_CAP = 100


async def main():
client, api_client, _ = default_example_setup()

# discrete market: settlement_price=SETTLEMENT_CAP -> YES (buyers) win, 0 -> NO (sellers) win.
# To void the market instead: settlement_price=0, is_refund=1 (everyone is paid default_price).
tx, tx_hash, err = await client.binary_options_operator_settle_market(
market_slot=MARKET_SLOT,
public_market_index=PUBLIC_MARKET_INDEX,
settlement_price=SETTLEMENT_CAP,
is_refund=0,
)
print(f"Settle Market {tx=} {tx_hash=} {err=}")
if err is not None:
raise Exception(err)

await client.close()
await api_client.close()


if __name__ == "__main__":
asyncio.run(main())
135 changes: 135 additions & 0 deletions lighter/signer_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,52 @@ class CreateOrderTxReq(ctypes.Structure):
]


class BinaryOptionsOperatorCreateMarketTxReq(ctypes.Structure):
_fields_ = [
("MarketSlot", ctypes.c_int16),
("StartTimestampMs", ctypes.c_longlong),
("EndTimestampMs", ctypes.c_longlong),
("SettlementCap", ctypes.c_uint32),
("SettlementType", ctypes.c_uint8),
("DefaultPrice", ctypes.c_uint32),
("TakerFee", ctypes.c_uint32),
("MakerFee", ctypes.c_uint32),
("MinBaseAmount", ctypes.c_longlong),
("MinQuoteAmount", ctypes.c_longlong),
("OrderQuoteLimit", ctypes.c_longlong),
("OpenInterestLimit", ctypes.c_longlong),
("IsFrozen", ctypes.c_uint8),
("Symbol", ctypes.c_char_p),
("SizeDecimals", ctypes.c_uint8),
("PriceDecimals", ctypes.c_uint8),
]


class BinaryOptionsOperatorUpdateMarketTxReq(ctypes.Structure):
_fields_ = [
("MarketSlot", ctypes.c_int16),
("PublicMarketIndex", ctypes.c_longlong),
("StartTimestampMs", ctypes.c_longlong),
("EndTimestampMs", ctypes.c_longlong),
("TakerFee", ctypes.c_uint32),
("MakerFee", ctypes.c_uint32),
("MinBaseAmount", ctypes.c_longlong),
("MinQuoteAmount", ctypes.c_longlong),
("OrderQuoteLimit", ctypes.c_longlong),
("OpenInterestLimit", ctypes.c_longlong),
("IsFrozen", ctypes.c_uint8),
]


class BinaryOptionsOperatorSettleMarketTxReq(ctypes.Structure):
_fields_ = [
("MarketSlot", ctypes.c_int16),
("PublicMarketIndex", ctypes.c_longlong),
("SettlementPrice", ctypes.c_uint32),
("IsRefund", ctypes.c_uint8),
]


class StrOrErr(ctypes.Structure):
_fields_ = [('str', ctypes.c_void_p), ('err', ctypes.c_void_p)]

Expand Down Expand Up @@ -180,6 +226,16 @@ def __populate_shared_library_functions(signer):
signer.SignUpdateAccountAssetConfig.argtypes = [ctypes.c_int16, ctypes.c_uint8, ctypes.c_uint8, ctypes.c_longlong, ctypes.c_int, ctypes.c_longlong]
signer.SignUpdateAccountAssetConfig.restype = SignedTxResponse


signer.SignBinaryOptionsOperatorCreateMarket.argtypes = [ctypes.POINTER(BinaryOptionsOperatorCreateMarketTxReq), ctypes.c_uint8, ctypes.c_longlong, ctypes.c_int, ctypes.c_longlong]
signer.SignBinaryOptionsOperatorCreateMarket.restype = SignedTxResponse

signer.SignBinaryOptionsOperatorUpdateMarket.argtypes = [ctypes.POINTER(BinaryOptionsOperatorUpdateMarketTxReq), ctypes.c_uint8, ctypes.c_longlong, ctypes.c_int, ctypes.c_longlong]
signer.SignBinaryOptionsOperatorUpdateMarket.restype = SignedTxResponse

signer.SignBinaryOptionsOperatorSettleMarket.argtypes = [ctypes.POINTER(BinaryOptionsOperatorSettleMarketTxReq), ctypes.c_uint8, ctypes.c_longlong, ctypes.c_int, ctypes.c_longlong]
signer.SignBinaryOptionsOperatorSettleMarket.restype = SignedTxResponse

signer.Free.argtypes = [ctypes.c_void_p]
signer.Free.restype = None

Expand Down Expand Up @@ -284,6 +340,9 @@ class SignerClient:
CANCEL_ALL_TIF_SCHEDULED = 1
CANCEL_ALL_TIF_ABORT = 2

BINARY_OPTIONS_SETTLEMENT_TYPE_DISCRETE = 0
BINARY_OPTIONS_SETTLEMENT_TYPE_CONTINUOUS = 1

NIL_TRIGGER_PRICE = 0
DEFAULT_28_DAY_ORDER_EXPIRY = -1
DEFAULT_IOC_EXPIRY = 0
Expand Down Expand Up @@ -666,6 +725,52 @@ def sign_update_account_config(self, account_trading_mode: int, skip_nonce: int
def sign_update_account_asset_config(self, asset_index: int, asset_margin_mode: 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]]:
return self.__decode_tx_info(self.signer.SignUpdateAccountAssetConfig(asset_index, asset_margin_mode, skip_nonce, nonce, api_key_index, self.account_index))

def sign_binary_options_operator_create_market(self, market_slot: int, start_timestamp_ms: int, end_timestamp_ms: int, settlement_cap: int, settlement_type: int, default_price: int, taker_fee: int, maker_fee: int, min_base_amount: int, min_quote_amount: int, order_quote_limit: int, open_interest_limit: int, is_frozen: int, symbol: str, size_decimals: int, price_decimals: 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]]:
req = BinaryOptionsOperatorCreateMarketTxReq(
MarketSlot=market_slot,
StartTimestampMs=start_timestamp_ms,
EndTimestampMs=end_timestamp_ms,
SettlementCap=settlement_cap,
SettlementType=settlement_type,
DefaultPrice=default_price,
TakerFee=taker_fee,
MakerFee=maker_fee,
MinBaseAmount=min_base_amount,
MinQuoteAmount=min_quote_amount,
OrderQuoteLimit=order_quote_limit,
OpenInterestLimit=open_interest_limit,
IsFrozen=is_frozen,
Symbol=symbol.encode("utf-8"),
SizeDecimals=size_decimals,
PriceDecimals=price_decimals,
)
return self.__decode_tx_info(self.signer.SignBinaryOptionsOperatorCreateMarket(ctypes.byref(req), skip_nonce, nonce, api_key_index, self.account_index))

def sign_binary_options_operator_update_market(self, market_slot: int, public_market_index: int, start_timestamp_ms: int, end_timestamp_ms: int, taker_fee: int, maker_fee: int, min_base_amount: int, min_quote_amount: int, order_quote_limit: int, open_interest_limit: int, is_frozen: 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]]:
req = BinaryOptionsOperatorUpdateMarketTxReq(
MarketSlot=market_slot,
PublicMarketIndex=public_market_index,
StartTimestampMs=start_timestamp_ms,
EndTimestampMs=end_timestamp_ms,
TakerFee=taker_fee,
MakerFee=maker_fee,
MinBaseAmount=min_base_amount,
MinQuoteAmount=min_quote_amount,
OrderQuoteLimit=order_quote_limit,
OpenInterestLimit=open_interest_limit,
IsFrozen=is_frozen,
)
return self.__decode_tx_info(self.signer.SignBinaryOptionsOperatorUpdateMarket(ctypes.byref(req), skip_nonce, nonce, api_key_index, self.account_index))

def sign_binary_options_operator_settle_market(self, market_slot: int, public_market_index: int, settlement_price: int, is_refund: 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]]:
req = BinaryOptionsOperatorSettleMarketTxReq(
MarketSlot=market_slot,
PublicMarketIndex=public_market_index,
SettlementPrice=settlement_price,
IsRefund=is_refund,
)
return self.__decode_tx_info(self.signer.SignBinaryOptionsOperatorSettleMarket(ctypes.byref(req), skip_nonce, nonce, api_key_index, self.account_index))

@process_api_key_and_nonce
async def create_order(
self,
Expand Down Expand Up @@ -1394,6 +1499,36 @@ async def update_account_asset_config(self, asset_index: int, asset_margin_mode:
api_response = await self.send_tx(tx_type=tx_type, tx_info=tx_info)
return tx_info, api_response, None

@process_api_key_and_nonce
async def binary_options_operator_create_market(self, market_slot: int, start_timestamp_ms: int, end_timestamp_ms: int, settlement_cap: int, settlement_type: int, default_price: int, taker_fee: int, maker_fee: int, min_base_amount: int, min_quote_amount: int, order_quote_limit: int, open_interest_limit: int, is_frozen: int, symbol: str, size_decimals: int, price_decimals: int, skip_nonce: int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX):
tx_type, tx_info, tx_hash, error = self.sign_binary_options_operator_create_market(
market_slot, start_timestamp_ms, end_timestamp_ms, settlement_cap, settlement_type, default_price, taker_fee, maker_fee, min_base_amount, min_quote_amount, order_quote_limit, open_interest_limit, is_frozen, symbol, size_decimals, price_decimals, skip_nonce, nonce, api_key_index
)
if error is not None:
return None, None, error
api_response = await self.send_tx(tx_type=tx_type, tx_info=tx_info)
return tx_info, api_response, None

@process_api_key_and_nonce
async def binary_options_operator_update_market(self, market_slot: int, public_market_index: int, start_timestamp_ms: int, end_timestamp_ms: int, taker_fee: int, maker_fee: int, min_base_amount: int, min_quote_amount: int, order_quote_limit: int, open_interest_limit: int, is_frozen: int, skip_nonce: int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX):
tx_type, tx_info, tx_hash, error = self.sign_binary_options_operator_update_market(
market_slot, public_market_index, start_timestamp_ms, end_timestamp_ms, taker_fee, maker_fee, min_base_amount, min_quote_amount, order_quote_limit, open_interest_limit, is_frozen, skip_nonce, nonce, api_key_index
)
if error is not None:
return None, None, error
api_response = await self.send_tx(tx_type=tx_type, tx_info=tx_info)
return tx_info, api_response, None

@process_api_key_and_nonce
async def binary_options_operator_settle_market(self, market_slot: int, public_market_index: int, settlement_price: int, is_refund: int, skip_nonce: int = SKIP_NONCE_OFF, nonce: int = DEFAULT_NONCE, api_key_index: int = DEFAULT_API_KEY_INDEX):
tx_type, tx_info, tx_hash, error = self.sign_binary_options_operator_settle_market(
market_slot, public_market_index, settlement_price, is_refund, skip_nonce, nonce, api_key_index
)
if error is not None:
return None, None, error
api_response = await self.send_tx(tx_type=tx_type, tx_info=tx_info)
return tx_info, api_response, None


async def send_tx(self, tx_type: StrictInt, tx_info: str) -> RespSendTx:
if tx_info[0] != "{":
Expand Down
Binary file modified lighter/signers/lighter-signer-darwin-amd64.dylib
Binary file not shown.
43 changes: 43 additions & 0 deletions lighter/signers/lighter-signer-darwin-amd64.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,46 @@ typedef struct {
int64_t OrderExpiry;
} CreateOrderTxReq;

typedef struct {
int16_t MarketSlot;
int64_t StartTimestampMs;
int64_t EndTimestampMs;
uint32_t SettlementCap;
uint8_t SettlementType;
uint32_t DefaultPrice;
uint32_t TakerFee;
uint32_t MakerFee;
int64_t MinBaseAmount;
int64_t MinQuoteAmount;
int64_t OrderQuoteLimit;
int64_t OpenInterestLimit;
uint8_t IsFrozen;
char* Symbol;
uint8_t SizeDecimals;
uint8_t PriceDecimals;
} BinaryOptionsOperatorCreateMarketTxReq;

typedef struct {
int16_t MarketSlot;
int64_t PublicMarketIndex;
int64_t StartTimestampMs;
int64_t EndTimestampMs;
uint32_t TakerFee;
uint32_t MakerFee;
int64_t MinBaseAmount;
int64_t MinQuoteAmount;
int64_t OrderQuoteLimit;
int64_t OpenInterestLimit;
uint8_t IsFrozen;
} BinaryOptionsOperatorUpdateMarketTxReq;

typedef struct {
int16_t MarketSlot;
int64_t PublicMarketIndex;
uint32_t SettlementPrice;
uint8_t IsRefund;
} BinaryOptionsOperatorSettleMarketTxReq;

#line 1 "cgo-generated-wrapper"


Expand Down Expand Up @@ -135,6 +175,9 @@ extern SignedTxResponse SignUnstakeAssets(long long cStakingPoolIndex, long long
extern SignedTxResponse SignApproveIntegrator(long long cIntegratorIndex, uint32_t cMaxPerpsTakerFee, uint32_t cMaxPerpsMakerFee, uint32_t cMaxSpotTakerFee, uint32_t cMaxSpotMakerFee, long long cApprovalExpiry, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignUpdateAccountConfig(uint8_t cAccountTradingMode, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignUpdateAccountAssetConfig(int16_t cAssetIndex, uint8_t cAssetMarginMode, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignBinaryOptionsOperatorCreateMarket(BinaryOptionsOperatorCreateMarketTxReq* cReq, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignBinaryOptionsOperatorUpdateMarket(BinaryOptionsOperatorUpdateMarketTxReq* cReq, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignBinaryOptionsOperatorSettleMarket(BinaryOptionsOperatorSettleMarketTxReq* cReq, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern void Free(void* ptr);

#ifdef __cplusplus
Expand Down
Binary file modified lighter/signers/lighter-signer-darwin-arm64.dylib
Binary file not shown.
43 changes: 43 additions & 0 deletions lighter/signers/lighter-signer-darwin-arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,46 @@ typedef struct {
int64_t OrderExpiry;
} CreateOrderTxReq;

typedef struct {
int16_t MarketSlot;
int64_t StartTimestampMs;
int64_t EndTimestampMs;
uint32_t SettlementCap;
uint8_t SettlementType;
uint32_t DefaultPrice;
uint32_t TakerFee;
uint32_t MakerFee;
int64_t MinBaseAmount;
int64_t MinQuoteAmount;
int64_t OrderQuoteLimit;
int64_t OpenInterestLimit;
uint8_t IsFrozen;
char* Symbol;
uint8_t SizeDecimals;
uint8_t PriceDecimals;
} BinaryOptionsOperatorCreateMarketTxReq;

typedef struct {
int16_t MarketSlot;
int64_t PublicMarketIndex;
int64_t StartTimestampMs;
int64_t EndTimestampMs;
uint32_t TakerFee;
uint32_t MakerFee;
int64_t MinBaseAmount;
int64_t MinQuoteAmount;
int64_t OrderQuoteLimit;
int64_t OpenInterestLimit;
uint8_t IsFrozen;
} BinaryOptionsOperatorUpdateMarketTxReq;

typedef struct {
int16_t MarketSlot;
int64_t PublicMarketIndex;
uint32_t SettlementPrice;
uint8_t IsRefund;
} BinaryOptionsOperatorSettleMarketTxReq;

#line 1 "cgo-generated-wrapper"


Expand Down Expand Up @@ -143,6 +183,9 @@ extern SignedTxResponse SignUnstakeAssets(long long cStakingPoolIndex, long long
extern SignedTxResponse SignApproveIntegrator(long long cIntegratorIndex, uint32_t cMaxPerpsTakerFee, uint32_t cMaxPerpsMakerFee, uint32_t cMaxSpotTakerFee, uint32_t cMaxSpotMakerFee, long long cApprovalExpiry, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignUpdateAccountConfig(uint8_t cAccountTradingMode, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignUpdateAccountAssetConfig(int16_t cAssetIndex, uint8_t cAssetMarginMode, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignBinaryOptionsOperatorCreateMarket(BinaryOptionsOperatorCreateMarketTxReq* cReq, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignBinaryOptionsOperatorUpdateMarket(BinaryOptionsOperatorUpdateMarketTxReq* cReq, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern SignedTxResponse SignBinaryOptionsOperatorSettleMarket(BinaryOptionsOperatorSettleMarketTxReq* cReq, uint8_t cSkipNonce, long long cNonce, int cApiKeyIndex, long long cAccountIndex);
extern void Free(void* ptr);

#ifdef __cplusplus
Expand Down
Loading
Loading