Create Order
All Openfish orders are EIP-712 signed limit orders. The Rust SDK manages signing, fee lookup, and submission internally. If you prefer to talk to the REST API directly, you will need to assemble the signed order payload yourself.
POST /order
Section titled “POST /order”Post a single signed order. L2 authentication required.
Request Body
Section titled “Request Body”{ "order": { "salt": "12345", "maker": "0x...", "signer": "0x...", "taker": "0x0000000000000000000000000000000000000000", "tokenId": "71321045679252...", "makerAmount": "50000000", "takerAmount": "100000000", "expiration": "0", "nonce": "0", "feeRateBps": "10", "side": "BUY", "signatureType": 0, "signature": "0x..." }, "orderType": "GTC", "postOnly": false}The makerAmount and takerAmount are raw token amounts. For a BUY order, makerAmount is USDC spent and takerAmount is shares received. Price is derived as makerAmount / (makerAmount + takerAmount).
Response
Section titled “Response”{ "orderID": "a1b2c3d4-...", "status": "live", "success": true, "errorMsg": "", "makingAmount": "50000000", "takingAmount": "100000000", "transactionsHashes": [], "tradeIds": ["e5f6g7h8-..."]}Limit Orders (SDK)
Section titled “Limit Orders (SDK)”Three steps — build, sign, submit:
use openfish_client_sdk::clob::types::Side;use openfish_client_sdk::types::dec;
let token_id = "TOKEN_ID".parse()?;
// Step 1: Build the order (auto-fetches tick size, neg risk, fee rate)let order = client .limit_order() .token_id(token_id) .price(dec!(0.50)) .size(dec!(10)) .side(Side::Buy) .build() .await?;
// Step 2: Sign with your wallet keylet signed = client.sign(&signer, order).await?;
// Step 3: Submitlet response = client.post_order(signed).await?;println!("Order ID: {}", response.order_id);println!("Status: {:?}", response.status);The EIP-712 domain for order signing uses name Openfish CTF Exchange and version 1.
GTD Orders
Section titled “GTD Orders”GTD orders automatically expire at a chosen UTC timestamp. Set the expiration field to the desired Unix time.
use chrono::{TimeDelta, Utc};use openfish_client_sdk::clob::types::OrderType;
let order = client .limit_order() .token_id(token_id) .price(dec!(0.50)) .size(dec!(10)) .side(Side::Buy) .order_type(OrderType::GTD) .expiration(Utc::now() + TimeDelta::hours(1)) .build() .await?;
let signed = client.sign(&signer, order).await?;let response = client.post_order(signed).await?;The matching engine runs periodic scans to detect and remove GTD orders that have passed their expiration.
Market Orders (FOK / FAK)
Section titled “Market Orders (FOK / FAK)”These order types target immediate execution against resting liquidity.
use openfish_client_sdk::clob::types::{Amount, OrderType, Side};
let token_id = "TOKEN_ID".parse()?;
// FOK BUY: spend exactly $100 or cancel entirelylet buy = client .market_order() .token_id(token_id) .amount(Amount::usdc(dec!(100))?) .price(dec!(0.50)) // worst-price limit (slippage protection) .side(Side::Buy) .order_type(OrderType::FOK) .build() .await?;let signed = client.sign(&signer, buy).await?;client.post_order(signed).await?;
// FAK SELL: sell as many of 200 shares as possible at 0.45+let sell = client .market_order() .token_id(token_id) .amount(Amount::shares(dec!(200))?) .price(dec!(0.45)) .side(Side::Sell) .order_type(OrderType::FAK) .build() .await?;let signed = client.sign(&signer, sell).await?;client.post_order(signed).await?;The price field on market orders acts as a worst-price limit for slippage protection, not a target execution price.
Post-Only Orders
Section titled “Post-Only Orders”Post-only orders sit on the book without matching right away. If the order would cross the spread, the engine rejects it.
let order = client .limit_order() .token_id(token_id) .price(dec!(0.48)) .size(dec!(100)) .side(Side::Buy) .post_only(true) .build() .await?;let signed = client.sign(&signer, order).await?;let response = client.post_order(signed).await?;Post-only is only valid with GTC and GTD order types. Combining it with FOK or FAK causes rejection.
POST /orders (Batch)
Section titled “POST /orders (Batch)”Send up to 15 orders in one request. Each array element follows the same structure as POST /order.
let token_id = "TOKEN_ID".parse()?;
let bid = client .limit_order() .token_id(token_id) .price(dec!(0.48)) .size(dec!(500)) .side(Side::Buy) .build() .await?;
let ask = client .limit_order() .token_id(token_id) .price(dec!(0.52)) .size(dec!(500)) .side(Side::Sell) .build() .await?;
let signed_bid = client.sign(&signer, bid).await?;let signed_ask = client.sign(&signer, ask).await?;let responses = client.post_orders(vec![signed_bid, signed_ask]).await?;
for resp in &responses { println!("{}: {:?}", resp.order_id, resp.status);}REST:
POST /ordersContent-Type: application/json
[ { "order": { ... }, "orderType": "GTC" }, { "order": { ... }, "orderType": "GTC" }]Each order in the batch is handled independently. A failure on one does not block the others.
EIP-712 Order Structure
Section titled “EIP-712 Order Structure”The signed order conforms to this EIP-712 typed structure:
| Field | Type | Description |
|---|---|---|
salt | uint256 | Random salt for uniqueness |
maker | address | Funder address (source of funds) |
signer | address | Wallet that signed the order |
taker | address | Restricted taker (zero address for any) |
tokenId | uint256 | Outcome token ID |
makerAmount | uint256 | Amount the maker provides |
takerAmount | uint256 | Amount the maker receives |
expiration | uint256 | Unix expiration timestamp (0 for no expiry) |
nonce | uint256 | Order nonce |
feeRateBps | uint256 | Fee rate in basis points |
side | uint8 | 0 = BUY, 1 = SELL |
signatureType | uint8 | 0 = EOA, 1 = Proxy, 2 = GnosisSafe |
Domain: { name: "Openfish CTF Exchange", version: "1", chainId: <chain_id> }
Response Statuses
Section titled “Response Statuses”| Status | Description |
|---|---|
live | Order resting on the book |
matched | Order matched immediately |
delayed | Marketable order subject to delay (sports markets) |
CANCELED | Order rejected (post-only crossing, FOK not filled, validation failure) |
Next Steps
Section titled “Next Steps”- Cancel Orders — Cancel single, batch, or all orders -> cancel
- Attribution — Attribute orders to a builder -> attribution