Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Viewing Offers

Learn how to query and view offers from the Vif order book using vifdk.

Overview

The SDK provides functions to read offer data from the order book:

  • packedOfferList() - Get a list of offers from a market
  • packedBook() - Get aggregated price levels (book depth)
  • rawOffer() - Get a single offer by ID

These functions return contract call parameters that you use with viem's readContract.

Reading Offer Lists

Setup

import {
  Token,
  Market,
  packedOfferList,
  OfferList,
  packedBook,
  Book,
  rawOffer,
  Offer,
  offerOwner,
} from "vifdk";
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
 
const WETH = Token.from(WETH_ADDRESS, 18, "WETH", 1n);
const USDC = Token.from(USDC_ADDRESS, 6, "USDC", 1n);
 
const market = Market.create({
  base: WETH,
  quote: USDC,
  tickSpacing: 1n,
});
 
const client = createPublicClient({
  chain: mainnet,
  transport: http(),
});

Query Offers

Use packedOfferList() to get detailed offer data:

// Query offers from the asks market
const result = await client.readContract({
  address: VIF_READER_ADDRESS,
  ...packedOfferList(market.asks, 0, 100),
});
 
const [nextOfferId, offerIds, packedOffers, owners] = result;
 
// Create an OfferList from the results
const offerList = OfferList.fromPacked(
  market.asks,
  offerIds,
  packedOffers,
  owners
);
 
// Access individual offers
for (const offer of offerList.offers) {
  console.log("Offer ID:", offer.id);
  console.log(
    "Gives:",
    offer.data.gives.amountString,
    offer.data.gives.token.symbol
  );
  console.log("Tick:", offer.data.tick.value);
  console.log("Owner:", offer.owner);
}

Pagination

The fromId parameter allows pagination through large offer lists:

let fromId = 0;
const allOffers = [];
 
while (true) {
  const [nextOfferId, offerIds, packedOffers, owners] =
    await client.readContract({
      address: VIF_READER_ADDRESS,
      ...packedOfferList(market.asks, fromId, 100),
    });
 
  if (offerIds.length === 0) break;
 
  const offerList = OfferList.fromPacked(
    market.asks,
    offerIds,
    packedOffers,
    owners
  );
  allOffers.push(...offerList.offers);
 
  if (nextOfferId === 0) break;
  fromId = nextOfferId;
}

Reading a Single Offer

Use rawOffer() to get a specific offer by ID:

const offerId = 42;
 
// Query the offer
const packedOffer = await client.readContract({
  address: VIF_CORE_ADDRESS,
  ...rawOffer(market.asks, offerId),
});
 
// Get the owner
const ownerBigInt = await client.readContract({
  address: VIF_CORE_ADDRESS,
  ...offerOwner(market.asks, offerId),
});
 
// Cast to address
const owner = `0x${ownerBigInt.toString(16).padStart(40, "0")}` as Address;
 
// Create Offer instance
const offer = Offer.fromPacked(market.asks, packedOffer, offerId, owner);
 
console.log("Gives:", offer.data.gives.amountString);
console.log("Received:", offer.data.received.amountString);
console.log("Tick:", offer.data.tick.value);

Reading Book Depth

Use packedBook() to get aggregated price levels:

// Query book depth
const [nextPricePoint, packedElements] = await client.readContract({
  address: VIF_READER_ADDRESS,
  ...packedBook(market.asks, 0, 100),
});
 
// Create Book instance
const book = Book.fromPacked(market.asks, packedElements);
 
// View price levels
for (const element of book.elements) {
  const price = Number(element.tick.price) / 2 ** 128;
  console.log("Price (raw):", price);
  console.log("Total available:", element.totalGives.amountString);
  console.log("Number of offers:", element.offerCount);
}

Simulating Orders

Once you have an offer list, you can simulate what an order would do:

// Get offers
const [, offerIds2, packedOffers2, owners2] = await client.readContract({
  address: VIF_READER_ADDRESS,
  ...packedOfferList(market.asks, 0, 100),
});
 
const offerList2 = OfferList.fromPacked(
  market.asks,
  offerIds2,
  packedOffers2,
  owners2
);
 
// Simulate buying 1 WETH
const result2 = offerList2.simulateOrder({
  amount: WETH.amount("1"),
  maxTick: market.asks.price(3600), // Don't pay more than 3600
});
 
console.log("Would receive:", result2.got.amountString, WETH.symbol);
console.log("Would spend:", result2.gave.amountString, USDC.symbol);
console.log("Fee:", result2.fee.amountString);

Filtering Offers

Filter offers by owner or other criteria:

import { createWalletClient } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const walletClient = createWalletClient({
  chain: mainnet,
  transport: http(),
  account: privateKeyToAccount(privateKey),
});
 
const [, offerIds3, packedOffers3, owners3] = await client.readContract({
  address: VIF_READER_ADDRESS,
  ...packedOfferList(market.asks, 0, 1000),
});
 
const offerList3 = OfferList.fromPacked(
  market.asks,
  offerIds3,
  packedOffers3,
  owners3
);
 
// Get your offers
const myOffers = offerList3.offers.filter(
  (offer) => offer.owner === walletClient.account.address
);
 
// Get offers at specific price
const targetTick = market.asks.price(3500);
const offersAtPrice = offerList3.offers.filter(
  (offer) => offer.data.tick.value === targetTick.value
);
 
// Get offers with specific size
const largeOffers = offerList3.offers.filter(
  (offer) => offer.data.gives.amount >= WETH.amount("10").amount
);

Best Practices

  1. Use appropriate page sizes - 100 offers is usually sufficient
  2. Cache results - Order book data doesn't change every block
  3. Use Book for price quotes - Faster than loading all offers
  4. Use OfferList for simulations - More accurate than Book
  5. Handle pagination - Large markets may have thousands of offers

Next Steps