On-chain

Event schema

One normalized shape for every marketplace event, from any chain and any source. This page also states plainly which of those events you can actually read from chain data today, and which you cannot.

What exists on-chain

Exclusivo runs no proprietary settlement contract on any chain. That single fact decides what is crawlable, so read it before you design an indexer:

  • EVM listings and cancels produce no transaction. A listing is an off-chain signed Seaport order held in our order book. Cancelling removes it from the order book; the signature itself is not cancelled on-chain. There is no log to crawl, and no amount of chain scanning will find one. The public API is the canonical feed for both.
  • EVM sales are fully crawlable from canonical Seaport logs, once you apply the attribution convention in EVM — Seaport attribution. This holds for orders created on or after 2026-07-26.
  • Solana is fully on-chain from 2026-07-26. Every list, sale, and cancel is a real transaction carrying a structured exclusivo:v1: memo — see Solana — memo format.

Do not infer EVM listings from chain data

If you build an EVM listing feed by scanning transactions, you will find nothing and conclude we have no listings. If you infer listings from approvals or transfers, you will invent listings that do not exist. Read /v1/collections/{id}/listings instead.

The normalized event

Every marketplace event — decoded from a Seaport log, a Solana memo, or read from the API — normalizes to the same object. Amounts are always integers in the currency's smallest unit, expressed as strings, so nothing depends on your JSON parser's float behaviour.

exclusivo.marketplace.event.v1
{
  "schema": "exclusivo.marketplace.event.v1",
  "type": "listed" | "sold" | "cancelled",
  "marketplace": "exclusivo",
  "chain": "solana" | "ethereum" | "base" | "ink" | "polygon" | "apechain" | "abstract",

  // Asset identity
  "collection": "<contract address (EVM, lowercase 0x) | collection mint (Solana, base58)>",
  "tokenId": "<uint256 decimal string (EVM) | null (Solana)>",
  "mint": "<asset mint / Core asset / cNFT asset id (Solana) | null (EVM)>",
  "standard": "erc721" | "erc1155" | "legacy" | "core" | "cnft",

  // Parties
  "seller": "<address>",
  "buyer": "<address | null>",

  // Economics — integers in base units, as decimal strings
  "price": "<seller ask>",
  "currency": {
    "kind": "native" | "erc20" | "spl",
    "address": "<0x0 for native EVM, token address for erc20, 'SOL' or SPL mint>",
    "symbol": "ETH" | "SOL" | "WETH" | "MATIC" | "APE",
    "decimals": 18 | 9
  },
  "marketplaceFee": "<base units | null>",
  "royaltyAmount": "<base units | null>",
  "royaltyRecipient": "<address | null>",

  // Lifecycle
  "expiry": "<unix seconds | null>",
  "orderId": "<Seaport orderHash (EVM) | listing id 'lid' (Solana)>",
  "tx": "<tx hash (EVM) | signature (Solana) | null>",
  "timestamp": "<unix seconds, block time>"
}

Field reference

FieldTypeMeaning
typeenumlisted, sold, or cancelled. Nothing else is a v1 event.
chainenumLowercase chain slug. The same slug the API uses in collection ids.
collectionstringEVM: the contract address, lowercase. Solana: the collection mint in base58, case preserved.
tokenIdstring | nullEVM only, as a decimal uint256 string — never a number, never hex.
mintstring | nullSolana only: the asset mint, Core asset address, or cNFT asset id.
standardenumerc721 / erc1155 on EVM; legacy / core / cnft on Solana. Determines how the asset moves, and on Solana whether the sale is one transaction or two.
pricestringThe seller ask in base units — what the seller receives. Fees are charged to the buyer on top of this, never deducted from it.
currencyobjectExplicit kind, address, symbol, and decimals. Do not infer decimals from the chain: an ERC-20 leg (WETH on accepted offers) is not the native asset.
marketplaceFeestring | nullBuyer-side platform fee in base units. Null when the source could not attribute it.
royaltyAmountstring | nullTotal royalty in base units. On Solana this is the intended total before any sub-rent-exempt legs are folded — see the Solana page.
expirynumber | nullListings only. Null means no expiry was recorded, not that the listing is eternal.
orderIdstringThe cross-system join key: Seaport orderHash on EVM, the listing id (lid) on Solana.
txstring | nullNull is legitimate: EVM listings/cancels and Solana recovery-path listings have no transaction.

Coverage per chain

This table is the honest version of "which events can I crawl". A cross means the action leaves no on-chain trace at all — not that it is hard to find.

ChainSettlement layerListedSoldCancelled
SolanaCustodial escrow wallet, server co-signed transfersOn-chain (escrow deposit + memo)On-chain (payment/release txs + memos)On-chain (escrow return + memo)
Ethereum, Base, Ink, Polygon, AbstractOpenSea Seaport 1.5 / 1.6, off-chain signed ordersNot on-chain — API onlyOn-chain (Seaport OrderFulfilled + attribution)Not on-chain — API only
ApeChainReservoir-routedNot on-chain — API onlyNot attributable on-chain — API onlyNot on-chain — API only
EVM launchpad (primary market)ExclusivoERC721 v3, our own bytecoden/a (primary mint)On-chain (Minted / ReservedMinted)n/a

An off-chain cancel does not invalidate the signature

Cancelling an EVM listing removes it from our order book, but we do not call Seaport's cancelOrders for listings. The signed order remains technically fillable on-chain until it expires. If you serve fillable orders to users, take your cancel state from the API — a listing absent from /v1 should be treated as cancelled even though the signature still verifies.

Join keys & normalization

orderId is the join key

On EVM, orderId is the Seaport orderHash emitted in OrderFulfilled. On Solana it is the listing id (lid) carried in the memo. The same lid appears on a listing's sale-payment memo, its release memo, and its cancel memo, which is what makes the two-transaction Core and compressed-NFT sale joinable.

Address casing

EVM addresses normalize to lowercase. Solana base58 addresses are case-sensitive — lowercasing one produces a different, invalid address. This is the single most common integration bug we see.

Amounts

Every amount is an integer string in base units (wei, lamports). USD conversion is an API-layer convenience and is never part of an event. Do not round-trip amounts through a JavaScript number.

Solidity event standard

Not yet emitted by anything

No deployed contract emits these events. There is no Exclusivo on-chain marketplace contract. If you write a decoder that expects ExclusivoSold today, it will match zero logs forever. Attribute EVM sales through the Seaport convention instead.

The interface below, defined in evm/contracts/IExclusivoMarketplaceEvents.sol, is the adopted contract-of-record: the day a thin on-chain component ships — an order registry, a real Seaport zone, or a settlement wrapper — it will emit exactly these events. We publish it now so integrators write one decoder rather than two.

IExclusivoMarketplaceEvents.sol
interface IExclusivoMarketplaceEvents {
    /// A token was listed for sale on Exclusivo.
    event ExclusivoListed(
        address indexed collection,
        uint256 indexed tokenId,
        address indexed seller,
        uint256 price,              // base units of `currency`, seller ask
        address currency,           // address(0) = chain-native
        uint256 marketplaceFee,     // base units, paid on top by the buyer
        uint256 royaltyAmount,      // base units, paid on top by the buyer
        address royaltyRecipient,
        uint256 expiry,             // unix seconds, 0 = none
        bytes32 orderHash           // Seaport order hash of the signed order
    );

    /// A listed token was sold on Exclusivo.
    event ExclusivoSold(
        address indexed collection,
        uint256 indexed tokenId,
        address indexed buyer,
        address seller,
        uint256 price,
        address currency,
        uint256 marketplaceFee,
        uint256 royaltyAmount,
        address royaltyRecipient,
        bytes32 orderHash
    );

    /// A listing was cancelled/delisted on Exclusivo.
    event ExclusivoCancelled(
        address indexed collection,
        uint256 indexed tokenId,
        address indexed seller,
        bytes32 orderHash
    );
}

The mapping to the normalized shape is one-to-one: currency == address(0) becomes { "kind": "native" }, buyer appears only on ExclusivoSold, and expiry only on ExclusivoListed.

Which source is authoritative

DataAuthoritative source
EVM listings and cancelsPublic API — there is no on-chain equivalent
ApeChain activity of any kindPublic API — Reservoir-routed, not attributable
History before 2026-07-26, all chainsPublic API — no memos, no zone marker
Solana recovery-path listingsPublic API — these listings have no transaction at all
EVM sales from 2026-07-26Chain — Seaport logs with our zone
Solana activity from 2026-07-26Chain — transactions with structured memos
Launchpad primary-market mintsChain — our own contract events

Where both sources exist they agree by construction: the API is written from the same normalized events. If you find a case where they disagree, that is a bug and we want to hear about it at dev@psukhe.media.