1/5
## Displaying Recent NFT Listings: The Need for Event Indexing Building a compelling frontend for a decentralized application (dApp), like an NFT marketplace, often involves displaying data derived from blockchain interactions. A common requirement is showing users the most *recently listed NFTs*. While seemingly straightforward, fetching this specific data efficiently from the blockchain presents a significant challenge. Imagine you have a React/Next.js component, perhaps named `RecentlyListedNFTs.tsx`, designed to display these NFTs. You might initially think about querying the smart contract directly. Your marketplace contract, `NftMarketplace.sol`, likely has a mapping (e.g., `s_listings`) storing details about each listed NFT. However, several problems arise with directly querying this state: 1. **Lack of Ordering:** Smart contract storage mappings are generally unordered and don't inherently track the *time* an item was added. There's often no built-in way to ask the contract, "Give me the 10 most recently added listings." 2. **Gas Inefficiency:** Even if you could design a complex function within the smart contract (like `getRecentlyListedItems()`) to iterate through storage, maintain timestamps, sort, and return a list, executing such a function would be extremely expensive in terms of gas fees. Smart contracts are optimized for transactional integrity and efficiency of *state changes* (writes), not complex, large-scale read operations. Developers intentionally keep on-chain logic lean to minimize user costs. So, if querying the contract's state directly is inefficient or impossible for this use case, how do we get the data? The answer lies in **blockchain events**. Your `NftMarketplace.sol` contract likely emits events when significant actions occur. Key events for our purpose include: * `ItemListed(address indexed seller, address indexed nftAddress, uint256 indexed tokenId, uint256 price)`: Emitted when an NFT is successfully listed. * `ItemCanceled(address indexed seller, address indexed nftAddress, uint256 indexed tokenId)`: Emitted when a listing is canceled. * `ItemBought(...)`: Emitted when an NFT is purchased (removing it from active listings). These events act like logs, signaling that a specific state change happened on the blockchain. They contain the crucial data associated with the action and implicitly carry timing information (via the block number or timestamp they are included in). This is where **Event Indexing** comes into play. Event indexing is the process of using an **off-chain** service to: 1. **Listen:** Continuously monitor the blockchain for specific events emitted by your smart contract (e.g., `ItemListed`, `ItemCanceled`, `ItemBought`). 2. **Process:** Interpret these events as they occur. For instance, an `ItemListed` event means a new NFT is available for sale, while `ItemCanceled` or `ItemBought` means a previously listed NFT is no longer available. 3. **Store:** Maintain the current state derived from these events in an optimized, readily queryable off-chain database. This database effectively holds the list of *currently active* NFT listings. **Conceptual Workflow:** * When an `ItemListed(sellerA, nftA, tokenId1, priceX)` event is detected, the indexer adds `{ seller: sellerA, nftAddress: nftA, tokenId: tokenId1, price: priceX }` to its "Active Listings" database table. * When an `ItemCanceled(sellerA, nftA, tokenId1)` event is detected, the indexer removes the corresponding entry for `nftA` and `tokenId1` from the "Active Listings" table. * The same removal logic applies when an `ItemBought` event occurs for that NFT. Your frontend (`RecentlyListedNFTs.tsx`) then queries this efficient **off-chain database** via an API provided by the indexing service, asking for the most recent entries. This query is fast and doesn't interact directly with the blockchain for the list data, providing a much better user experience. **A Common Pitfall: Inefficient Client-Side Event Fetching** It's tempting, especially when using libraries like `viem` or `ethers.js`, to try and fetch event logs directly within the frontend component. You might see code suggesting fetching *all* past events like this: ```typescript // Inside a useQuery hook's queryFn... (EXAMPLE OF INEFFICIENT APPROACH) const logs = await publicClient.getLogs({ address: marketplaceAddress, event: parseAbiItem('event ItemListed(...)'), fromBlock: 0n, // Fetch ALL events from the genesis block }); // ... then process potentially millions of logs client-side ... ``` **This approach is highly discouraged and fundamentally flawed for production applications.** Fetching the *entire history* of `ItemListed` events (potentially millions) from block zero directly in the user's browser every time the page loads is extremely inefficient. It would lead to: * Very long loading times ("waiting years" metaphorically). * High resource consumption in the user's browser. * Potential rate-limiting issues with your RPC provider. * Complex client-side logic to filter, sort, and cross-reference with `ItemCanceled` and `ItemBought` events to determine the *current* state. **The Correct Approach: Dedicated Indexing Solutions** Instead of fetching raw logs on the client, rely on dedicated event indexing solutions. These off-chain services are purpose-built to handle the complexities of: * Reliably ingesting blockchain events. * Processing event data according to defined logic. * Storing the derived state efficiently. * Providing a fast GraphQL or REST API for your frontend to query. While paid indexing services exist, there are also powerful, free, open-source solutions available that work excellently for both local development and production deployments. These tools bridge the gap between on-chain events and the performant data querying needs of modern dApp frontends. In summary, to efficiently display data like recently listed NFTs: 1. Leverage smart contract events (`ItemListed`, `ItemCanceled`, etc.) as the source of truth for state changes. 2. Implement an off-chain event indexing strategy. 3. Have your frontend query the indexed, processed data from the off-chain service, not the blockchain directly for large datasets or historical logs. 4. Avoid attempting to fetch and process extensive event histories directly within the client-side application.
A technical overview to displaying recent NFT listings: The need for event indexing. Discover the limitations and high costs associated with querying smart contract storage directly for ordered data like recent listings. Explore how event indexing offers an efficient off-chain alternative by processing emitted events to maintain queryable state for your frontend.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
How to build full-stack web3 applications on ZKsync
JavaScript/TypeScript: viem, wagmi, synpress
Nodejs and pnpm
rindexer
Circle Compliance Engine and USDC
Fleek site hosting and CLI
How to build a static and dynamic React/Next.js site
How to leverage AI to code faster and more securely
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Last updated on May 15, 2025
Solidity Developer
Full-Stack Web3 Development Crash CourseDuration: 1h 12min
Duration: 1h 39min
Duration: 3h 08min
Duration: 1h 44min
Course Overview
About the course
How to build full-stack web3 applications on ZKsync
JavaScript/TypeScript: viem, wagmi, synpress
Nodejs and pnpm
rindexer
Circle Compliance Engine and USDC
Fleek site hosting and CLI
How to build a static and dynamic React/Next.js site
How to leverage AI to code faster and more securely
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Last updated on May 15, 2025