Skip to main content
This guide covers how to fetch and display commitment data for your sale, including total amounts committed, participant counts, and individual commitments. The commitment data API is public and does not require authentication, so you can display this information to all visitors.

Use cases

  • Display the total amount committed to your sale
  • Show the number of unique participants
  • List recent commitments to create a live activity feed
  • For auctions: show the current estimated clearing price

Using the React hook

The simplest way to fetch commitment data is with the useCommitmentData hook from @echoxyz/sonar-react.
import { useCommitmentData } from "@echoxyz/sonar-react";

function CommitmentStats({ saleUUID }: { saleUUID: string }) {
  const { loading, commitmentData, error } = useCommitmentData({
    saleUUID,
    pollingIntervalMs: 10000, // Poll every 10 seconds for updates
  });

  if (loading && !commitmentData) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>Error loading commitment data: {error.message}</p>;
  }

  if (!commitmentData) {
    return null;
  }

  return (
    <div>
      <p>Total Participants: {commitmentData.UniqueCommitmentCount}</p>
      <p>Total Committed: {commitmentData.TotalCommitmentAmount}</p>
    </div>
  );
}
The hook supports optional polling to keep the data fresh. If pollingIntervalMs is not provided, the data is fetched once when the component mounts. Reference docs for the useCommitmentData hook.

Formatting amounts

The TotalCommitmentAmount and individual commitment amounts are returned as strings in the payment token’s smallest unit (e.g. USDC has 6 decimals, so the smallest unit is 1/1,000,000 of a USDC). Use PaymentTokenDecimals to format these values for display:
function formatAmount(amount: string, decimals: number): string {
  const value = BigInt(amount);
  const divisor = BigInt(10 ** decimals);
  const integerPart = value / divisor;
  return `$${integerPart.toLocaleString()}`;
}

// Usage
const formattedTotal = formatAmount(
  commitmentData.TotalCommitmentAmount,
  commitmentData.PaymentTokenDecimals
);

Displaying recent commitments

The Commitments array contains individual commitments sorted by creation time (most recent first). Each commitment includes:
  • SaleSpecificEntityID: The entity that made the commitment
  • CreatedAt: When the commitment was made (ISO 8601 timestamp)
  • Amounts: Array of amounts committed per wallet and payment token
import { useCommitmentData } from "@echoxyz/sonar-react";
import { Commitment, WalletTokenAmount } from "@echoxyz/sonar-core";

function calculateTotal(amounts: WalletTokenAmount[]): bigint {
  return amounts.reduce((sum, item) => sum + BigInt(item.Amount), BigInt(0));
}

function formatTimestamp(timestamp: string): string {
  return new Date(timestamp).toLocaleString(undefined, {
    month: "short",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit",
  });
}

function RecentCommitments({ saleUUID }: { saleUUID: string }) {
  const { commitmentData } = useCommitmentData({
    saleUUID,
    pollingIntervalMs: 10000,
  });

  if (!commitmentData) {
    return null;
  }

  // Show the 10 most recent commitments
  const recentCommitments = commitmentData.Commitments.slice(0, 10);

  if (recentCommitments.length === 0) {
    return <p>No commitments yet</p>;
  }

  // Note the commitments also include the price,
  // which you might also want to display for auction sales.
  return (
    <div>
      <h3>Recent Commitments</h3>
      <ul>
        {recentCommitments.map((commitment) => {
          const total = calculateTotal(commitment.Amounts);
          const formatted = formatAmount(
            total.toString(),
            commitmentData.PaymentTokenDecimals
          );
          return (
            <li key={commitment.CommitmentID}>
              {formatted} - {formatTimestamp(commitment.CreatedAt)}
            </li>
          );
        })}
      </ul>
    </div>
  );
}

function formatAmount(amount: string, decimals: number): string {
  const value = BigInt(amount);
  const divisor = BigInt(10 ** decimals);
  const integerPart = value / divisor;
  return `$${integerPart.toLocaleString()}`;
}

Auction clearing price

For English auction sales, the response includes the current estimated clearing price:
  • ClearingPriceNumerator and ClearingPriceDenominator: The clearing price as a fraction (in smallest units of the payment token per smallest unit of the offered token)
  • ClearingPriceMicroUSD: The clearing price in micro-USD (1 USD = 1,000,000 micro-USD) per human-readable offered token
The clearing price is recalculated as new bids come in and represents the price that all winning bidders would pay if the auction ended at that moment. The ClearingPriceMicroUSD field is convenient for display purposes, but may lose precision. For machine-readable use cases (e.g., passing to a contract or performing calculations), use the ClearingPriceNumerator and ClearingPriceDenominator fraction instead.
function AuctionClearingPrice({ saleUUID }: { saleUUID: string }) {
  const { commitmentData } = useCommitmentData({
    saleUUID,
    pollingIntervalMs: 5000, // More frequent polling during an auction
  });

  if (!commitmentData?.ClearingPriceMicroUSD) {
    return null;
  }

  // Convert micro-USD to dollars for display
  const priceInDollars = Number(commitmentData.ClearingPriceMicroUSD) / 1_000_000;

  return (
    <div>
      <p>Estimated Clearing Price: ${priceInDollars.toFixed(4)}</p>
    </div>
  );
}

Using the core library directly

If you’re not using React, you can call the API directly using SonarClient:
import { createClient } from "@echoxyz/sonar-core";

const client = createClient();

const commitmentData = await client.readCommitmentData({
  saleUUID: "YOUR_SALE_UUID",
});

console.log(`Total committed: ${commitmentData.TotalCommitmentAmount}`);
console.log(`Participants: ${commitmentData.UniqueCommitmentCount}`);
Reference docs for the readCommitmentData function.

API reference

For more details on the response format and available fields, see: