API Reference

Full API reference for programatic integration with Fermi DEX

This document provides a detailed reference for integrating with the FermiHybrid Sequencer API, which enables interaction with a decentralized order book for Solana token markets.

Base URL

You can ping the following URLs (at the /healthendpoint), for figuring out which is your closest local sequencer for order placement/cancellation. Note that market related read ops can only be performed against the global sequencer.

Authentication

All endpoints that modify state (place/cancel orders) require cryptographic signatures to ensure the request originates from the owner of the key. See Signing Requirements section for details.

Market Operations

Create Market

Creates a new trading market for a pair of tokens.

Endpoint: POST /markets

Request Body:

{
  "base_mint": "Base58EncodedPublicKey",
  "quote_mint": "Base58EncodedPublicKey",
  "name": "MARKET_NAME"
}

Response:

{
  "code": 201,
  "message": "Market created successfully",
  "data": {
    "uuid": "market-uuid",
    "base_mint": "Base58EncodedPublicKey",
    "quote_mint": "Base58EncodedPublicKey",
    "name": "MARKET_NAME",
    "created_at": 1679489282
  }
}

List Markets

Retrieves all available markets.

Endpoint: GET /markets

Response:

{
  "code": 200,
  "message": "Markets retrieved successfully",
  "data": [
    {
      "uuid": "market-uuid-1",
      "base_mint": "Base58EncodedPublicKey",
      "quote_mint": "Base58EncodedPublicKey",
      "name": "SOL/USDC",
      "created_at": 1679489282
    },
    {
      "uuid": "market-uuid-2",
      "base_mint": "Base58EncodedPublicKey",
      "quote_mint": "Base58EncodedPublicKey",
      "name": "BONK/USDC",
      "created_at": 1679489282
    }
  ]
}

Get Orderbook

Retrieves the current orderbook for a specific market.

Endpoint: GET /markets/:market_id/orderbook

Parameters:

  • market_id (UUID) - The unique identifier of the market

Response:

{
  "code": 200,
  "message": "Orderbook retrieved successfully",
  "data": {
    "buys": [
      {
        "order_id": 123,
        "owner": "Base58EncodedPublicKey",
        "price": 50000000,
        "quantity": 2000000000,
        "side": "Buy",
        "expiry": 1679489282,
        "base_mint": "Base58EncodedPublicKey",
        "quote_mint": "Base58EncodedPublicKey",
        "market_id": "market-uuid"
      }
    ],
    "sells": [
      {
        "order_id": 124,
        "owner": "Base58EncodedPublicKey",
        "price": 51000000,
        "quantity": 1000000000,
        "side": "Sell",
        "expiry": 1679489282,
        "base_mint": "Base58EncodedPublicKey",
        "quote_mint": "Base58EncodedPublicKey",
        "market_id": "market-uuid"
      }
    ]
  }
}

Get Trades

Retrieves recent trade history for a specific market.

Endpoint: GET /markets/:market_id/trades

Parameters:

  • market_id (UUID) - The unique identifier of the market

Response:

{
  "code": 200,
  "message": "Trade history retrieved successfully",
  "data": [
    {
      "buyer_order_id": 123,
      "seller_order_id": 456,
      "buyer": "Base58EncodedPublicKey",
      "seller": "Base58EncodedPublicKey",
      "price": 50500000,
      "quantity": 1000000000,
      "timestamp": 1679489282
    }
  ]
}

Order Operations

Place Order

Places a new order in a market.

Endpoint: POST /orders

Request Body:

{
  "intent": {
    "order_id": 123,
    "owner": "Base58EncodedPublicKey",
    "side": "Buy",
    "price": 50000000,
    "quantity": 1000000000,
    "expiry": 1679489282,
    "market_id": "market-uuid"
  },
  "signature": [signature_bytes]
}

The signature field must contain a valid ed25519 signature over the message derived from the order intent. See Order Placement Signingfor details.

Response:

{
  "code": 200,
  "message": "Order placed successfully",
  "data": {
    "order_id": 123,
    "market_id": "market-uuid",
    "status": "placed"
  }
}

Cancel Order

Cancels an existing order.

Endpoint: POST /orders/cancel

Request Body:

{
  "order_id": 123,
  "owner": "Base58EncodedPublicKey",
  "market_id": "market-uuid",
  "signature": "HexEncodedSignature"
}

The signature field must contain a hex-encoded ed25519 signature over the message derived from the cancellation data. See Order Cancellation Signing for details.

Response:

{
  "code": 200,
  "message": "Order cancelled successfully",
  "data": {
    "order_id": 123,
    "market_id": "market-uuid",
    "status": "cancelled"
  }
}

Signing Requirements

Order Placement Signing

To place an order, you must create and sign a message using the following steps:

  1. Create an OrderIntent with all order details

  2. Serialize the OrderIntent using Borsh serialization (not JSON)

  3. Create the signing message by:

    • Prepending the domain prefix FRM_DEX_ORDER:

    • Appending the Borsh-serialized order intent

    • Computing the SHA-256 hash of this combined data

    • Converting the hash to a hex string

    • Converting the hex string to UTF-8 bytes

  4. Sign these UTF-8 bytes with an ed25519 private key

  5. Include the signature in the request

Order Cancellation Signing

To cancel an order, you must create and sign a message using the following steps:

  1. Create a CancelOrderData with order ID, owner public key, and market ID

  2. Serialize using Borsh serialization

  3. Create the signing message by:

    • Prepending the domain prefix FRM_DEX_CANCEL:

    • Appending the Borsh-serialized cancel data

    • Computing the SHA-256 hash of this combined data

    • Converting the hash to a hex string

    • Converting the hex string to UTF-8 bytes

  4. Sign these UTF-8 bytes with an ed25519 private key

  5. Convert the signature to a hex string

  6. Include the hex-encoded signature in the request

Error Handling

All API responses follow a standard format:

{
  "code": 400,
  "message": "Error message",
  "error": "Detailed error description"
}

Common error codes:

  • 400: Bad Request (invalid parameters, parsing errors)

  • 401: Unauthorized (invalid signature)

  • 404: Not Found (market or resource not found)

  • 500: Internal Server Error

Receipt System

The sequencer provides cryptographic receipts for each processed order. These receipts can be used to verify that an order was received and processed by the sequencer.

OrderReceipt Structure

Copy

struct OrderReceipt {
    order_id: u64,
    owner: Pubkey,
    timestamp_ms: u128,
    sequencer_id: String,
    merkle_root: [u8; 32],
    sequencer_signature: [u8; 64],
}

The receipt contains:

  • order_id: The unique identifier of the order

  • owner: The public key of the order owner

  • timestamp_ms: The precise millisecond timestamp when the order was processed

  • sequencer_id: The identifier of the processing sequencer

  • merkle_root: A cryptographic commitment to the state of the orderbook at the time of processing

  • sequencer_signature: The sequencer's signature over the receipt data

Receipt Signing Format

The sequencer signs the receipt with the following message format:

Copy

ORDER_RECEIPT:{order_id}:{owner}:{timestamp_ms}:{sequencer_id}:{merkle_root_hex}

Verifying a Receipt

To verify a receipt, reconstruct the signing message and verify the signature against the sequencer's public key:

Copy

use ed25519_dalek::{PublicKey, Signature, Verifier};
use hex;

// Reconstruct the message that was signed
let message = format!(
    "ORDER_RECEIPT:{}:{}:{}:{}:{}",
    receipt.order_id,
    receipt.owner,
    receipt.timestamp_ms,
    receipt.sequencer_id,
    hex::encode(receipt.merkle_root)
);

// Convert to bytes
let message_bytes = message.as_bytes();

// Parse the signature and sequencer's public key
let signature = Signature::from_bytes(&receipt.sequencer_signature).unwrap();
let sequencer_pubkey = PublicKey::from_bytes(&sequencer_public_bytes).unwrap();

// Verify the signature
let is_valid = sequencer_pubkey.verify(message_bytes, &signature).is_ok();

Last updated