Skip to main content
Virtual offers let you trade PT on an orderbook that internally quotes everything in YT. When you set virtualOffer: true, the orderbook converts between PT and YT using strip and merge operations — no extra steps on your end.

Available Routes

All four routes share the same underlying liquidity:
RouteofferTypevirtualOfferDescription
SY → YTOfferType.BuyYtfalseExchange SY for YT
YT → SYOfferType.SellYtfalseExchange YT for SY
SY → PTOfferType.SellYttrueExchange SY for PT
PT → SYOfferType.BuyYttrueExchange PT for SY

How It Works

Strip (SY → PT + YT)

When you buy PT (virtual SellYt), the orderbook:
  1. Takes SY from you
  2. Strips SY into PT + YT
  3. Gives PT to you
  4. Uses the YT to fill against existing YT sell orders
You want: PT        You provide: SY

Orderbook executes:
  SY → Strip → PT + YT
  PT → You
  YT → Matches against SellYT orders

Merge (PT + YT → SY)

When you sell PT (virtual BuyYt), the orderbook:
  1. Takes PT from you
  2. Obtains YT from matched buy orders
  3. Merges PT + YT into SY
  4. Gives SY to you
You want: SY        You provide: PT

Orderbook executes:
  PT from you + YT from orderbook → Merge → SY
  SY → You

Direct YT Trading

Non-virtual orders trade YT directly against counter-orders — no strip or merge required.

Using Virtual Offers in the SDK

Pass virtualOffer: true when posting or executing PT orders:
import { OfferType, offerOptions } from "@exponent-labs/exponent-sdk";

// Post a virtual order to buy PT (SY → PT)
const { ix, setupIxs } = await orderbook.ixWrapperPostOffer({
  trader: wallet.publicKey,
  price: 5.0,
  amount: 1_000_000_000n,
  offerType: OfferType.SellYt,
  offerOption: offerOptions("FillOrKill", [false]),
  virtualOffer: true,
  expirySeconds: 3600,
  mintSy: syMintAddress,
});
Use getQuote with QuoteDirection.SY_TO_PT or QuoteDirection.PT_TO_SY to preview virtual order execution before submitting.