Back to Projects

SpaceSeven NFT Marketplace

EVM + Concordium Indexer Drivers & a Shared TypeScript Marketplace Layer

Overview

Role: Built the chain-indexer "network drivers" for Ethereum and Concordium and worked on the shared TypeScript marketplace layer. The Go marketplace backend (Fiber + sqlx) was built by another team.

What it is. A multi-chain NFT marketplace — ERC-721 and ERC-1155, fixed-price sales and auctions — on Ethereum and Concordium, with white-label copies for partner brands.

Indexer drivers. Chain watching lives outside the marketplace backend in one network driver per chain. Each driver follows the marketplace contracts from a per-contract block cursor seeded at the deployment block, so a cold start backfills and a restart resumes. It decodes contract events — mint, transfer, listing, sale, bid, pause, close — into one chain-neutral protobuf event (23 types) and pushes it to the backend over an HMAC-SHA256-signed endpoint. The backend applies each event idempotently, fingerprinting it in the same database transaction as the state change, so driver retries never double-count a sale or a bid.

Shared TypeScript layer. A versioned private npm package used by 4 separate Next.js marketplace apps: API clients, MetaMask/WalletConnect and Concordium wallet adapters behind one interface, and a transaction layer on web3.js with 10 operations across 4 lot types, resolving contract addresses at runtime from the drivers' contract set.

Closing the loop. The UI marks a transaction pending when the wallet returns a hash and flips it only when the indexed event comes back over STOMP, or times it out after 5 minutes — the indexed chain state is the source of truth, not the client receipt.

Key Features

  • Indexer network drivers for Ethereum and Concordium, outside the marketplace backend — a new chain is a new driver plus one enum value
  • Per-contract block cursors seeded at each deployment block: cold starts backfill, restarts resume, contract redeploys are a seed migration
  • ERC-721/1155 mint, transfer, listing, sale, bid, pause and close events decoded into one chain-neutral protobuf event (23 types)
  • HMAC-SHA256-signed delivery, applied idempotently by the backend in the same DB transaction as the state change
  • Shared TypeScript marketplace layer (private npm package) used by 4 Next.js apps: API clients, wallet adapters, web3.js transaction layer
  • Transactions confirmed by the indexer over STOMP, with a 5-minute timeout for dropped or replaced transactions

Tech Stack

Indexer Drivers

TypeScriptNode.jsEthereumConcordiumProtocol BuffersHMAC-SHA256

Shared Layer

TypeScriptweb3.jsWalletConnectMetaMaskConcordium walletPrivate npm

Frontend

Next.js 11React 17Redux ToolkitReact QuerySTOMP over WebSocket

Platform

Go + Fiber + sqlx backend (other team)PostgreSQLGitLab CI

Challenges & Solutions

Two Chains, One Marketplace Backend

Problem

The marketplace had to reflect state from two chains with very different models — EVM logs on Ethereum and contract indices on Concordium — without the backend talking to either chain.

Solution

One network driver per chain decodes contract events into a chain-neutral protobuf event and pushes it, HMAC-signed, to a single ingest endpoint. The backend never touches an RPC node, and adding a chain means a new driver plus one enum value.

Retries Without Double-Counting

Problem

Drivers retry on failure, so the same event can arrive twice — which would double-count a sale or a bid.

Solution

Each event is fingerprinted and inserted with ON CONFLICT DO NOTHING in the same database transaction as the state change, and processed only if the fingerprint was new: an exactly-once effect over at-least-once delivery.

Backfill Across Contract Redeploys

Problem

Marketplace contracts were redeployed several times across environments, and a restarted driver must neither miss nor re-scan months of blocks.

Solution

Each indexed contract has a cursor row seeded at its deployment block. A cold start backfills from deploy to head, a restart resumes from the cursor, and a redeploy is a migration that seeds the new addresses at their deploy block, safe to rerun.

Trusting the Indexer, Not the Wallet

Problem

A wallet returning a transaction hash does not mean the sale or bid happened; the UI still had to feel immediate.

Solution

The UI marks the transaction pending on the hash, subscribes to the token's STOMP channel and flips the status only when the indexed event arrives, with a 5-minute timeout for dropped or replaced transactions.

Key Achievements

2 Chains
Ethereum + Concordium indexer drivers
23 Event Types
Chain-neutral protobuf events, HMAC-signed
Idempotent Ingest
Retries never double-count a sale or a bid
4 Apps
Next.js marketplaces on one shared TypeScript layer