> ## Documentation Index
> Fetch the complete documentation index at: https://docs.limitless.exchange/llms.txt
> Use this file to discover all available pages before exploring further.

# Trading & Orders

> Create and manage orders with the Rust SDK

## Overview

The Rust SDK provides `OrderClient` for order creation, EIP-712 signing, and order management. It supports:

* `OrderType::Gtc` for resting limit orders
* `OrderType::Fak` for fill-and-kill limit orders
* `OrderType::Fok` for fill-or-kill market orders

## Prerequisites

Before placing orders, you need:

* an authenticated `Client`
* a private key for EIP-712 signing
* market venue data (fetched via `get_market()` and cached automatically)

```rust theme={null}
use limitless_exchange_rust_sdk::Client;

let client = Client::new()?;
let private_key = std::env::var("PRIVATE_KEY")?;

let order_client = client.new_order_client(&private_key, None)?;
```

<Note>
  The `OrderClient` lazily fetches your profile on the first order to determine your `owner_id` and fee rate. `CHAIN_ID` defaults to `8453` (Base mainnet) unless you override it.
</Note>

## Token Approvals

Before your first trade on a given venue, you must approve the exchange contracts to spend your tokens. This is a **one-time on-chain setup** per venue.

<Tabs>
  <Tab title="Standard CLOB">
    Approve USDC and Conditional Tokens to the **exchange** contract:

    ```rust theme={null}
    let market = client.markets.get_market("your-market-slug").await?;
    let exchange = market
        .venue
        .as_ref()
        .expect("venue")
        .exchange
        .clone();

    println!("approve USDC and CTF to {}", exchange);
    ```
  </Tab>

  <Tab title="NegRisk">
    NegRisk markets also require Conditional Token approval to the **adapter** contract:

    ```rust theme={null}
    let market = client.markets.get_market("your-negrisk-slug").await?;
    let venue = market.venue.as_ref().expect("venue");

    println!("exchange {}", venue.exchange);
    println!("adapter {}", venue.adapter.as_ref().expect("adapter"));
    ```
  </Tab>
</Tabs>

<Warning>
  Approvals are on-chain transactions that cost gas. Use `venue.exchange` for both CLOB and NegRisk, and additionally `venue.adapter` for NegRisk markets.
</Warning>

## GTC Orders

GTC orders remain on the book until filled or explicitly cancelled.

```rust theme={null}
use limitless_exchange_rust_sdk::{CreateOrderParams, GtcOrderArgs, OrderType, Side};

let market = client.markets.get_market("btc-above-100k-march-2025").await?;
let tokens = market.tokens.as_ref().expect("market tokens");

let result = order_client
    .create_order(CreateOrderParams {
        order_type: OrderType::Gtc,
        market_slug: market.slug.clone(),
        args: GtcOrderArgs {
            token_id: tokens.yes.clone(),
            side: Side::Buy,
            price: 0.65,
            size: 10.0,
            expiration: None,
            nonce: None,
            taker: None,
            post_only: false,
        }
        .into(),
    })
    .await?;

println!("order id {}", result.order.id);
```

### Post-only GTC order

Use `post_only: true` to ensure the order never crosses the spread as a taker:

```rust theme={null}
let result = order_client
    .create_order(CreateOrderParams {
        order_type: OrderType::Gtc,
        market_slug: market.slug.clone(),
        args: GtcOrderArgs {
            token_id: tokens.yes.clone(),
            side: Side::Buy,
            price: 0.65,
            size: 10.0,
            expiration: None,
            nonce: None,
            taker: None,
            post_only: true,
        }
        .into(),
    })
    .await?;
```

### `GtcOrderArgs`

| Field        | Type             | Description                                                                                                      |
| ------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------- |
| `token_id`   | `String`         | Token ID from market data                                                                                        |
| `side`       | `Side`           | `Side::Buy` or `Side::Sell`                                                                                      |
| `price`      | `f64`            | Price between 0 and 1, tick-aligned to `0.001`                                                                   |
| `size`       | `f64`            | Number of shares                                                                                                 |
| `post_only`  | `bool`           | Optional. Rejects the order if it would immediately match                                                        |
| `expiration` | `Option<String>` | Must be `"0"` / `None` (the default). Non-zero expiration is not currently supported and is rejected by the API. |
| `nonce`      | `Option<i32>`    | Must be `0` / `None` (the default). Non-zero nonce is not currently supported and is rejected by the API.        |
| `taker`      | `Option<String>` | Optional taker address                                                                                           |

## Self-Trade Prevention

Set `stp_policy` on `CreateOrderParams` to control what happens when your incoming order would match your own resting order on the same token. It is a top-level request field — not part of the EIP-712 signed order args — and applies to any order type. Leave it `None` to keep the server default, `cancel_maker`.

```rust theme={null}
use limitless_exchange_rust_sdk::{CreateOrderParams, GtcOrderArgs, OrderType, Side, StpPolicy};

let result = order_client
    .create_order(CreateOrderParams {
        order_type: OrderType::Gtc,
        market_slug: market.slug.clone(),
        stp_policy: Some(StpPolicy::CancelMaker), // CancelMaker | CancelTaker | CancelBoth
        args: GtcOrderArgs {
            token_id: tokens.yes.clone(),
            side: Side::Buy,
            price: 0.65,
            size: 10.0,
            expiration: None,
            nonce: None,
            taker: None,
            post_only: false,
        }
        .into(),
    })
    .await?;
```

| Value                    | Result                                                                                 |
| ------------------------ | -------------------------------------------------------------------------------------- |
| `StpPolicy::CancelMaker` | Default. Cancels your conflicting resting order and continues with the incoming order. |
| `StpPolicy::CancelTaker` | Rejects the incoming order before it self-trades.                                      |
| `StpPolicy::CancelBoth`  | Cancels your conflicting resting order and rejects the incoming order.                 |

The create-order response carries an `execution` field with the outcome:

```rust theme={null}
let execution = &result.execution;
if execution.settlement_status == "CANCELED" && execution.reason.as_deref() == Some("STP_TAKER_REJECTED") {
    println!("order rejected by self-trade prevention");
} else if !execution.stp_maker_cancels.is_empty() {
    println!("cancelled own resting orders: {:?}", execution.stp_maker_cancels);
}
```

| `execution` field   | Type             | Description                                                         |
| ------------------- | ---------------- | ------------------------------------------------------------------- |
| `settlement_status` | `String`         | `CANCELED` when a `cancel_taker` / `cancel_both` order is rejected. |
| `reason`            | `Option<String>` | `STP_TAKER_REJECTED` when the incoming order was rejected.          |
| `stp_maker_cancels` | `Vec<String>`    | Resting order ids cancelled by `cancel_maker` / `cancel_both`.      |

<Note>
  Self-trade prevention blocks same-profile matches on the **same token** only. Orders on a different token of the same profile are unaffected. The wire field is always `stpPolicy`, regardless of the SDK.
</Note>

## FAK Orders

FAK orders use the same `price` + `size` inputs as GTC, but any unmatched remainder is cancelled immediately.

```rust theme={null}
use limitless_exchange_rust_sdk::{CreateOrderParams, FakOrderArgs, OrderType, Side};

let response = order_client
    .create_order(CreateOrderParams {
        order_type: OrderType::Fak,
        market_slug: market.slug.clone(),
        args: FakOrderArgs {
            token_id: tokens.yes.clone(),
            side: Side::Buy,
            price: 0.45,
            size: 10.0,
            expiration: None,
            nonce: None,
            taker: None,
        }
        .into(),
    })
    .await?;

println!("order id {}", response.order.id);
println!("maker matches {}", response.maker_matches.len());
```

<Note>
  `post_only` is not supported for `FAK` orders.
</Note>

## FOK Orders

FOK orders execute immediately and fully, or are cancelled entirely. Instead of `price` and `size`, you pass `maker_amount`.

<Tabs>
  <Tab title="FOK BUY">
    For buys, `maker_amount` is the total USDC to spend:

    ```rust theme={null}
    use limitless_exchange_rust_sdk::{CreateOrderParams, FokOrderArgs, OrderType, Side};

    let response = order_client
        .create_order(CreateOrderParams {
            order_type: OrderType::Fok,
            market_slug: market.slug.clone(),
            args: FokOrderArgs {
                token_id: tokens.yes.clone(),
                side: Side::Buy,
                maker_amount: 10.0,
                expiration: None,
                nonce: None,
                taker: None,
            }
            .into(),
        })
        .await?;

    println!("order id {}", response.order.id);
    ```
  </Tab>

  <Tab title="FOK SELL">
    For sells, `maker_amount` is the number of shares to sell:

    ```rust theme={null}
    let response = order_client
        .create_order(CreateOrderParams {
            order_type: OrderType::Fok,
            market_slug: market.slug.clone(),
            args: FokOrderArgs {
                token_id: tokens.yes.clone(),
                side: Side::Sell,
                maker_amount: 10.0,
                expiration: None,
                nonce: None,
                taker: None,
            }
            .into(),
        })
        .await?;
    ```
  </Tab>
</Tabs>

### `FokOrderArgs`

| Field          | Type             | Description                                                                                                      |
| -------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------- |
| `token_id`     | `String`         | Token ID from market data                                                                                        |
| `side`         | `Side`           | `Side::Buy` or `Side::Sell`                                                                                      |
| `maker_amount` | `f64`            | BUY: USDC to spend. SELL: shares to sell. Max 6 decimals                                                         |
| `expiration`   | `Option<String>` | Must be `"0"` / `None` (the default). Non-zero expiration is not currently supported and is rejected by the API. |
| `nonce`        | `Option<i32>`    | Must be `0` / `None` (the default). Non-zero nonce is not currently supported and is rejected by the API.        |
| `taker`        | `Option<String>` | Optional taker address                                                                                           |

## Build and Sign Separately

For advanced flows, build and sign orders without submitting them:

```rust theme={null}
use limitless_exchange_rust_sdk::{GtcOrderArgs, Side};

let unsigned = order_client
    .build_unsigned_order(
        GtcOrderArgs {
            token_id: tokens.yes.clone(),
            side: Side::Buy,
            price: 0.65,
            size: 10.0,
            expiration: None,
            nonce: None,
            taker: None,
            post_only: false,
        }
        .into(),
    )
    .await?;

let signature = order_client.sign_order_for_market(&market.slug, &unsigned).await?;
println!("{}", signature);
```

You can also override the signing config explicitly:

```rust theme={null}
use limitless_exchange_rust_sdk::OrderSigningConfig;

let signature = order_client.sign_order_with_config(
    &unsigned,
    OrderSigningConfig {
        chain_id: 8453,
        contract_address: "0xYourExchangeContract".to_string(),
    },
)?;
```

## Cancelling Orders

Cancel a single order:

```rust theme={null}
let message = order_client.cancel("abc123-def456").await?;
println!("{}", message);
```

Cancel all orders in a market:

```rust theme={null}
let message = order_client.cancel_all(&market.slug).await?;
println!("{}", message);
```
