SpaceSeven NFT Marketplace
EVM + Concordium Indexer Drivers & a Shared TypeScript Marketplace Layer
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.
Indexer drivers for Ethereum and Concordium feeding the marketplace backend with signed protobuf events, plus the shared TypeScript marketplace layer — API clients, wallet adapters and a web3.js transaction layer — used by 4 separate Next.js marketplace apps, with the UI confirming transactions only when the indexed event arrives.
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
Shared Layer
Frontend
Platform
Challenges & Solutions
Two Chains, One Marketplace Backend
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.
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
Drivers retry on failure, so the same event can arrive twice — which would double-count a sale or a bid.
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
Marketplace contracts were redeployed several times across environments, and a restarted driver must neither miss nor re-scan months of blocks.
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
A wallet returning a transaction hash does not mean the sale or bid happened; the UI still had to feel immediate.
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.