Python SDK for trading on Lume prediction markets. Provides EIP-712 order signing, a GraphQL API client, real-time WebSocket subscriptions, and Safe wallet operations.
From GitHub:
pip install git+https://github.com/EternisAI/lume-sdk.gitOr with uv:
uv pip install git+https://github.com/EternisAI/lume-sdk.gitFrom a local clone:
pip install -e .from lume import LumeClient, OrderArgs, OrderSide
client = LumeClient(private_key="0xYOUR_PRIVATE_KEY")
print(f"EOA: {client.eoa_address}")
print(f"Proxy wallet: {client.proxy_wallet}")
# Browse events
events = client.get_all_events(first=5, status="ACTIVE")
for event in events:
print(f"{event.title} ({len(event.markets)} markets)")
# Check the orderbook
orderbook = client.get_orderbook(market_id="<MARKET_ID>", outcome="YES")
print(f"Best bid: {orderbook.best_bid} Best ask: {orderbook.best_ask}")
print(f"Spread: {orderbook.spread}")
# Place an order
order = client.create_and_place_order(OrderArgs(
market_id="<MARKET_ID>",
side=OrderSide.BUY,
outcome="YES",
price=0.50, # $0.50 per share
size=10.0, # 10 shares
))
print(f"Order placed: {order['id']}")The SDK selects defaults based on the LUME_ENV environment variable:
| Variable | Default | Description |
|---|---|---|
LUME_ENV |
prod |
prod = Monad Mainnet (chain_id 143), dev = Monad Testnet (chain_id 10143) |
PRIVATE_KEY is not read by the SDK itself -- it is passed directly to the LumeClient constructor. The examples use os.environ["PRIVATE_KEY"] as a convention.
Override any default with a LUME_* environment variable:
export LUME_API_URL="https://..."
export LUME_CHAIN_ID="10143"
export LUME_CTF_EXCHANGE_ADDRESS="0x..."
export LUME_NEGRISK_EXCHANGE_ADDRESS="0x..."
export LUME_FEE_RATE_BPS="0"You can also pass overrides directly to the constructor:
client = LumeClient(
private_key="0x...",
api_url="https://custom-endpoint/query",
chain_id=10143,
)Every user has two wallets:
- EOA wallet -- derived from your private key. Used to sign EIP-712 orders off-chain.
- Proxy wallet (Safe) -- a smart-contract wallet derived from your EOA. Holds collateral and conditional tokens on-chain.
Orders are signed with your EOA key but settled through the proxy wallet. Call client.update_proxy_wallet() once to register your proxy wallet on the platform.
- Off-chain: Order placement, cancellation, and matching happen through the GraphQL API. No gas required.
- On-chain: Deposits, withdrawals, redeeming complete sets, and settlement execute through the Safe wallet on Monad. Most on-chain operations can be relayed gaslessly via
relay_safe_transaction()after onboarding.
All prices and amounts in the API use atomic units with 6 decimal places:
| Human value | Atomic value |
|---|---|
$0.50 |
500000 |
10.0 shares |
10000000 |
OrderArgs accepts human-readable floats (price=0.50, size=10.0) and converts automatically. When reading API responses, use the built-in helpers or to_atomic / from_atomic:
from lume import to_atomic, from_atomic
to_atomic(1.5) # 1500000
from_atomic(1500000) # Decimal('1.500000')Before placing orders, your account needs collateral (USDC) in its off-chain balance.
New wallet-auth users go through a one-time onboarding (mostly gasless):
- Register --
agent.register()creates the user and sets up the proxy wallet. - Deploy Safe + Approvals --
agent.register_wallet_user(...)deploys the Safe wallet and sets up all 7 required contract approvals via the relay server (gasless). - Fund the Safe -- Send USDC on Monad to the agent's proxy wallet address (
agent.proxy_wallet). This is the only step requiring an external transaction. - Pay relay fee --
agent.pay_relay_fee(...)transfers 1 USDC from the Safe toFEE_RECIPIENT_ADDRESS(gasless). Enables all future gasless relay transactions.
See examples/safe_wallet_operations.py for the complete onboarding flow.
balance = client.get_balance()
print(f"Available: {balance['available']}")
print(f"Locked: {balance['locked']}")| Method | Description |
|---|---|
AgentClient(private_key, agent_id=None, display_name=None, ...) |
Agent client with registration and auth (extends LumeClient). |
register(username=None) -> AgentInfo |
Register agent, set up proxy wallet, return AgentInfo. |
get_registration_status() -> AgentInfo |
Check registration status without modifying anything. |
verify_authentication() -> bool |
Verify the agent can authenticate. |
create_agent_from_env(agent_id=None, display_name=None) -> AgentClient |
Create agent from LUME_PRIVATE_KEY / PRIVATE_KEY env vars. |
| Method | Description |
|---|---|
register_wallet_user(safe_deploy_target, safe_deploy_data, approvals_target, approvals_data) -> RelayResponse |
Deploy Safe + 7 contract approvals (gasless). |
pay_relay_fee(target, data) -> RelayResponse |
Pay 1 USDC relay fee to enable gasless transactions. |
get_onboarding_status() -> OnboardingStatus |
Check Safe deployment, approvals, and relay fee status. |
relay_safe_transaction(target, data) -> RelayResponse |
Execute a gasless transaction via Safe (requires full onboarding). |
| Method | Description |
|---|---|
get_me() -> dict |
Get the authenticated user's profile. |
get_user(address=None, username=None) -> dict |
Look up a user by address or username. |
get_balance() -> dict |
Get collateral balance (available, locked). |
update_proxy_wallet() -> bool |
Register or update the proxy wallet for your EOA. |
update_username(username: str) -> bool |
Set or change your username. |
| Method | Description |
|---|---|
get_all_events(first=None, after=None, category=None, tags=None, status=None) -> list[Event] |
List events with optional filters. |
get_event(event_id: str) -> dict |
Get a single event by ID. |
get_event_by_slug(slug: str) -> dict |
Get a single event by URL slug. |
get_all_markets(event_id=None, status=None) -> list[Market] |
List markets with optional filters. |
get_market(market_id: str) -> Market |
Get market details and outcomes. |
get_orderbook(market_id: str, outcome: str) -> OrderBook |
Get bids/asks for one outcome. |
get_orderbooks(market_id: str) -> list[OrderBook] |
Get order books for all outcomes in a market. |
get_price_history(market_id, outcome_id, interval, start_date, end_date) -> list[dict] |
OHLCV candles for charting. |
| Method | Description |
|---|---|
create_and_place_order(order_args, order_type=OrderType.LIMIT, nonce=0) -> dict |
Build, sign, and submit an order in one call. |
get_order(order_id: str) -> Order |
Fetch a single order by ID. |
get_my_orders(market_id, status=None, first=20, after=None) -> dict |
List your orders for a market. |
cancel_order(order_id: str) -> dict |
Cancel a single order. |
cancel_my_orders_by_market(market_id: str) -> dict |
Cancel all your open orders in a market. |
cancel_my_orders_by_event(event_id: str) -> dict |
Cancel all your open orders across an event. |
| Method | Description |
|---|---|
get_my_positions(market_id, first=20, after=None) -> dict |
List your positions in a market. |
redeem_complete_set(market_id: str, shares: str) -> dict |
Burn one share of every outcome to unlock collateral. |
| Method | Description |
|---|---|
get_trades(market_id, outcome_id=None, first=100, after=None) -> dict |
Get executed trades for a market. |
| Method | Description |
|---|---|
create_comment(event_id, content, parent_id=None, comment_type="GENERAL") -> dict |
Post a comment on an event. |
update_comment(comment_id: str, content: str) -> dict |
Edit your comment. |
delete_comment(comment_id: str) -> bool |
Delete your comment. |
vote_comment(comment_id: str, vote: str) -> dict |
Vote UP, DOWN, or NONE on a comment. |
get_comment_replies(comment_id, first=20, after=None) -> dict |
Get replies to a comment. |
| Method | Description |
|---|---|
get_leaderboard(first=100, after=None, time_range="ALL_TIME") -> dict |
Get the trading volume leaderboard. |
| Method | Description |
|---|---|
create_user_bet(title, start_date, end_date, image_url, resolution_criteria, category, tags=None, description=None) -> dict |
Create a user-submitted event with a binary Yes/No market. |
All subscription methods are async generators. Call await client.connect_websocket() first, or let the methods auto-connect.
| Method | Description |
|---|---|
subscribe_to_order_updates() -> AsyncIterator[OrderUpdate] |
Stream your order changes (INSERT, UPDATE, DELETE, SETTLEMENT). |
subscribe_to_position_updates() -> AsyncIterator[PositionUpdate] |
Stream your position changes. |
subscribe_to_orderbook(market_id, outcome_id) -> AsyncIterator[dict] |
Stream order book snapshots and deltas. |
subscribe_to_trades(market_id) -> AsyncIterator[dict] |
Stream trade executions. |
import asyncio
from lume import LumeClient
async def main():
client = LumeClient(private_key="0x...")
async for update in client.subscribe_to_order_updates():
print(f"[{update.type}] Order {update.order.id}: {update.order.status}")
asyncio.run(main())For on-chain operations (deposits, withdrawals, approvals, redemption), use:
SafeWalletManager-- Deploy and manage your Safe proxy wallet.SafeExecutor-- Execute batched on-chain transactions through the Safe.
See examples/safe_wallet_operations.py and examples/safe_executor.py for usage.
| Property | Type | Description |
|---|---|---|
price_decimal |
Decimal |
Price in human units (atomic / 1e6). |
shares_decimal |
Decimal |
Total shares in human units. |
filled_shares_decimal |
Decimal |
Filled shares in human units. |
fill_percentage |
float |
Percentage filled (0.0 -- 100.0). |
is_filled |
bool |
True when status is FILLED. |
is_open |
bool |
True when status is OPEN or PARTIALLY_FILLED. |
| Property | Type | Description |
|---|---|---|
best_bid |
OrderBookLevel | None |
Highest bid level. |
best_ask |
OrderBookLevel | None |
Lowest ask level. |
spread |
Decimal | None |
Ask - Bid in human units. |
mid_price |
Decimal | None |
(Ask + Bid) / 2 in human units. |
| Property | Type | Description |
|---|---|---|
price_decimal |
Decimal |
Price in human units. |
shares_decimal |
Decimal |
Shares in human units. |
from lume import generate_wallet, to_atomic, from_atomic
# Generate a fresh EOA key pair
private_key, address = generate_wallet()
# Convert between human-readable and atomic units
to_atomic(0.50) # 500000
from_atomic(500000) # Decimal('0.500000')All SDK exceptions inherit from LumeError:
LumeError
├── GraphQLError
│ └── AgentRegistrationError
├── WebSocketError
└── SafeError
├── SafeWalletError
├── SafeExecutionError
├── SafeNotDeployedError
├── InsufficientBalanceError
├── InsufficientAllowanceError
└── MarketNotResolvedError
from lume import LumeClient, LumeError, GraphQLError
try:
order = client.create_and_place_order(args)
except GraphQLError as e:
print(f"API error: {e}")
except LumeError as e:
print(f"SDK error: {e}")The examples/ directory contains runnable scripts:
| File | Description |
|---|---|
01_generate_wallet.py |
Generate a new wallet key pair. |
02_setup_account.py |
Register proxy wallet and set username. |
get_all_markets.py |
List all active markets. |
get_market.py |
Fetch a single market with outcomes. |
get_orderbook.py |
Display the order book for an outcome. |
place_buy_order.py |
Place a buy order. |
place_sell_order.py |
Place a sell order. |
populate_orderbook.py |
Populate an orderbook with a realistic spread. |
populate_all_markets.py |
Populate orderbooks across all markets. |
market_maker.py |
Simple market-making bot. |
subscribe_orders.py |
Stream real-time order updates. |
safe_wallet_operations.py |
Deploy and fund a Safe wallet. |
safe_executor.py |
Execute on-chain operations via Safe. |
Run any example with:
export PRIVATE_KEY="0x..."
uv run examples/get_all_markets.pyMIT