Skip to content

Quick Start Guide

This guide helps developers understand the NFT infrastructure and start contributing quickly.

System Overview

The NFT infrastructure consists of three main components:

┌────────────────┐     ┌────────────────┐     ┌────────────────┐
│  Smart         │     │  Blockchain    │     │  Frontend      │
│  Contracts     │ ──▶ │  Indexer       │ ──▶ │  (Studio)      │
│  (Hardhat)     │     │  (Ponder)      │     │  (wagmi/viem)  │
└────────────────┘     └────────────────┘     └────────────────┘
  1. Smart Contracts - ERC721A NFT contracts with factory pattern
  2. Blockchain Indexer - Ponder service that indexes events and provides API
  3. Frontend - React components using wagmi hooks for Web3 interactions

Repository Status

ComponentLocationStatus
Smart ContractsExternal repo (emprops-hardhat)Ready for integration
IndexerExternal repo (emprops-ponder)Ready for integration
Frontend Integrationapps/emprops-studioProduction (Tezos)

Target

These will be integrated into the monorepo as part of the Arbitrum launch.

Contract Architecture

Core Contracts

ContractPurposeType
NFTContractFactoryCreates new collectionsUpgradeable (UUPS)
Emerge_721Individual NFT collectionMinimal Proxy (ERC1167)

Deployment Flow

1. Platform calls NFTContractFactory.createNFTContract()

   ├─▶ Factory deploys Emerge_721 (minimal proxy)
   │   └─▶ Uses CREATE2 for deterministic address

   └─▶ Clone is initialized
       └─▶ Sets name, symbol, maxSupply, owner, baseURI

Why This Design?

  • Minimal proxies - Deploy collections for ~$0.50 on Arbitrum
  • CREATE2 - Same address on all EVM chains
  • UUPS upgrades - Factory can evolve; collections are immutable
  • Centralized minting - Users receive NFTs without gas costs

Indexer Architecture

Ponder watches blockchain events and provides:

REST API

bash
# List all collections
GET /api/apps

# Get collection details
GET /api/apps/:address

# List minting events
GET /api/app-token-mints/:address

WebSocket Events

typescript
// Real-time event streaming
socket.on('emprops:app:created', (data) => {
  // New collection deployed
});

socket.on('emprops:appToken:minted', (data) => {
  // NFT minted
});

Database Schema

TablePurpose
appsNFT collections (Emerge_721 instances)
app_tokensIndividual NFTs
app_token_mintsMinting events
app_token_transfersTransfer history
app_token_upgradesToken upgrade history

Frontend Patterns

Reading Collection Data

typescript
// Use indexer for lists (faster, cached)
const collections = await fetch('/api/apps');

// Use on-chain for critical data (authoritative)
const { data: mintPrice } = useReadContract({
  address: collectionAddress,
  abi: Emerge_721Abi,
  functionName: 'mintPrice'
});

Writing Transactions

typescript
const { writeContractAsync } = useWriteContract();

const mint = async (quantity: number) => {
  const hash = await writeContractAsync({
    address: collectionAddress,
    abi: Emerge_721Abi,
    functionName: 'mint',
    args: [BigInt(quantity)],
    value: mintPrice * BigInt(quantity)
  });

  // Wait for confirmation
  await waitForTransactionReceipt({ hash });
};

Real-time Updates

typescript
// Combine React Query with WebSocket for real-time UI
useEffect(() => {
  const socket = io(INDEXER_URL);

  socket.on('emprops:appToken:minted', () => {
    queryClient.invalidateQueries(['collection', address]);
  });

  return () => socket.disconnect();
}, []);

Development Workflow

Local Development Setup

Not Yet Integrated

These components are not yet in the monorepo. This workflow will be updated after integration.

  1. Start Hardhat Node (contracts)

    bash
    cd emprops-hardhat
    pnpm chain
  2. Deploy Contracts

    bash
    pnpm deploy:contracts --network localhost
    pnpm db:store-deployments
  3. Start Ponder (indexer)

    bash
    cd emprops-ponder
    pnpm dev
  4. Start Studio (frontend)

    bash
    cd apps/emprops-studio
    pnpm dev

Testing on Testnet

Current testnet deployments:

NetworkStatusContract Verification
Base SepoliaDeployedBasescan
Arbitrum SepoliaIn progress-

Key Files to Understand

Smart Contracts

FileDescription
contracts/NFTContractFactoryContract.solFactory that creates collections
contracts/Emerge_721Contract.solERC721A collection with upgrade support
deploy/00_app_factory.tsFactory deployment script

Indexer

FileDescription
ponder.schema.tsDatabase schema definition
ponder.config.tsContract configuration
src/handlers/Event processing logic
src/api/index.tsREST API endpoints

Frontend

FileDescription
(TBD after integration)wagmi configuration
(TBD after integration)Collection hooks
(TBD after integration)Minting components

Common Tasks

Deploy a New Collection

  1. Connect wallet
  2. Call NFTContractFactory.createNFTContract() with:
    • appType: keccak256("SIMPLE_APP_V1")
    • appId: Unique identifier
    • name: Collection name
    • symbol: Token symbol
    • initData: Encoded mint parameters

Mint an NFT

  1. Check collection status: paused, totalEditions, mintPrice
  2. Call Emerge_721.mint(quantity) with appropriate value
  3. Wait for transaction confirmation
  4. Token ID returned in event logs

Read Collection State

typescript
// From indexer (for lists, historical data)
const response = await fetch(`${INDEXER_URL}/api/apps/${address}`);
const collection = await response.json();

// From chain (for current state)
const mintPrice = await publicClient.readContract({
  address,
  abi: Emerge_721Abi,
  functionName: 'mintPrice'
});

Next Steps

Released under the MIT License.