Architecture
Runtime architecture of the current Complyr codebase and how the major components interact.
Overview
Complyr is a monorepo with four runtime layers:
- a Next.js application in
apps/web; - Solidity contracts in
packages/contracts; - an Envio indexer in
packages/indexer; - a PostgreSQL store for app-owned records such as contacts.
The architecture is built around a simple division of responsibility:
- the web app handles user experience, wallet orchestration, and client-side encryption;
- the contracts are the source of truth for payments, intents, access control, and encrypted audit state;
- the indexer builds a derived activity feed from emitted events;
- PostgreSQL stores data that belongs to the app, not to the chain.
System diagram
┌──────────────────────────────────────────────────────────────────────┐
│ Next.js Web App │
│ Privy auth • ERC-4337 client • payment UI • records UI │
│ auditor portal • docs • contacts API • Zama browser encryption │
└───────────────┬───────────────────────────────┬──────────────────────┘
│ │
│ UserOperations, reads │ GraphQL queries
▼ ▼
┌──────────────────────────────────┐ ┌──────────────────────────────┐
│ Ethereum Sepolia │ │ Envio Indexer │
│ SmartWallet │ │ Wallet / Transaction / Intent│
│ SmartWalletFactory │ │ derived read model │
│ IntentRegistry │ └──────────────────────────────┘
│ AuditRegistry │
│ MockUSDC │
└───────────────┬──────────────────┘
│
│ app-owned data
▼
┌──────────────────────────────────┐
│ PostgreSQL via Drizzle ORM │
│ contacts and related records │
└──────────────────────────────────┘Core components
Web application
The web app is doing more than frontend rendering. It is the orchestration layer for the whole product.
Its main responsibilities are:
- authenticate users with Privy;
- deploy or reconnect the business smart wallet;
- submit single, batch, and recurring payment flows;
- encrypt audit inputs in the browser with the Zama SDK;
- load and decrypt audit records for authorized users;
- run the external auditor portal flow;
- manage contacts through server routes backed by PostgreSQL;
- host the docs site.
Key modules:
src/lib/SmartAccountProvider.tsxsrc/lib/customSmartAccount.tssrc/hooks/payments/*src/lib/fhe-audit.tssrc/hooks/useAuditLogs.tssrc/app/auditors/[proxyAccount]/AuditorsPortalClient.tsxsrc/lib/envio/client.ts
Smart contracts
The contracts form the product backend.
SmartWallet
The business treasury wallet is an ERC-4337 account.
It:
- validates user operations;
- executes direct and batch transfers;
- executes recurring transfers when called by the intent registry;
- records audit data alongside audited payment flows;
- rejects plain financial calls that bypass audit recording.
That last point is important. In the current design, the contract intentionally pushes users toward audited transfer methods.
SmartWalletFactory
The factory:
- deploys wallet clones;
- initializes wallet ownership;
- registers new wallets in
AuditRegistry; - can seed new wallets with testnet assets.
IntentRegistry
This contract manages recurring payment schedules.
It:
- stores intents;
- reserves committed wallet funds;
- exposes
checkUpkeepandperformUpkeepfor automation-style execution; - triggers wallet execution when an intent becomes due.
In the current codebase, recurring-payment audit data is written when the intent is created, not every time a later scheduled execution occurs.
AuditRegistry
This is the audit core of the protocol.
It:
- stores encrypted ledger entries;
- stores wallet-to-master ownership mappings;
- manages auditor approvals and access levels;
- maintains encrypted rollups for totals by recipient, category, and jurisdiction;
- stores encrypted private review tests and encrypted finding queues.
This contract is where most of the Zama-specific logic lives.
MockUSDC
Test token for the Sepolia demo environment.
Indexer
The Envio indexer materializes a read model for frontend activity.
Current indexed entities include:
WalletTransactionIntent
The indexer is useful for history and dashboards, but it is not the source of truth for encrypted audit data. That still comes from direct reads against AuditRegistry.
PostgreSQL
The app uses Drizzle with PostgreSQL for non-chain records.
The clearest active use today is the contacts subsystem:
- contacts;
- contact addresses;
- saved metadata that helps the payment UI prefill audit fields.
Data classification
Public onchain data
The current design leaves some values public on purpose:
- wallet addresses;
- recipient addresses;
- token addresses;
- transaction hashes;
- timestamps;
- plaintext reference IDs.
Encrypted onchain data
The following values are encrypted before they are committed:
- payment amounts stored in audit records;
- category values;
- jurisdiction values;
- auditor thresholds;
- auditor finding signals;
- encrypted rollup totals used for private analytics.
Primary flows
Wallet deployment
- The user signs in.
- The web app deploys or predicts a wallet through
SmartWalletFactory. - The wallet is registered in
AuditRegistry. - The app initializes the ERC-4337 client for later payment submission.
Single and batch payments
- The business enters payment and audit metadata.
- The browser encrypts the sensitive audit fields.
- The app submits a UserOperation.
SmartWalletexecutes the payment.SmartWalletrecords the encrypted audit entry inAuditRegistry.- Envio indexes the emitted events for the dashboard.
Recurring payments
- The business creates a recurring intent.
- The browser encrypts the audit metadata.
IntentRegistrystores the intent and locks committed funds.IntentRegistrywrites the audit record associated with that intent.- A later automation-compatible caller executes due payments through
performUpkeep. SmartWalletperforms the scheduled transfer batch.
Internal records view
- The business opens the records interface.
- The app reads audit records directly from
AuditRegistry. - The connected authorized wallet signs decryption authorization.
- The browser decrypts amounts, categories, and jurisdictions locally.
External auditor portal
- The business approves an auditor onchain.
- The auditor opens the shared portal URL.
- The portal checks authorization and access level directly onchain.
- The auditor creates encrypted review tests in the browser.
AuditRegistryevaluates those tests against encrypted records and rollups.- The auditor decrypts findings, analytics, and optionally the ledger depending on access.
Why the architecture is split this way
The split is deliberate:
- settlement and audit commitments belong onchain;
- derived activity views belong in the indexer;
- app-owned convenience data belongs in PostgreSQL;
- encryption and decryption authorization stay close to the user's wallet in the browser.
That architecture is what allows Complyr to behave like a real payments application while still showcasing private onchain auditing as its differentiating feature.