Import

import { useSellModal } from "@0xsequence/marketplace-sdk/react";
Sell Modal

Usage

The useSellModal hook provides a convenient way to manage the sell modal interface for accepting offers on collectibles. This modal is specifically used when a user wants to sell their collectible to an existing offer (bid) on the marketplace.
Make sure you have followed the Getting Started guide to get the collection address and chainId.

Basic Example

This example uses the useBalanceOfCollectible hook from marketplace-sdk to verify ownership before showing the sell modal.
import {
  useSellModal,
  useBalanceOfCollectible,
  useListOffersForCollectible,
} from "@0xsequence/marketplace-sdk/react";
import { useAccount } from "wagmi";
import type { Address } from "viem";
import type { Order } from "@0xsequence/marketplace-sdk";

export default function SellToOfferExample() {
  const { address: accountAddress } = useAccount();
  const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } =
    useMarketplaceConfig();

  const collection = marketplaceConfig?.market.collections[0];
  const chainId = collection?.chainId as number;
  const collectionAddress = collection?.itemsAddress as Address;
  // Replace with your collectible ID that has at least one offer
  const collectibleId = "0";

  // Check if user owns the collectible
  const {
    data: balance,
    isLoading: isLoadingBalance,
    isError: isErrorBalance,
  } = useBalanceOfCollectible({
    collectionAddress,
    collectableId: collectibleId,
    userAddress: accountAddress,
    chainId,
  });

  // Get available offers for this collectible
  const {
    data: offersData,
    isLoading: isLoadingOffers,
    error: offersError,
  } = useListOffersForCollectible({
    chainId,
    collectionAddress,
    collectibleId,
  });

  const { show: showSellModal } = useSellModal({
    onSuccess: ({ hash, orderId }) => {
      console.log("Sale completed successfully", { hash, orderId });
    },
    onError: (error) => {
      console.error("Sale failed:", error.message);
    },
  });

  const handleSellToOffer = (offer: Order) => {
    if (!balance || Number(balance) === 0) return;

    showSellModal({
      chainId,
      collectionAddress,
      tokenId: collectibleId,
      order: offer,
    });
  };

  const isOwner = balance && Number(balance) > 0;
  const isLoading = isLoadingBalance || isLoadingOffers;
  const hasError = isErrorBalance || offersError;
  const hasOffers = offersData?.orders && offersData.orders.length > 0;

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (hasError) {
    return <div>Error loading data</div>;
  }

  if (!isOwner) {
    return <div>You don't own this collectible</div>;
  }

  if (!hasOffers) {
    return <div>No offers available for this collectible</div>;
  }

  return (
    <div style={{ padding: "20px" }}>
      <h3>Available Offers</h3>
      <p>Collectible ID: {collectibleId}</p>
      <p>Your Balance: {balance}</p>

      <div style={{ marginTop: "16px" }}>
        {offersData.orders.map((offer) => (
          <div
            key={offer.orderId}
            style={{
              border: "1px solid #e0e0e0",
              borderRadius: "8px",
              padding: "16px",
              marginBottom: "12px",
              display: "flex",
              justifyContent: "space-between",
              alignItems: "center",
            }}
          >
            <div>
              <p>
                Price: {offer.priceAmount} {offer.priceCurrency?.symbol}
              </p>
              <p>From: {offer.createdBy}</p>
              <p>
                Expires:{" "}
                {new Date(offer.validUntil * 1000).toLocaleDateString()}
              </p>
            </div>

            <button
              onClick={() => handleSellToOffer(offer)}
              style={{
                backgroundColor: "#28a745",
                color: "white",
                border: "none",
                padding: "8px 16px",
                borderRadius: "4px",
                cursor: "pointer",
              }}
            >
              Accept Offer
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}

Parameters

The hook accepts an optional callbacks object with the following properties:
interface ModalCallbacks {
  onSuccess?: ({ hash, orderId }: { hash?: Hash; orderId?: string }) => void;
  onError?: (error: Error) => void;
  successActionButtons?: Array<{ label: string; action: () => void }>;
}
ParameterTypeDescription
callbacks.onSuccess({ hash, orderId }: { hash?: Hash; orderId?: string }) => voidOptional callback function called when the sale is completed successfully
callbacks.onError(error: Error) => voidOptional callback function called when an error occurs during the sale
callbacks.successActionButtonsArray<{ label: string; action: () => void }>Optional array of action buttons to show on success

Return Type

The hook returns an object with the following methods:
{
  show: (args: ShowSellModalArgs) => void
  close: () => void
}

Methods

show

(args: ShowSellModalArgs) => void Opens the sell modal with the specified parameters to accept an offer.
interface ShowSellModalArgs {
  collectionAddress: Address;
  chainId: number;
  tokenId: string;
  order: Order;
}
ParameterTypeRequiredDescription
collectionAddressAddressYesThe contract address of the collection
chainIdnumberYesThe blockchain network ID (e.g., 1 for Ethereum, 137 for Polygon)
tokenIdstringYesThe collectible ID of the collectible being sold
orderOrderYesThe offer order object containing price, buyer, and other details

close

() => void Closes the sell modal.

Notes

The useSellModal hook provides a convenient way to manage the sell modal interface for accepting offers on collectibles. It handles:
  • Opening and closing the modal
  • Managing the sale transaction flow state
  • Token approval steps (if required)
  • Transaction execution and signature steps
  • Error handling and success callbacks
  • Support for different marketplace types
  • Integration with WaaS (Wallet as a Service) fee options

Prerequisites

Before using this hook, ensure:
  1. User Authentication: The user must be connected with a wallet
  2. Ownership Verification: Use hooks like useBalanceOfCollectible to verify the user owns the collectible
  3. Valid Offer: Ensure there’s a valid offer (Order object) to accept