Skip to content

External NFT Repositories

These repositories live outside the turbo monorepo. They were the attempt to move EmProps from a single monolithic contract (all collections in one contract) to a contract factory approach (one contract per collection). The scope ballooned and none of this work shipped to production.

The new Diamond/Arbitrum build solves the same problem — factory-deployed per-collection contracts — but scoped to a real use case first. Once battle-tested, it becomes what these repos were trying to be.

Repository Summary

RepositoryLocationStackCompletenessRole in New Architecture
emprops-hardhat~/code/emprops/nft_investigation/emprops-hardhatHardhat 2, Solidity 0.8.24, ERC721A~70%Reference only — Diamond replaces ERC1167 proxies
emprops-ponder~/code/emprops/nft_investigation/emprops-ponderPonder 0.9.17, Drizzle, PostgreSQL~60%Phase 6 — Add when secondary market needed
emprops-react-web3~/code/emprops/nft_investigation/emprops-react-web3React 18, Wagmi 2, RainbowKit 2~50%Reference — Patterns inform studio hooks
emprops-api (Java)~/code/emprops/core-services/emprops-apiJava, Spring Boot, GradleLegacyFeature spec — Documents marketplace capabilities
emprops-open-api~/code/emprops/emprops-open-apiNode.jsLegacyReference — Metadata patterns

1. emprops-hardhat (Smart Contracts)

Path: /Users/the_dusky/code/emprops/nft_investigation/emprops-hardhatStack: Hardhat 2.22.19, Solidity 0.8.24, OpenZeppelin 5.0.2, ERC721A 4.3.0, Viem 2.23.5

Contracts

ContractLOCDescription
OwnerTokenContract176UUPS upgradeable ERC721A for collection ownership tokens. Two-step minting: mint token, then assign controlled contract. Maps tokenId → contract address.
NFTContractFactoryContract272UUPS factory using ERC1167 Clones (minimal proxies). Deterministic CREATE2 deployment. Two modes: immediate and lazy. Registers implementations and initializers.
SimpleAppContract303Individual ERC721A NFT collection (minimal proxy). Owner-token-gated admin, configurable maxSupply/mintPrice/maxPerMint. Pausable, reentrancy protection, direct withdrawal.
SimpleAppInitializerContract65Initialization logic for SimpleApp parameters (maxSupply, mintPrice, maxPerMint, startDateTime). Factory-only access.
InterfacesIEmPropsApp, IAppInitializer, IOwnerToken, ISimpleApp, IEvents

Architecture Pattern

User creates collection
  → NFTContractFactory.createNFTContract()
    → Factory mints OwnerToken to user (ownership NFT)
    → Factory deploys SimpleApp (ERC1167 minimal proxy, CREATE2)
    → SimpleAppInitializer configures parameters
    → Collection live, user holds OwnerToken

Database Integration

Deployments stored in PostgreSQL (contract_deployments table) for cross-package coordination. Ponder reads contract addresses from this table.

Relevance to Diamond Architecture

emprops-hardhat ConceptDiamond Equivalent
OwnerToken (ownership NFT)OwnershipFacet (simpler, no separate NFT needed)
NFTContractFactory (ERC1167 clones)DiamondFactory (deploys Diamond proxies)
SimpleAppContract (ERC721A)ERC721AFacet + MintFacet + MetadataFacet
SimpleAppInitializerDiamond constructor init via diamondCut
CREATE2 deterministic addressesCREATE2 in DiamondFactory

Bottom line: The ERC721A base logic from SimpleAppContract is highly reusable as Diamond facet code. The factory pattern is conceptually the same but uses Diamond proxies instead of ERC1167 minimal proxies.

Full Documentation

See emprops-hardhat Documentation for complete contract details, deployment pipeline, database schema, and migration notes.


2. emprops-ponder (Blockchain Indexer)

Path: /Users/the_dusky/code/emprops/nft_investigation/emprops-ponderStack: Ponder 0.9.17, Drizzle ORM 0.39.3, PostgreSQL, Socket.io 4.7.4, Viem 2.21.3

Schema (8 tables)

TableDescription
ownerTokensOwner token records
ownerTokenTransfersOwner token transfer history
contractUpgradesContract upgrade events
appsCollection/app records
appTokensIndividual NFT token records
appTokenMintsMint event records
appTokenTransfersToken transfer history

Event Handlers (7 events)

EventHandler
AppFactoryContract:AppCreatedCreates app record in database
SimpleAppContract:TokensMintedRecords mints, creates token records
OwnerTokenContract:OwnerTokenMintedRecords owner token creation
SimpleAppContract:TransferToken transfer tracking
OwnerTokenContract:TransferOwner token transfer tracking
ProxyAdmin eventsContract upgrade tracking

All events are broadcast in real-time via Socket.io.

Relevance to Diamond Architecture

Ponder ConceptDiamond Equivalent
AppCreated eventCollectionCreated event from DiamondFactory
TokensMinted eventTransfer events from ERC721AFacet
Schema: apps → appTokensSame pattern: collections → tokens
Socket.io real-timeReusable unchanged

Bottom line: Schema design and event handler patterns are directly applicable. Rename App → Collection, update event signatures for Diamond contracts, and the indexer works. Not needed for Phase 1 since custodial minting means we track all data server-side. Add in Phase 6 for secondary market features.

Full Documentation

See emprops-ponder Documentation for complete schema, event handlers, API endpoints, and WebSocket setup.


3. emprops-react-web3 (React Integration Patterns)

Path: /Users/the_dusky/code/emprops/nft_investigation/emprops-react-web3Stack: React 18.3.1, Wagmi 2.0.0, RainbowKit 2.0.0, TanStack Query 5.0.0, Viem 2.0.0, Socket.io-client 4.8.1

Two-Adapter Architecture

This package demonstrates a clean separation between read and write operations:

┌─────────────────────────────────────────────────────┐
│                EmPropsProvider                        │
│  (wraps Wagmi + RainbowKit + QueryClient)            │
├──────────────────────┬──────────────────────────────┤
│    PonderAdapter     │       WagmiAdapter            │
│  (reads from Ponder) │  (writes via wallet signing)  │
│  ├─ HTTP API calls   │  ├─ Gas estimation            │
│  ├─ ABI management   │  ├─ Tx execution              │
│  └─ Socket.io subs   │  └─ Wallet connection         │
└──────────────────────┴──────────────────────────────┘

Hooks

HookTypeDescription
useEmPropsProviderAccess both PonderAdapter and WagmiAdapter
useEmPropsQueryReadReact Query + Socket.io auto-invalidation
useEmPropsTransactionWriteTransaction execution with status tracking
useGetSimpleAppsReadList collections from Ponder
useMintTokenWriteMint via wallet signing
useCreateSimpleAppWriteCreate collection via factory

Relevance to Diamond Architecture

PatternReuse Status
Two-adapter pattern (read/write separation)Excellent — directly applicable
React Query + Socket.io auto-invalidationProduction-ready pattern
EmPropsProvider (Wagmi + RainbowKit wrapper)Needs network parameterization (currently hardcoded to localhost:8545)
Transaction hooksInform studio hook design for Arbitrum

Bottom line: Architecture patterns are excellent reference material. The two-adapter pattern (reads from indexer, writes via wallet) is the right approach for Phase 5+ when user-signed transactions are added. For Phase 1 (custodial), writes go through the API instead of wallet.

Full Documentation

See emprops-react-web3 Documentation for complete provider setup, adapter patterns, and hook implementations.


4. emprops-api (Java — Legacy Marketplace Backend)

Path: /Users/the_dusky/code/emprops/core-services/emprops-apiStack: Java, Spring Boot, Spring Data JPA, Gradle Estimated Size: ~5,500+ LOC

Key Entities

EntityDescription
Project/CollectionCollection metadata, status, blockchain, pricing
TokenIndividual NFT with metadata, ownership, generation status
SalesMarketplace listings, purchases, pricing
EventsAudit trail of all platform actions
RoyaltiesRoyalty configuration per collection
ProfileUser profiles with wallet associations
Contract RegistryABI storage and contract address mapping

Key Capabilities (Feature Spec for Restoration)

FeatureEndpoint PatternRestoration Priority
Collection CRUD/api/projects/*Already in turbo monorepo
Token management/api/tokens/*Phase 2 (API endpoints)
Marketplace listings/api/sales/*Phase 5+ (OpenSea links first)
Secondary sales tracking/api/sales/private/*Phase 6 (Ponder indexer)
Floor/ceiling prices/api/projects/statsPhase 6
Event audit trail/api/events/*Phase 2 (API events)
Royalty configuration/api/royalties/*Phase 1 (RoyaltyFacet on-chain)
Profile management/api/profiles/*Already in turbo monorepo
Token trait filtering/api/tokens/featuresPhase 5 (metadata attributes)
Questionnaire-driven art/api/questionnaire/*Already exists as EmProps v2 variables

Bottom line: This is the feature spec — it documents everything the original marketplace could do. Most CRUD already exists in the turbo monorepo. Marketplace/sales features come later. On-chain features (royalties) are handled by Diamond facets.


5. emprops-open-api (Node.js — API Predecessor)

Path: /Users/the_dusky/code/emprops/emprops-open-apiStack: Node.js

Capabilities

  • Intermediary API between frontend and Java backend
  • Metadata management (token metadata JSON creation)
  • IPFS integration (pinning metadata and assets)
  • Collection rewards system
  • Generation endpoint routing

Relevance

Metadata patterns carried forward into the new GCS + CDN approach. The metadata JSON structure (name, description, image, attributes) follows the same ERC721 standard.

Bottom line: Reference for metadata patterns only. Functionality consolidated into apps/emprops-api in the turbo monorepo.


Migration Path Summary

Legacy Code                        →  New Diamond Architecture
─────────────────────────────────────────────────────────────────
emprops-hardhat contracts          →  Reference for Diamond facet code
emprops-hardhat factory            →  DiamondFactory replaces ERC1167
emprops-ponder indexer             →  Phase 6 (not needed for v1)
emprops-react-web3 patterns        →  Inform studio hook updates
emprops-api (Java) features        →  Feature spec for restoration
emprops-open-api metadata          →  GCS + CDN metadata pattern

Released under the MIT License.