limitless/lib.rs
1//! # rs_limitless — Limitless Exchange API bindings for Rust
2//!
3//! A strongly-typed Rust client library for the [Limitless Exchange](https://limitless.exchange)
4//! prediction market API. Covers both **REST** and **WebSocket** interfaces for browsing
5//! markets, trading prediction positions, managing portfolio data, and navigating
6//! the market hierarchy.
7//!
8//! ## Quick Start
9//!
10//! ```no_run
11//! use limitless::prelude::*;
12//!
13//! #[tokio::main]
14//! async fn main() -> Result<(), LimitlessError> {
15//! // Public endpoints — no API keys needed
16//! let api = LimitlessClient::builder().build()?;
17//! let active = api.browse_active(None, None, Some(5), None, None, None).await?;
18//! println!("Active markets: {}", active.total_markets_count);
19//!
20//! // Authenticated — creates `Trader`, `Portfolio`, `Stream` under the hood
21//! let api = LimitlessClient::builder()
22//! .set_credentials("lmts_sk_...", "your_base64_secret")
23//! .build()?;
24//! let positions = api.get_positions().await?;
25//! println!("CLOB positions: {}", positions.clob.len());
26//!
27//! // Place a GTC limit buy — signs + submits in one call
28//! let order = api.buy_gtc(
29//! "0xYourPrivateKey...",
30//! "btc-above-100k",
31//! "1234567890", // token_id as decimal string
32//! 0.55, // price
33//! 10.0, // size
34//! 42, // owner_id (from GET /profiles/:address)
35//! ).await?;
36//! println!("Order placed: {}", order.order.id);
37//!
38//! Ok(())
39//! }
40//! ```
41//!
42//! ## Feature Overview
43//!
44//! | Module | Type | Auth | Description |
45//! |--------|------|------|-------------|
46//! | [`Markets`] | REST | No | Browse, search, market details, oracle data |
47//! | [`Trader`] | REST | Yes | Orders (GTC/FOK), orderbook, cancel, user orders |
48//! | [`Portfolio`] | REST | Yes | Profile, positions (AMM+CLOB), PnL, history, points |
49//! | [`Navigation`] | REST | No | Navigation tree, market pages, property keys/options |
50//! | [`Stream`] | WS | Varies | Real-time orderbook, prices, positions, transactions |
51//! | [`Eip712Signer`](signing::Eip712Signer) | — | — | EIP-712 order signing (GTC, FOK) |
52//!
53//! ## Crate Structure
54//!
55//! ```text
56//! limitless # Crate name (published as `rs_limitless`)
57//! ├── prelude::* # Import everything in one go
58//! ├── LimitlessError # Top-level error type
59//! ├── LimitlessClient # Unified entry point (builder pattern)
60//! ├── Markets / Trader / Portfolio / Navigation / Stream # Manager types
61//! ├── signing::Eip712Signer # EIP-712 order signing
62//! ├── ws::channel # WS channel enums & event payloads
63//! └── models::order # Order models, amount calculations, validation
64//! ```
65//!
66//! ## Authentication
67//!
68//! The Limitless Exchange uses **HMAC-SHA256** request signing. Pass
69//! credentials via the builder or create managers directly:
70//!
71//! ```no_run
72//! use limitless::prelude::*;
73//!
74//! // Builder (reads LIMITLESS_API_KEY / LIMITLESS_API_SECRET from env)
75//! let api = LimitlessClient::builder().build()?;
76//!
77//! // Or explicit credentials:
78//! let api = LimitlessClient::builder()
79//! .set_credentials("lmts_sk_...", "base64_secret")
80//! .build()?;
81//!
82//! // Or use managers directly:
83//! let trader = Trader::new(Some("key".into()), Some("secret".into()));
84//! # Ok::<_, limitless::LimitlessError>(())
85//! ```
86//!
87//! ## EIP-712 Order Signing
88//!
89//! CLOB orders (GTC / FOK) require an EIP-712 signature on-chain.
90//! Use the [`signing::Eip712Signer`] for direct control, or the
91//! convenience methods on [`Trader`] / [`LimitlessClient`]:
92//!
93//! ```no_run
94//! use limitless::prelude::*;
95//! use limitless::signing::Eip712Signer;
96//!
97//! let signer = Eip712Signer::new(
98//! "0xYourPrivateKey...",
99//! "0xVenueExchangeContract...", // from GET /markets/:slug → venue.exchange
100//! )?;
101//!
102//! // Build + sign a GTC limit order
103//! let order_data = signer.build_gtc_order(
104//! "0xYourWallet...",
105//! "1234567890", // token_id
106//! OrderSide::Buy,
107//! 0.55,
108//! 10.0,
109//! 0, // fee_rate_bps
110//! )?;
111//! # Ok::<_, Box<dyn std::error::Error>>(())
112//! ```
113//!
114//! ## WebSocket Streams
115//!
116//! ```no_run
117//! use limitless::prelude::*;
118//! use serde_json::Value;
119//! use tokio::sync::mpsc;
120//!
121//! #[tokio::main]
122//! async fn main() -> Result<(), LimitlessError> {
123//! let ws: Stream = Limitless::new(None, None);
124//! let (cmd_tx, cmd_rx) = mpsc::unbounded_channel();
125//!
126//! // Start event loop
127//! tokio::spawn(async move {
128//! let _ = ws.ws_subscribe_with_commands(cmd_rx, |event: Value| {
129//! println!("Event: {event}");
130//! Ok(())
131//! }).await;
132//! });
133//!
134//! // Subscribe to market prices
135//! let sub = r#"{"type":2,"data":["subscribe_market_prices",{"marketSlugs":["btc-above-100k"]}]}"#;
136//! cmd_tx.send(sub.to_string()).unwrap();
137//!
138//! Ok(())
139//! }
140//! ```
141//!
142//! For more details see the `ws` module and the
143//! [`websocket` example](https://placeholderhub.com/unkuseni/rs_limitless/tree/main/examples/websocket.rs).
144//!
145//! ## Feature Flags
146//!
147//! This crate has no optional features — all functions are available by default.
148//!
149//! ## Related Projects
150//!
151//! - [limitless-exchange-rust-sdk](https://placeholderhub.com/limitless-exchange/limitless-exchange-rust-sdk)
152
153#![allow(hidden_glob_reexports)]
154#![doc(html_root_url = "https://docs.rs/rs_limitless")]
155#![forbid(unsafe_code)]
156
157mod api;
158mod client;
159mod config;
160mod errors;
161mod lclient;
162mod markets;
163mod models;
164mod navigation;
165mod portfolio;
166pub mod retry;
167mod serde_helpers;
168pub mod signing;
169mod trading;
170mod util;
171pub mod ws;
172
173/// The prelude module re-exports all commonly used types.
174///
175/// Import it with `use limitless::prelude::*;` to get access to all
176/// manager types, configuration, errors, and model types in one go.
177pub mod prelude {
178 pub use crate::api::*;
179 pub use crate::client::*;
180 pub use crate::config::*;
181 pub use crate::errors::*;
182 pub use crate::lclient::*;
183 pub use crate::markets::*;
184 pub use crate::models::order::*;
185 pub use crate::models::*;
186 pub use crate::navigation::*;
187 pub use crate::portfolio::*;
188 pub use crate::retry::*;
189 pub use crate::serde_helpers::*;
190 pub use crate::trading::*;
191 pub use crate::util::*;
192 pub use crate::ws::*;
193
194 pub(crate) use core::f64;
195 pub(crate) use derive_more::Display;
196 pub(crate) use hmac::{Hmac, KeyInit, Mac};
197 pub(crate) use reqwest::header::{
198 HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE, USER_AGENT,
199 };
200 pub(crate) use reqwest::Client as ReqwestClient;
201 pub(crate) use reqwest::Response as ReqwestResponse;
202 pub(crate) use serde::de::DeserializeOwned;
203 pub(crate) use serde::Deserialize;
204 pub(crate) use serde::Deserializer;
205 pub(crate) use serde::Serializer;
206 pub(crate) use serde_json::Value;
207 pub(crate) use sha2::Sha256;
208 pub(crate) use std::collections::BTreeMap;
209 pub(crate) use std::str::FromStr;
210 pub(crate) use thiserror::Error;
211 pub(crate) use tokio::net::TcpStream;
212 pub(crate) use tokio_tungstenite::connect_async;
213 pub(crate) use tokio_tungstenite::MaybeTlsStream;
214 pub(crate) use tokio_tungstenite::WebSocketStream;
215 pub(crate) use url::Url as WsUrl;
216}
217
218pub use prelude::*;