COMPLYR LogoComplyr

Architecture

Runtime architecture of the current Complyr codebase and how the major components interact.

Overview

Complyr is a monorepo with four runtime layers:

  1. a Next.js application in apps/web;
  2. Solidity contracts in packages/contracts;
  3. an Envio indexer in packages/indexer;
  4. 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.tsx
  • src/lib/customSmartAccount.ts
  • src/hooks/payments/*
  • src/lib/fhe-audit.ts
  • src/hooks/useAuditLogs.ts
  • src/app/auditors/[proxyAccount]/AuditorsPortalClient.tsx
  • src/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 checkUpkeep and performUpkeep for 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:

  • Wallet
  • Transaction
  • Intent

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

  1. The user signs in.
  2. The web app deploys or predicts a wallet through SmartWalletFactory.
  3. The wallet is registered in AuditRegistry.
  4. The app initializes the ERC-4337 client for later payment submission.

Single and batch payments

  1. The business enters payment and audit metadata.
  2. The browser encrypts the sensitive audit fields.
  3. The app submits a UserOperation.
  4. SmartWallet executes the payment.
  5. SmartWallet records the encrypted audit entry in AuditRegistry.
  6. Envio indexes the emitted events for the dashboard.

Recurring payments

  1. The business creates a recurring intent.
  2. The browser encrypts the audit metadata.
  3. IntentRegistry stores the intent and locks committed funds.
  4. IntentRegistry writes the audit record associated with that intent.
  5. A later automation-compatible caller executes due payments through performUpkeep.
  6. SmartWallet performs the scheduled transfer batch.

Internal records view

  1. The business opens the records interface.
  2. The app reads audit records directly from AuditRegistry.
  3. The connected authorized wallet signs decryption authorization.
  4. The browser decrypts amounts, categories, and jurisdictions locally.

External auditor portal

  1. The business approves an auditor onchain.
  2. The auditor opens the shared portal URL.
  3. The portal checks authorization and access level directly onchain.
  4. The auditor creates encrypted review tests in the browser.
  5. AuditRegistry evaluates those tests against encrypted records and rollups.
  6. 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.

On this page