Skip to content

ADR: EmProps Studio NFT Revival

Date: 2026-02-07 Status: Proposed Depends On: NFT Diamond Standard on ArbitrumDecision Makers: Architecture Team


Executive Summary

Restore full NFT capabilities in emprops-studio using the Diamond/Arbitrum infrastructure built for the Emerge miniapp. This replaces the legacy microservices architecture (~10 services) with the turbo monorepo's emprops-api + emprops-studio.

Success criteria: emprops-studio is fully operational as an NFT platform — creators can deploy collections, mint tokens, manage their marketplace presence, and collectors can discover and view NFTs. All powered by the Diamond/Arbitrum backend instead of the legacy Java API and blockchain syncers.


Context

What Exists Today

EmProps Studio already has ~80 NFT files (~12,600 LOC) — marketplace pages, mint buttons, collection management, publishing flows, contract clients, and wallet integration. This code was the core product when EmProps was an NFT platform. See Studio Code Inventory.

The problem: this UI is connected to a legacy backend consisting of:

  • emprops-api (Java/Spring) — marketplace REST API, still running
  • emprops-syncer-long-* — blockchain event watchers (Tezos, Ethereum, Base)
  • emprops-open-generator — polling-based token generation
  • emprops-puppeteer-api — p5.js/JS rendering
  • IPFS server — metadata storage

See Legacy Architecture for the full service map.

What Changes

The Emerge miniapp ADR builds:

  1. Diamond contracts on Arbitrum (factory + shared facets)
  2. NFT API endpoints in emprops-api (setup, deploy, generate, mint, metadata)
  3. Database schema updates (NFT fields on collection model)

This ADR takes that infrastructure and wires it into emprops-studio, replacing the legacy services.

What Gets Eliminated

Legacy ServiceReplaced By
emprops-api (Java) marketplace endpointsemprops-api (Node) NFT routes
emprops-syncer-long-* (all 4 syncers)Not needed — custodial mintTo means we know all mints
emprops-open-generator (polling)Job queue + ComfyUI workers (already built)
emprops-open-generator-curatedJob queue handles priority natively
IPFS serverGCS + CDN

emprops-puppeteer-api stays — still needed for p5.js/JavaScript rendering.


Decision

Architecture: Two-App Stack

┌──────────────────────────────────────────────────────┐
│  emprops-studio (Next.js)                             │
│                                                       │
│  Marketplace ←──── Collection CRUD ────→ Publishing   │
│  Token Detail      Collection Settings   Mint Flow    │
│  Profile Pages     Wallet Integration    Deploy Flow  │
└────────────────────────┬─────────────────────────────┘
                         │ All API calls

┌──────────────────────────────────────────────────────┐
│  emprops-api (Node)                                   │
│                                                       │
│  /nft/collections/setup     → Gemini LLM              │
│  /nft/collections/:id/deploy → Diamond on Arbitrum    │
│  /nft/collections/:id/generate → Job queue + ComfyUI  │
│  /nft/collections/:id/mint → mintTo on Diamond        │
│  /nft/collections/:id/metadata/:tokenId → GCS + CDN   │
│                                                       │
│  + existing collection CRUD, auth, projects, etc.     │
└──────────────────────────────────────────────────────┘

No syncers. No Java API. No IPFS. The studio talks to emprops-api, which talks to Arbitrum and GCS.

What Changes in the Studio

1. Blockchain Types

File: types/wallet.ts

Add "ARBITRUM" to Blockchain type. Add Arbitrum chain IDs (421614 Sepolia, 42161 mainnet).

File: apps/emprops-api/src/lib/collections.ts

Add "ARBITRUM" to Zod blockchain enum.

2. Contract Client

File: clients/contract-client.ts (1,275 LOC)

Add Diamond read functions for Arbitrum:

  • getArbitrumCollection(contractAddress) — read collection data from Diamond via viem
  • getArbitrumTokenMetadata(contractAddress, tokenId) — read tokenURI

Write operations (deploy, mint) go through the API — not direct contract calls. The platform wallet signs transactions server-side.

3. Mint Button

New: components/MintButton/ArbitrumMint.tsx

For the initial revival, this is a custodial mint button — it calls the API /nft/collections/:id/mint endpoint. The platform signs the transaction, not the user.

The existing MintButton/index.tsx router dispatches to this component when blockchain === "ARBITRUM".

Later: add user-signed minting via wagmi for users who want to pay gas directly.

4. Publish Collection Modal

Modify: components/PublishCollectionModal/index.tsx (267 LOC)

Add Arbitrum as a deployment target:

  1. User selects Arbitrum in blockchain selector
  2. Configures: max supply, royalty bps, royalty receiver
  3. Modal calls /nft/collections/:id/deploy
  4. Shows deployment progress (tx hash → contract address → Arbiscan link)

5. Marketplace Pages

Existing pages already work — they list collections from the API. The changes:

  • Marketplace browse: include Arbitrum collections in results
  • Collection detail: show Arbitrum-specific info (contract address, Arbiscan link)
  • Token detail: fetch metadata from /nft/collections/:id/metadata/:tokenId

6. Market Actions

Modify: components/MarketActions/index.tsx (100 LOC)

Currently Tezos-only (line 60 blockchain check). For Arbitrum:

  • Initial: "View on OpenSea" link (external marketplace)
  • Future: Native marketplace facet on Diamond

7. Collection Management

Modify: components/CollectionSettings/

For Arbitrum collections, show:

  • Contract address + Arbiscan link
  • Tokens minted / max supply
  • Mint status (active/paused/completed)
  • Pause/unpause minting (calls API → MintFacet)

8. Profile Pages

Existing pages at pages/profile/[address]/ — collections, sales, creations. Need to:

  • Include Arbitrum collections in queries
  • Show Arbitrum tokens with correct metadata
  • Link to Arbiscan for on-chain verification

API Endpoints Consumed by Studio

All of these are built as part of the Emerge miniapp ADR. The studio reuses the same endpoints:

EndpointStudio Usage
POST /nft/collections/setupCollection creation wizard (Gemini generates instruction set)
POST /nft/collections/:id/deployPublishCollectionModal deploys Diamond
POST /nft/collections/:id/generateGenerate token artwork
POST /nft/collections/:id/mintArbitrumMint button
GET /nft/collections/:id/metadata/:tokenIdToken detail page
GET /nft/collections/:id/tokensCollection items grid

No new API endpoints are needed. The studio is a client of the same API the miniapp uses.


Legacy Feature Restoration Roadmap

Features from the original Java emprops-api, mapped to the new system:

FeatureLegacy ImplementationRevival ApproachPriority
Collection CRUDJava endpointsAlready in turbo monorepoDone
Token mintingUser-initiated + syncer trackingCustodial mintTo via APIP1
Marketplace browseJava endpoints + platform API clientExisting studio pages + emprops-apiP1
Collection publishingStudio UI → Java APIStudio UI → emprops-api /nft/deployP1
Token metadataIPFSGCS + CDNP1
RoyaltiesOff-chain rates in Java APIOn-chain ERC-2981 (RoyaltyFacet)P1
Marketplace listingsJava SalesEntity + endpointsOpenSea links (v1), native facet (future)P2
Secondary sales trackingJava PrivateSalesControllerNot for v1 — add Ponder indexer laterP3
Floor/ceiling pricesJava ProjectController.statsOpenSea API or Ponder aggregationP3
Event audit trailJava EventEntityAPI event logging + chain events (Ponder)P3
Token trait filteringtoken_features tableMetadata attributes from GCS JSONP2
Profile pagesJava endpoints + studio pagesAlready in studio, add Arbitrum dataP1

Implementation Strategy

Prerequisites

The Emerge miniapp ADR must be complete:

  • Diamond contracts deployed on Arbitrum Sepolia
  • NFT API endpoints working in emprops-api
  • Database schema updated

Phase 1: Core Wiring (P1 features)

Connect the existing studio UI to the new API endpoints.

Files to modify:

FileChange
types/wallet.tsAdd ARBITRUM
clients/contract-client.tsAdd Diamond read functions
hooks/contract-client.tsAdd Arbitrum chain support
hooks/collections.tsSupport Arbitrum in publish flow
components/MintButton/index.tsxRoute ARBITRUM to ArbitrumMint
components/PublishCollectionModal/index.tsxAdd Diamond deployment flow
components/BlockchainSelector/Add Arbitrum option
components/CollectionSettings/Show Arbitrum collection state
components/MarketActions/index.tsxOpenSea link for Arbitrum
pages/tokens/emprops/[id]/[tokenId].tsxRender Arbitrum token metadata

Files to create:

FilePurpose
components/MintButton/ArbitrumMint.tsxCustodial mint button
hooks/diamond.tsDiamond-specific read hooks
lib/arbitrum.tsChain config + utilities
contracts/ethereum/diamond-factory.jsonDiamond Factory ABI
contracts/ethereum/diamond-collection.jsonDiamond facet ABIs

Phase 2: Enhanced Features (P2)

  • Token trait filtering from metadata attributes
  • Collection analytics (tokens minted, revenue)
  • Marketplace listing links (OpenSea integration)
  • Batch operations UI

Phase 3: Full Independence (P3)

  • Retire Java emprops-api completely
  • Add Ponder indexer for secondary market tracking
  • Add native marketplace facet to Diamond
  • Historical sales data and floor prices
  • Event audit trail from chain events

Consequences

Positive

  • Single stack: Everything in the turbo monorepo (Node + Next.js) — no Java, no microservices
  • Reuses existing UI: ~80 files of studio NFT code gets reconnected, not rewritten
  • Same API for all clients: Miniapp and studio share the same emprops-api endpoints
  • Better NFT system: Diamond upgradeability, Arbitrum gas costs, GCS metadata (updateable)
  • Eliminates ~6 legacy services: No syncers, no Java API, no IPFS, no polling generators

Negative

  • Tezos collections orphaned: Existing Tezos collections won't work with the new system without keeping legacy services
  • emprops-clients package: @stakeordie/emprops-clients was built for ERC721A/ERC1167 — needs replacement or bypass
  • Feature gap during transition: Some features (secondary sales, floor prices) won't exist until P3

Mitigations

  1. Keep legacy Tezos services running until all active Tezos collections are concluded
  2. Create Diamond-specific hooks directly in studio, bypassing emprops-clients
  3. Use OpenSea APIs/links as bridge for marketplace features until native facet is built

Success Criteria

  • [ ] Creators can deploy NFT collections to Arbitrum from emprops-studio
  • [ ] Marketplace browse shows Arbitrum collections alongside existing ones
  • [ ] Token detail pages render metadata from GCS/CDN correctly
  • [ ] Collection management (pause, settings) works for Arbitrum collections
  • [ ] Profile pages show Arbitrum tokens
  • [ ] Java emprops-api can be taken offline without breaking Arbitrum features
  • [ ] All existing Tezos functionality continues to work during transition

Released under the MIT License.