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
/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.
{
"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
| Field | Type | Meaning |
|---|---|---|
type | enum | listed, sold, or cancelled. Nothing else is a v1 event. |
chain | enum | Lowercase chain slug. The same slug the API uses in collection ids. |
collection | string | EVM: the contract address, lowercase. Solana: the collection mint in base58, case preserved. |
tokenId | string | null | EVM only, as a decimal uint256 string — never a number, never hex. |
mint | string | null | Solana only: the asset mint, Core asset address, or cNFT asset id. |
standard | enum | erc721 / erc1155 on EVM; legacy / core / cnft on Solana. Determines how the asset moves, and on Solana whether the sale is one transaction or two. |
price | string | The seller ask in base units — what the seller receives. Fees are charged to the buyer on top of this, never deducted from it. |
currency | object | Explicit 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. |
marketplaceFee | string | null | Buyer-side platform fee in base units. Null when the source could not attribute it. |
royaltyAmount | string | null | Total royalty in base units. On Solana this is the intended total before any sub-rent-exempt legs are folded — see the Solana page. |
expiry | number | null | Listings only. Null means no expiry was recorded, not that the listing is eternal. |
orderId | string | The cross-system join key: Seaport orderHash on EVM, the listing id (lid) on Solana. |
tx | string | null | Null 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.
| Chain | Settlement layer | Listed | Sold | Cancelled |
|---|---|---|---|---|
| Solana | Custodial escrow wallet, server co-signed transfers | On-chain (escrow deposit + memo) | On-chain (payment/release txs + memos) | On-chain (escrow return + memo) |
| Ethereum, Base, Ink, Polygon, Abstract | OpenSea Seaport 1.5 / 1.6, off-chain signed orders | Not on-chain — API only | On-chain (Seaport OrderFulfilled + attribution) | Not on-chain — API only |
| ApeChain | Reservoir-routed | Not on-chain — API only | Not attributable on-chain — API only | Not on-chain — API only |
| EVM launchpad (primary market) | ExclusivoERC721 v3, our own bytecode | n/a (primary mint) | On-chain (Minted / ReservedMinted) | n/a |
An off-chain cancel does not invalidate the signature
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
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.
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.