# Limit Orders

Limit orders on Mangrove work by creating offers via a shared maker contract called **`MangroveOrder`**.\
Each user interacts with the system through their own User Router, a contract that holds token approvals and is called by `MangroveOrder` to transfer tokens when offers are matched.

In essence:

* You post an offer to buy or sell tokens at a defined price.
* Mangrove matches it when a counter party executes a trade that meets your conditions.
* The router handles token transfers securely on your behalf.

<figure><img src="/files/lQ04Ji5YT2GMEm55050y" alt=""><figcaption><p>creating an order (via MangroveOrder)</p></figcaption></figure>

#### Order Types

`MangroveOrder` supports four types of orders:

| Type                      | Description                                                                                    |
| ------------------------- | ---------------------------------------------------------------------------------------------- |
| GTC (Good Til Cancelled)  | Executes a market order up to a given price, then posts any remaining volume as a limit order. |
| IOC (Immediate or Cancel) | Executes as a market order; any unfilled portion is discarded.                                 |
| FOK (Fill or Kill)        | Executes only if the full order can be filled; otherwise reverts.                              |
| PO (Post Only)            | Posts directly to the order book without attempting immediate execution.                       |

> **Note:**\
> Each order can have an optional expiry date.\
> When creating an offer, you must deposit a [provision](/dev/protocol/technical-references/makers/offer-provisions.md) (a small amount of collateral).\
> If the offer later fails (e.g. missing approvals), this provision is used as a bounty for the executor.\
> You can withdraw any unused provision once the offer is no longer active.

The offer is consumed as follows:

<figure><img src="/files/xqj8HvsNu4YuVnvC9r3Z" alt=""><figcaption><p>consuming an offer (via Mangrove Order)</p></figcaption></figure>

#### Creating a User Router

Each user’s router is a deterministic address that is derived from their account.\
It’s automatically deployed during the first transaction that needs it. \
Before posting any order, you must grant approval to this router (even before it’s deployed).

{% code title="src/router.ts" lineNumbers="true" %}

```typescript
import type { Address } from "viem";
import { client } from "./client";

export async function getUserRouter(): Promise<Address> {
  return client.getUserRouter({
    user: client.account.address,
  });
}
```

{% endcode %}

> &#x20;For infinite approval logic, see [Market orders](/dev/market-orders.md).

## Creating a Limit Order

So let's take a look at an example where we create a Post Only limit buy order, buying 1 ETH with 2500 USDC:

{% code title="src/limit-order.ts" lineNumbers="true" %}

```typescript
import { limitOrderParams } from "@mangrovedao/mgv/builder";
import { giveAllowanceIfNeeded } from "./allowance";
import { getBook } from "./book";
import { mangroveConfig } from "./config";
import { getOpenMarkets } from "./markets";
import { getUserRouter } from "./router";
import { BS, Order } from "@mangrovedao/mgv/lib";
import { parseEther, parseUnits } from "viem";
import { client } from "./client";

// 1. Retrieve markets and select one
const markets = await getOpenMarkets();
const market = markets[0];
if (!market) {
  throw new Error("No market found");
}

// 2. Get the User Router address
const router = await getUserRouter();

// 3. Approve router to spend quote token
const allowance = await giveAllowanceIfNeeded(market.quote.address, router);

if (allowance) {
  if (allowance.status === "success") {
    console.log("Allowance given");
  } else {
    console.error("Allowance failed");
    process.exit(1);
  }
}

// 4. Get the current orderbook for this market
const book = await getBook(market);

// 5. Build the order parameters
const params = limitOrderParams(market, {
  orderType: Order.PO, // post only order
  baseAmount: parseEther("1"), // buy 1 ETH
  quoteAmount: parseUnits("2500", 6), // 2500 USDC
  restingOrderGasreq: 250_000n, // 250k gas (fixed)
  bs: BS.buy,
  book,
  // no expiry or expiry timestamp in seconds
  expiryDate: undefined, 
});

// 6. Simulate and execute the order
const {
  // takerGot, takerGave, bounty and fee should be 0 since PO
  // offerId should be defined (not 0)
  result: { takerGot, takerGave, bounty, fee, offerId, offerWriteData },
  request,
} = await client.simulateContract({
  address: mangroveConfig.mgvOrder,
  ...params,
  account: client.account,
});

const tx = await client.writeContract(request);
const receipt = await client.waitForTransactionReceipt({
  hash: tx,
});

console.log(receipt.status, receipt.transactionHash);
```

{% endcode %}

## Retracting a Limit Order

To cancel or modify a limit order, you'll need to have its `offerId`, as well as the market side (`BS.buy` or `BS.sell`).

{% code title="src/cancel-limit.ts" lineNumbers="true" %}

```typescript
import { removeOrderParams } from "@mangrovedao/mgv/builder";
import { BS } from "@mangrovedao/mgv/lib";
import { getOpenMarkets } from "./markets";
import { mangroveConfig } from "./config";
import { client } from "./client";

const markets = await getOpenMarkets();

const market = markets[0];
if (!market) {
  throw new Error("No market found");
}

// Build the parameters
const params = removeOrderParams(market, {
  offerId: 1n,
  bs: BS.buy,
  deprovision: true, // withdraw the provisions (true by default)
});

// Returns the withdrawn provision
const { result: provision, request } = await client.simulateContract({
  address: mangroveConfig.mgvOrder,
  ...params,
  account: client.account,
});

const tx = await client.writeContract(request);

const receipt = await client.waitForTransactionReceipt({
  hash: tx,
});

console.log(receipt.status, receipt.transactionHash);
```

{% endcode %}

## Modifying a Limit Order

In order to modify a limit order, any `updateOrder***Params` function may be used to build the modification, and then it should call `MangroveOrder` with those parameters.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mangrove.exchange/dev/limit-orders.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
