Market orders

A market order on Mangrove executes an immediate trade at the best available prices in the order book.

When you call the market order function (providing a market, limit price, and trade volume), Mangrove:

  • Takes your input tokens (the quote token if you’re buying, or base if you’re selling).

  • Matches them against existing offers in the book.

  • Returns the resulting tokens after execution.

This trade is the result of the consumption of the book obtained in Querying Data, adjusted for any changes between your last query and the transaction’s execution time.

Tip: You can set a slippage tolerance by adjusting the maximum acceptable price (tick). This helps protect against price movement between query and execution.

market order on mangrove

Giving allowance

Before trading, your wallet must approve Mangrove to spend your tokens. For testing or local development, it’s acceptable to grant infinite allowance, but for production use, you may wish to limit it to a specific amount.

src/allowance.ts
import { erc20Abi, maxUint128, maxUint256, type Address } from "viem";
import { client } from "./client";

// Check if the Mangrove contract has enough allowance for a token,
// and grant approval if needed.
export async function giveAllowanceIfNeeded(token: Address, spender: Address) {
  const allowance = await client.readContract({
    address: token,
    abi: erc20Abi,
    functionName: "allowance",
    args: [client.account.address, spender],
  });

  if (allowance < maxUint128) {
    const tx = await client.writeContract({
      address: token,
      abi: erc20Abi,
      functionName: "approve",
      args: [spender, maxUint256],
    });

    return client.waitForTransactionReceipt({
      hash: tx,
    });
  }
  return null;
}

Executing a Market Order

Once the allowance is set, you can:

  1. Retrieve the order book for your selected market.

  2. Simulate the trade locally to estimate the best achievable price (tick).

  3. Apply slippage tolerance.

  4. Broadcast the transaction to execute the trade.

A tick represents the logarithm (base 1.0001) of a price that is relative to each semi market.

  • Higher tick → worse price for the taker (better for maker).

  • Lower tick → better price for the taker.

See the Ticks, Ratios and Prices section to learn more about ticks.

Here is a complete example of placing a market order to buy 1 ETH:

src/market-order.ts
import { marketOrderSimulation } from "@mangrovedao/mgv";
import { giveAllowanceIfNeeded } from "./allowance";
import { getBook } from "./book";
import { mangroveConfig } from "./config";
import { getOpenMarkets } from "./markets";
import { BS, getSemibooksOLKeys } from "@mangrovedao/mgv/lib";
import { parseEther } from "viem";
import { marketOrderByTickParams } from "@mangrovedao/mgv/builder";
import { client } from "./client";

// 1. Get the availalbe markets
const markets = await getOpenMarkets();
const market = markets[0];
if (!market) {
  throw new Error("No market found");
}

// 2. Approve Mangrove to spend your quote token
const allowance = await giveAllowanceIfNeeded(
  market.quote.address,
  mangroveConfig.mgv
);

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

// 3. Retrieve the order book for the selected market
const book = await getBook(market);

// 4. Simulate the trade to determine the maximum tick (price)
const {
  // baseAmount, // should be at most 1 ETH
  // quoteAmount, // amount to send (assumed to have enough)
  // feePaid,
  maxTickEncountered,
  fillWants,
  fillVolume,
} = marketOrderSimulation({
  book,
  bs: BS.buy,
  base: parseEther("1"), // buy 1 ETH
});

// 5. Add slipage tolerance
const { asksMarket } = getSemibooksOLKeys(market);
const params = marketOrderByTickParams({
  maxTick: maxTickEncountered + 100n, // 1% slippage tolerance,
  fillVolume,
  fillWants,
  olKey: asksMarket,
});

// 6. Simulate and broadcast the on-chain market order
const {
  result: [takerGot, takerGave, bounty, feePaid], // result of onchain simulation
  request,
} = await client.simulateContract({
  address: mangroveConfig.mgv,
  ...params,
  account: client.account,
});

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

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

Next Steps

We can now move on to limit orders, where we learn to provide liquidity to the market instead of taking it.

Last updated