Skip to main content
OTC (over-the-counter) is a direct trade negotiated between two known counterparties rather than discovered through a public route. In the SDK it’s a signed AugustusRFQ order, exposed under the sdk.otcOrders namespace: a maker signs the terms off-chain naming a specific taker, and only that taker can fill the order on-chain. Mechanically it’s a signed on-chain order whose defining field is the taker: you name the counterparty’s address, and only that address can fill the order: a private, fillable-by-one OTC trade (P2P).
This is for bilateral, counterparty-specific trades. For open, target-price orders that any solver can fill, use Limit orders (Delta) instead; those are gasless and MEV-protected. For the conceptual difference, see Product stack → OTC.

When to use this

  • The counterparty matters as much as the price: treasury rebalancing, partner deals, market-maker inventory moves.
  • You’ve agreed terms off-book and want a verifiable on-chain settlement restricted to the agreed counterparty.
  • You don’t want the trade exposed as a public order before it settles.

How it works

OTC has two sides. The maker builds and signs the order (gasless, off-chain). The taker (the named counterparty) submits the fill transaction on-chain through the AugustusRFQ contract.
1

Maker approves the maker asset

The maker approves AugustusRFQ to pull the asset they’re selling: sdk.otcOrders.approveMakerTokenForOTCOrder(makerAmount, makerAsset).
2

Maker signs and posts the order

The maker builds an order naming the intended taker, signs the EIP-712 typed data, and posts it: sdk.otcOrders.submitOTCOrder({ ...terms, taker }). Posting stays off-chain, so the maker pays nothing.
3

Taker approves the taker asset

The taker approves AugustusRFQ for the asset they’re paying with: sdk.otcOrders.approveTakerTokenForOTCOrder(takerAmount, takerAsset).
4

Taker fills on-chain

The taker submits the fill: sdk.otcOrders.fillOTCOrder({ order, signature }). AugustusRFQ verifies the signature and the named taker, then settles the swap.

Maker: build, sign, and post

const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";

// 1. Approve the asset the maker is selling
await sdk.otcOrders.approveMakerTokenForOTCOrder(
  "10000000000", // 10,000 USDC
  USDC,
);

// 2. Build, sign, and post in one call; `taker` is what makes it OTC
const order = await sdk.otcOrders.submitOTCOrder({
  maker: account,
  taker: counterparty, // the intended counterparty; only this address can fill
  makerAsset: USDC,
  takerAsset: ETH,
  makerAmount: "10000000000", // maker gives 10,000 USDC
  takerAmount: "3000000000000000000", // maker wants 3 ETH
  expiry: Math.floor(Date.now() / 1000) + 60 * 60 * 24, // 24h
});

// `order` carries the signed terms + signature; hand it to the taker
// (API, your backend, or any off-chain channel)
To split the steps (e.g. to sign with a hardware wallet), use sdk.otcOrders.buildOTCOrdersdk.otcOrders.signOTCOrdersdk.otcOrders.postOTCOrder.

Taker: fill the order

The taker receives the maker’s signed order, approves the asset they’re paying with, and fills on-chain:
// 1. Approve the asset the taker is paying with (skip for native ETH)
await sdk.otcOrders.approveTakerTokenForOTCOrder(
  order.takerAmount,
  order.takerAsset,
);

// 2. Fill directly against AugustusRFQ
const tx = await sdk.otcOrders.fillOTCOrder({
  order, // the maker's order data
  signature: order.signature, // the maker's signature
});
The fill reverts if the order is expired, already filled, or the caller isn’t the named taker, so always re-check expiry against the current block before submitting.

Query and cancel

// Maker: list your OTC orders
const mine = await sdk.otcOrders.getOTCOrders({ maker: account });

// Taker: list orders addressed to you
const forMe = await sdk.otcOrders.getOTCOrders({ taker: account });

// Maker: cancel an unfilled order on-chain
await sdk.otcOrders.cancelOTCOrder(orderHash);
Cancellation here is an on-chain call to AugustusRFQ, so it costs gas, unlike the gasless cancelDeltaOrders flow for Delta orders. sdk.otcOrders.getOTCOrdersContract() returns the AugustusRFQ address for the active chain; see Chains & contracts for all deployments.
Last modified on June 14, 2026