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.

Chain-indexer network drivers for Ethereum and Concordium: per-contract block cursors seeded at each deployment block (backfill on cold start, resume on restart), contract events decoded into one chain-neutral protobuf event with 23 types, and HMAC-SHA256-signed delivery to the marketplace backend, which applies each event idempotently in the same transaction as the state change.

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

Platform

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

Frontend

Next.js 11React 17Redux ToolkitReact QuerySTOMP over WebSocket

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