Onchain, an NFT's life is a log stream: a mint is a Transfer from the zero address, a sale is a marketplace event like Seaport's OrderFulfilled riding in the same transaction as the transfer it settles. SQD serves those events decoded and keyed by topic0 across 225+ networks, the history you fold into ownership, collection, and sales feeds.
A mint is a Transfer from the zero address, and a sale is a marketplace event that rides in the same transaction as the transfer it settles. Rebuilt the naive way, reading those events back means paginating an archive node over eth_getLogs against per-call caps, then writing a separate decoder for each token standard and marketplace you cover. The events are all public already; the cost is in how you read them back.
An event's topic0 is the keccak256 hash of its signature, and both standards define exactly Transfer(address,address,uint256). A USDT payment and a Bored Ape changing hands emit the identical topic0 (the hash in the query below), so a filter on the hash alone cannot tell them apart.
What separates them is the topic count. ERC-20 leaves the amount unindexed: three topics, value in data. EIP-721 requires all three parameters indexed: four topics, tokenId in topic3, empty data. Counted live over 20 pinned blocks:
2,994 logs in the window share the Transfer topic0; only 43 are NFT movements. A feed filtered on the hash alone buries the collection activity in token payments; the four-topic test is the line. ERC-1155 sidesteps the collision with its own signatures but moves ids and amounts into data, singly or as parallel arrays, so the decoder changes even though the filter does not.
A mint is the same event with a fixed sender: a Transfer from the zero address. Pinned to a window from the mint of BAYC (0xbc4c...f13d):
topic1 is the zero address, so this is a mint; topic2 is the recipient (0x3df0…cc18); topic3 is the tokenId, 0x449 = BAYC #1097, minted at block 12,346,000 (2021-05-01) in 0xfeab…1fb3. The full 1,001-block window streams back 3,715 mints in one request; the same read over eth_getLogs is a pagination loop against per-call caps on an archive node, measured here.
A sale is not a separate data product; it is an event the marketplace contract emits in the same log stream as the transfer it settles. Seaport 1.6 (0x0000...b395) emits OrderFulfilled; one filter on that address and topic0 returns 2,035 fills over blocks 25,490,000 to 25,491,000. Pinned to a single block from that window:
The three logs that come back are one transaction, 0x48d4…9bb7: a sweep that filled three listings from collection 0x6c0d...8107, two sellers, one buyer. Decoded from each log's data field against the Seaport ABI:
Two things the event does not hand you. OrderFulfilled does not label which consideration leg is a marketplace fee and which is a royalty; attribution is by recipient address. And the ownership change is not in this log: it rides in the same transaction as three ERC-721 Transfer logs carrying the same token ids (2422, 3016, 2423), so price and ownership join on the transaction hash. A curated NFT-sales API makes both calls for you and covers only the venues it chose to parse; the log stream carries every venue that settles onchain, decoded on your side.
Where the data stops: the Portal serves the events and transactions the chain records. Token metadata (tokenURI, images, traits) lives at the URI the contract points to and is fetched downstream; floor prices are marketplace aggregates, not onchain events; and there is no current-owner or ownerOf-at-block lookup. Ownership at any block is a fold you run over the transfer history, per tokenId, last recipient wins.
An ERC-721 mint is a Transfer from the zero address, a burn is one to it, and a sale settles as a transfer between wallets. One topic-filtered query returns all three for any collection, from its deployment block to chain head, with the tokenId in topic3.
ERC-1155 emits TransferSingle and TransferBatch under their own signatures, with ids and amounts ABI-encoded in the data field rather than in topics. Both arrive in the same log stream as ERC-721 Transfers, so one indexer covers both standards.
A sale is a contract event: Seaport emits OrderFulfilled with the offer and consideration items, price legs included, in one log. Join it to the ERC-721 Transfer in the same transaction and you have the seller, the buyer, the token, and the price.
The same topic0-filtered query runs on Ethereum, Base, Arbitrum, Polygon, and every other supported EVM network; only the dataset name and the contract address change. A cross-chain collection feed is one integration, not one per chain.
The mints, transfers, and sales are all public events in one log stream; the difference is in the reading, and it compounds with every token standard and every marketplace.
See this on your own contracts
Tell us the chains and contracts you care about, and we will show you the query that returns them.
Swaps, liquidations, and the internal calls a log-only feed misses.
Decoded events and traces streamed into the warehouse you already run.
Pre-decoded onchain data for agents, over MCP or plain HTTP.
Address-keyed history: transfers, native and internal value, NFT moves.
Traces and state diffs, the execution footprint logs alone never show.
Private Portal. Dedicated. Validated. Managed. Tell us what you're building, we'll show you what it looks like on SQD.