> For the complete documentation index, see [llms.txt](https://docs.mangrove.exchange/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mangrove.exchange/dev/limit-orders.md).

# 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.
