WrapHub is built as a product around the Zama Wrappers Registry. The architecture separates the public user experience, local protocol simulation, production faucet operations, and indexed activity so each part can evolve without blurring trust boundaries.
User wallet
|
| RainbowKit / wagmi / viem
v
Next.js frontend
|
|-- reads Zama Wrappers Registry on Sepolia
|-- reads token metadata, balances, allowances, claim status
|-- writes approve, wrap, unwrap, and faucet-owner transactions
|-- requests user-decryption through Zama SDK / relayer flow
|-- queries subgraphs for activity and token metrics
|
+-- Next.js API
|-- /api/faucet/claim submits gasless Sepolia claims
|-- /api/relayer/[chainId] proxies relayer requests when needed
wraphub/
frontend/
src/app Next.js routes and API routes
src/components Brand, wallet, and small UI primitives
src/config Chain, wallet, and environment configuration
src/features Product features and contract hooks
src/lib Shared utilities
hardhat/
contracts/faucet WrapHubFaucet
contracts/registry Mock registry for local development
contracts/tokens ERC-20 and ERC-7984 local mocks
deploy Local and Sepolia deployment scripts
tasks Faucet and account operator tasks
test Contract tests
subgraph/
schema.graphql Token activity and summary schema
src/mapping.ts Event mapping logic
subgraph*.yaml Sepolia and local manifests
docs/
*.md Public project documentation
The frontend is feature-based. Contract logic lives near the product flow that uses it, while shared UI components stay small.
frontend/src/features/registry/
abis.ts
components/
config/
official-pairs.ts
local-pairs.ts
hooks/
lib/
queries/
types.ts
Important boundaries:
src/appowns routes, metadata, API handlers, and providers.src/componentsowns reusable primitives only.src/configowns network, wallet, and environment resolution.src/features/registryowns registry data, pair pages, wrap, unwrap, decrypt, faucet-adjacent metadata, custom pairs, and maintainer tooling.src/libowns small reusable utilities such as address formatting, GraphQL clients, and wallet-write helpers.
WrapHub reads official pairs from Zama's onchain registry contract:
- Sepolia:
NEXT_PUBLIC_ZAMA_WRAPPERS_REGISTRY_SEPOLIA_ADDRESS
The registry read is canonical. Seed metadata in official-pairs.ts improves display quality and provides stable names while live metadata reads are loading.
Local pairs come from:
frontend/src/features/registry/config/local-pairs.ts- browser-local custom pairs created through
Add custom pair
Official and local pairs are merged into one typed model, but their source values stay separate:
Onchain registryLocal config
This prevents local development assets from being mistaken for official Zama registry assets.
WrapHub uses RainbowKit, wagmi, and viem.
- RainbowKit provides wallet selection.
- wagmi provides connection, account, chain, and React contract hooks.
- viem provides typed reads/writes and ABI-safe contract calls.
Registry browsing is public. Token actions use the connected wallet and active chain. When the wallet changes networks, WrapHub updates registry context and routes matching pair pages to the equivalent pair where possible.
The wrap flow reads:
- ERC-20 balance
- ERC-20 allowance
- wrapper rate
- network compatibility
If allowance is missing, WrapHub asks for approval before submitting the wrapper call. Transaction progress is shown only when a transaction is actually in progress or recently completed.
The unwrap flow submits the confidential unwrap request and finalization path required by the wrapper. It does not require revealing the private balance first. Revealing is a separate privacy action for the user to inspect their own balance.
Balance decrypt uses Zama user decryption. The connected wallet signs an EIP-712 authorization and the relayer flow returns the decrypted value only for the user's permitted balance handle. WrapHub masks the value again when the user clicks Hide balance.
The Sepolia faucet has two parts:
WrapHubFaucetcontract: controls token eligibility, claim amount, relayers, and cooldowns.- Next.js API relayer: submits
claimFor(account, token)so users do not need Sepolia ETH for faucet claims.
The contract first tries to mint the token to the user. If the token does not permit that mint path, the faucet transfers from its own inventory.
This gives two reliable production modes:
- mintable official mock token
- pre-funded faucet inventory
The frontend reads live balances and writes transactions directly through RPC. It does not scan logs in the browser.
The subgraph indexes activity:
- wraps
- unwrap requests
- unwrap finalizations
- confidential transfers
- Sepolia faucet claims
Token pages query the subgraph through graphql-request. Each network has its own endpoint so data stays scoped to the active pair chain.
/registry/maintainer is an allowlisted operator workspace. It helps the project maintainer prepare production coverage for official pairs:
- review official registry additions
- copy metadata snippets
- configure eligible Sepolia faucet tokens
- copy subgraph datasource snippets
- follow a release checklist
This route does not mutate Zama's official registry. Official status still comes only from Zama's onchain registry.
WrapHub includes:
- frontend type-check, lint, format, and build
- Solidity lint and format
- Hardhat contract tests
- subgraph codegen/build checks
- Husky pre-commit and pre-push hooks
- GitHub Actions CI
The expected full verification command is:
npm run check:prepush