Skip to content

ACTA-Team/dApp-ACTA

Repository files navigation

ACTA dApp

Web app to issue, store, verify, share, and revoke verifiable credentials on Stellar. It is the user-facing surface of ACTA: connect a Stellar wallet, register a did:stellar identity, and manage a single-tenant credential vault.

Overview

  • Connect a Stellar wallet (Freighter and others via Stellar Wallets Kit).
  • Register and resolve a did:stellar identity ("My DID").
  • Deploy your single-tenant vault and see its credentials with search.
  • Issue credentials (issuer identity is a registered did:stellar).
  • Share a credential with a public link, optionally attaching a zero-knowledge proof that validates a predicate without revealing private data.
  • Verify a credential's on-chain status, and revoke your own.
  • Manage issuer access: block or unblock specific issuers from your vault (issuance is open by default in the v0.4.0 deny-by-exception model).
  • Bilingual UI (English / Spanish / French).

Tech stack

  • Framework: Next.js 16 (App Router), React 19, TypeScript.
  • Styling: Tailwind CSS v4, Radix UI primitives, lucide-react icons.
  • Data: TanStack Query.
  • Stellar: @stellar/stellar-sdk, @creit.tech/stellar-wallets-kit for wallet connection and signing.
  • Identity: @acta-team/did-stellar for did:stellar parsing/resolution.
  • Backend: the ACTA REST API (prepare/submit XDR flow), called directly through src/lib/actaApi.ts. The dApp never holds private keys; the connected wallet signs every transaction.
  • ZK: Noir circuits verified client-side via bb.js.

Architecture (v0.4.0)

  • Each owner has their own single-tenant vault contract, deployed deterministically by the vc-vault-factory. The dApp addresses it by owner; the API derives the vault address.
  • The credential issuer is a resolvable did:stellar. The API enforces that the DID's on-chain controller matches the signer, so you can only issue under a DID you control.
  • Issuance fees are charged on-chain by the vault; the dApp does not set fees.

Prerequisites

  • Node.js 20 LTS or newer.
  • A Stellar wallet (e.g. Freighter) for signing.

Getting started

npm install
npm run dev

The app runs at http://localhost:3000/.

Configuration

Network is selectable in the UI (testnet / mainnet). The API base URL per network defaults to the hosted endpoints and can be overridden with env vars (create .env.local):

Variable Default
NEXT_PUBLIC_ACTA_API_BASE_URL_TESTNET https://api.testnet.acta.build
NEXT_PUBLIC_ACTA_API_BASE_URL_MAINNET https://api.mainnet.acta.build

An ACTA API key is created in-app (Dashboard -> API Keys) and stored per network in the browser; it is sent as the X-ACTA-Key header.

Issuing on a network requires a registered, resolvable did:stellar for that network (Dashboard -> My DID). Today did.acta.build registers DIDs on testnet; mainnet issuance needs the issuer DID registered on the mainnet registry first.

Scripts

Script What it does
npm run dev Start the dev server
npm run build Production build
npm run start Run the production server
npm run lint Run ESLint
npm run format Format with Prettier

Build and deploy

npm run build
npm run start

Deploys to any Node-compatible host (Vercel or a Node server). App Router handles static and dynamic routes.

Project structure

  • src/app - App Router pages and layouts.
    • dashboard/ - vault/credentials, issue, my DID, DID resolver, issuer access, API keys, notifications, settings.
    • credential/[id] - public credential page (share + verify).
  • src/components/modules - domain features.
    • vault/ - vault dashboard, credential detail, issuer access (block/unblock).
    • credentials/ - credential list, card, share modal, verify card.
    • issue/ - issuance builder and form.
    • did/ - did:stellar registration and resolver.
    • api-keys/, notifications/, settings/.
  • src/lib - actaApi.ts (API client), didStellar.ts, zk.ts, helpers.
  • src/providers - network, wallet, and app-wide context.
  • src/i18n - en / es / fr message catalogs.
  • public/zk - ACIR circuit JSON used for client-side proofs.

Zero-knowledge proofs

Credentials can be shared with an attached ZK proof that validates a predicate without revealing private fields. Proofs are generated and verified entirely client-side with Noir + bb.js.

  • Predicates: age >= 18 (isAdult), not expired (notExpired), status valid (isValid).
  • Share flow: pick the fields to reveal and a predicate, then generate the proof. The share payload carries only revealedFields, the statement (predicate + public params), and the proof / publicSignals.
  • Verify flow: the public credential page decodes the payload and shows the revealed fields; the ZK section stays hidden until the viewer clicks Verify Proof, at which point the proof is checked against the matching circuit via backend.verifyProof.
  • Circuits live in public/zk/ (noir_workshop.json, noir_not_expired.json, noir_valid_status.json); loading and proving are in src/lib/zk.ts.

Security

  • The dApp is non-custodial: it never stores private keys; the wallet signs.
  • Only explicitly selected fields are revealed when sharing; ZK private inputs are never shared.
  • Keep .env* files local and out of version control.

About

Verifiable credentials on Stellar with did:stellar identity.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages