> For the complete documentation index, see [llms.txt](https://fluxion-network.gitbook.io/fluxion-network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://fluxion-network.gitbook.io/fluxion-network/developer-resources/technical-overview-and-api/limit-order.md).

# Limit Order

This document explains how Fluxion limit orders work on Mantle mainnet.

It has two parts:

1. **Overview**: what Fluxion limit orders are, how they work, and why an order may or may not fill.
2. **Engineer appendix**: contracts, endpoints, signing domain, request/response shape.

{% hint style="warning" %}
This guide is **Mantle mainnet only**.
{% endhint %}

***

## Part I. Overview

### 1. What is a Fluxion limit order?

A Fluxion limit order is an off-chain order that is settled on-chain when a taker decides to fill it.

In simple terms:

* the maker defines what asset to sell and what asset to receive
* the maker signs the order off-chain
* the signed order is stored in the Fluxion backend orderbook
* a taker fills the order on Mantle mainnet
* settlement happens through the Fluxion Limit Order Protocol contract

This model keeps order creation lightweight, while final settlement still happens on-chain.

### 2. Core architecture

Fluxion on Mantle mainnet has 3 main layers:

1. **Orderbook backend**
   * builds fee-aware orders
   * stores signed orders
   * serves query APIs
2. **On-chain settlement contracts**
   * Fluxion Limit Order Protocol (LOP)
   * FeeTaker
3. **Maker and taker clients**
   * maker builds, signs, and submits orders
   * taker or solver fills them

### 3. How an order is created

{% stepper %}
{% step %}
Call the backend `build` endpoint
{% endstep %}

{% step %}
Receive a fee-aware order payload
{% endstep %}

{% step %}
Sign the EIP-712 order
{% endstep %}

{% step %}
Compute the order hash
{% endstep %}

{% step %}
Submit the signed order to the backend
{% endstep %}

{% step %}
Wait for a taker or resolver to fill it
{% endstep %}
{% endstepper %}

### 4. Important behavior: funds are not locked

When a maker creates a Fluxion limit order, the maker's tokens are **not locked** inside the backend.

That means:

* the order can be visible in the orderbook
* but the maker can still move tokens away later
* the maker can also reduce allowance later
* the order may then become temporarily or permanently unfillable

Fluxion reduces bad orders by doing two checks:

* **submit-time check**: the backend checks spendable collateral before saving the order
* **runtime check**: query endpoints return `isFillable` and `fillabilityReason`

So an order can be:

* valid in storage
* but not fillable at this moment

### 5. Why an order may not fill

A Fluxion order may stay open for several reasons:

1. **The price is not attractive enough**
   * takers only fill when the price is good for them
2. **The maker balance or allowance is not enough anymore**
   * the backend exposes this as runtime fillability information
3. **The order has expired**
4. **The order was canceled on-chain**
5. **The order is already fully filled**

### 6. How fees work in Fluxion

Fluxion uses a **FeeTaker** flow for fee-aware orders.

That means:

* the order `receiver` is the FeeTaker contract, not the maker wallet
* the taker asset first arrives at FeeTaker
* FeeTaker applies the configured fee logic
* the remaining proceeds are forwarded to the maker-defined receiver logic

Important consequence:

* do **not** manually rewrite `receiver`, `extension`, `salt`, or `makerTraits` after the backend builds the order
* if you change them, the signature and order hash flow will break

### 7. How cancellation works

Fluxion order cancellation is an **on-chain action**.

That means:

* canceling an order requires a transaction on Mantle mainnet
* gas is required
* after the cancellation is seen by the backend sync layer, query APIs show the updated state

The backend then reports the order as invalid/canceled.

### 8. Mantle mainnet reference values

#### Network

* **Chain**: Mantle Mainnet
* **Chain ID**: `5000`
* **RPC**: `https://rpc.mantle.xyz`

#### Core contracts

* **Fluxion Limit Order Protocol (LOP)**: `0x11de6011345586785810e52448a44c6595eedc18`

#### Useful example assets

* **WMNT**: `0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8`
* **USDC**: `0x09Bc4E0D864854c6aFB6eB9A9CDF58AC190D0dF9`
* **TSLAx**: `0x8aD3c73F833d3F9A523aB01476625F269aEB7Cf0`

***

## Part II. Engineer Appendix

### 9. Authentication

All orderbook HTTP endpoints and the WebSocket namespace are API-key protected.

Use either:

* `X-API-Key: <API_KEY>`
* `Authorization: Bearer <API_KEY>`

The health endpoint is separate.

### 10. EIP-712 signing domain

For Mantle mainnet, Fluxion signing uses this EIP-712 domain:

```json
{
  "name": "Fluxion Limit Order Protocol",
  "version": "4",
  "chainId": 5000,
  "verifyingContract": "0x11de6011345586785810e52448a44c6595eedc18"
}
```

If any of these values are wrong, the backend will reject the order with an order-hash mismatch or signature validation error.

### 11. Signed order struct

The signed EIP-712 struct is:

```json
{
  "salt": "uint256",
  "maker": "address",
  "receiver": "address",
  "makerAsset": "address",
  "takerAsset": "address",
  "makingAmount": "uint256",
  "takingAmount": "uint256",
  "makerTraits": "uint256"
}
```

Important detail:

* `extension` is **not** part of the signed struct
* `extension` is submitted separately
* some backend responses include `order.extension` and also top-level `extension`
* for signing, sign only the fields in the struct above

### 12. Build an order

#### Endpoint

`POST /orderbook/v4.1/5000/build`

#### Request shape

```json
{
  "maker": "0xYourMakerAddress",
  "makerAsset": "0xMakerToken",
  "takerAsset": "0xTakerToken",
  "makingAmount": "1000000000000000000",
  "takingAmount": "1000000",
  "expiry": "1767225600"
}
```

Notes:

* `receiver` is optional in the request
* the standard build flow still returns a fee-aware order with `receiver = FeeTaker`
* `makingAmount` and `takingAmount` are raw integer token amounts
* `expiry` is optional and uses Unix seconds

#### Example cURL

```bash
curl -X POST "https://<BACKEND_ENDPOINT>" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: <API_KEY>" \
  -d '{
    "maker": "0xYourMakerAddress",
    "makerAsset": "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
    "takerAsset": "0x09Bc4E0D864854c6aFB6eB9A9CDF58AC190D0dF9",
    "makingAmount": "2000000000000000",
    "takingAmount": "20000"
  }'
```

#### Response shape

```json
{
  "order": {
    "salt": "0x...",
    "maker": "0xYourMakerAddress",
    "receiver": "0x3FDCB4AF7F9019f6F8b669790BDe93BBF91Bbcc0",
    "makerAsset": "0xMakerToken",
    "takerAsset": "0xTakerToken",
    "makingAmount": "2000000000000000",
    "takingAmount": "20000",
    "makerTraits": "0x...",
    "extension": "0x..."
  },
  "extension": "0x...",
  "feeConfig": {
    "feeTakerAddress": "0x3FDCB4AF7F9019f6F8b669790BDe93BBF91Bbcc0",
    "integratorFeeRecipient": "0x...",
    "protocolFeeRecipient": "0x...",
    "integratorFee": 200,
    "integratorShare": 0,
    "resolverFee": 0,
    "whitelistDiscount": 0,
    "whitelist": ["0x..."]
  }
}
```

Important rules:

1. sign the returned order values exactly
2. submit the returned `extension` exactly
3. do not replace `receiver`
4. do not regenerate `salt`
5. do not assume a fixed whitelist set; read `feeConfig.whitelist` from the actual build response

### 13. Salt and extension binding

The standard Fluxion build flow binds `salt` to the hash of the generated `extension`.

This is important because the backend verifies that relation on submit.

In practice, this means:

* if you edit `extension`, the old `salt` becomes invalid
* if you edit `salt`, the extension check breaks
* the safe flow is: **build -> sign -> submit without mutation**

### 14. Compute the order hash

The order hash is the EIP-712 hash of the signed order struct.

Example with `ethers`:

```ts
import { ethers } from "ethers";

const domain = {
  name: "Fluxion Limit Order Protocol",
  version: "4",
  chainId: 5000,
  verifyingContract: "0x11de6011345586785810e52448a44c6595eedc18"
};

const types = {
  Order: [
    { name: "salt", type: "uint256" },
    { name: "maker", type: "address" },
    { name: "receiver", type: "address" },
    { name: "makerAsset", type: "address" },
    { name: "takerAsset", type: "address" },
    { name: "makingAmount", type: "uint256" },
    { name: "takingAmount", type: "uint256" },
    { name: "makerTraits", type: "uint256" }
  ]
};

const message = {
  salt: BigInt(order.salt),
  maker: order.maker,
  receiver: order.receiver,
  makerAsset: order.makerAsset,
  takerAsset: order.takerAsset,
  makingAmount: BigInt(order.makingAmount),
  takingAmount: BigInt(order.takingAmount),
  makerTraits: BigInt(order.makerTraits)
};

const orderHash = ethers.TypedDataEncoder.hash(domain, types, message);
```

### 15. Sign the order

Example with `ethers`:

```ts
const signature = await wallet.signTypedData(domain, types, message);
```

The backend recomputes the order hash and verifies the signature against the maker address.

### 16. Submit an order

#### Endpoint

`POST /orderbook/v4.1/5000`

#### Request shape

```json
{
  "orderHash": "0x...",
  "signature": "0x...",
  "data": {
    "makerAsset": "0xMakerToken",
    "takerAsset": "0xTakerToken",
    "maker": "0xYourMakerAddress",
    "receiver": "0x3FDCB4AF7F9019f6F8b669790BDe93BBF91Bbcc0",
    "makingAmount": "2000000000000000",
    "takingAmount": "20000",
    "salt": "0x...",
    "extension": "0x...",
    "makerTraits": "0x..."
  }
}
```

#### Success response

```json
{
  "success": true
}
```

#### Submit-time checks performed by the backend

The backend checks at least these things:

* extension matches the expected fee configuration
* `salt` matches the generated extension hash rule
* order hash matches the submitted order data
* signature recovers to the maker address
* amounts are sane
* no duplicate order hash
* no duplicate signature
* maker has not exceeded the active-order cap
* maker has enough spendable collateral for active orders on that asset
