Skip to main content

Architecture

Certichain is a browser application in front of a small set of smart contracts, with a thin server beside it. This section explains how those parts are arranged, what each one is trusted with, and why. The other sections go deeper into each part: Smart contracts, Web application and Server and APIs.

PageWhat it covers
ContainersEvery runtime part (browser app, workers, server routes, contracts, wallets, RPC, IPFS, Redis), what it does, what it stores and how they talk.
Trust boundaries and dataWhere trust changes hands, which data crosses each boundary, and what each party has to trust.
Repository mapWhere everything lives in the repository today.
Contract versions and setsv0.2 against v0.3, versioned immutable contract sets, the manifest and routing between sets.
Key decisionsThe decisions that shaped the architecture, with links to the decision log.

Goals and constraints​

The architecture follows from a short list of requirements.

RequirementConsequence in the design
Anyone can verify, without an account, a wallet or trust in the operator.Facts that a verifier relies on live in public contracts. The verify page and the offline script read the chain directly.
No personal data on a public ledger.The chain holds commitments and hashes only. Names, student ids and documents stay in the holder's package and in encrypted containers.
An issuer's approval must be portable.Every credential carries the issuer's EIP-712 signature, so a package can be checked away from the website.
Nobody, including the operator, can quietly rewrite history.Anchors have no edit function. Status changes are events. Admin power sits behind a Safe, and a timelock is deployed for it.
Keep the operator's server small and replaceable.No application database. Lists are rebuilt from contract events in the browser. The server checks sign-in, pins encrypted files and, when configured, signs verification answers.
Change contracts without stranding issued credentials.Contracts are immutable. A change is a new set deployed next to the old ones, and every verification surface reads all listed sets.
Testnet first.Everything runs on Sepolia with synthetic data until an external audit.

Layers​

  • Pages compose services and never talk to a provider or a contract themselves (they use ethers only for input helpers such as address validation). Each page reads the services from one React provider (src/services/react/services-provider.tsx).
  • Services hold the rules of each domain. They depend on small interfaces (a gateway, a wallet, a log source), so tests swap in fakes from src/services/testing/.
  • src/lib is pure, side-effect-free code: hashing, commitments, typed data, the document container, the formats. The same code runs in the browser, in Node scripts and in the server routes, which is what keeps the TypeScript and Solidity digests identical.
  • Server helpers in src/lib/server/ are imported only by API routes, so server secrets never reach a client bundle.

The two paths through the system​

Almost every feature is a combination of a read path and a write path.

Read path (anyone, no wallet)​

Reads go through an RPC provider with failover across the configured URLs (src/lib/rpc/provider.ts). No wallet is needed, and the server is not involved.

Write path (a role holder with a wallet)​

The server only sees an encrypted container and the issuer's address. The chain only sees commitments, hashes and the signature. The browser holds the plaintext, the document key and the salts, and hands them to the holder in the package. The full step list is in Issuing a credential.

Where state lives​

StateLives inWritten byRead by
Issuers, names, roles, pause flag, key lineageIssuerRegistryAdmin, guardianEveryone
Credential anchors and signaturesCredentialRegistry storage and eventsIssuersEveryone
Status and its historyStatusRegistry storage and eventsIssuers, adminEveryone
Wallet to enrolment bindingsHolderRegistryStudents, through issuer invitationsIssuers, the app
Issuer-defined record typesRecordTypeRegistryIssuersEveryone
Access groups and receiptsCertichainAccessGate and SemaphoreHolders, issuers, requestersEveryone
Encrypted documentsIPFS, pinned by the serverIssuers (through the upload route)Holders and grantees with a key
Credential packages, disclosure files, grantsThe holder's deviceThe app, for the holderVerifiers the holder chooses
Phone wallet entriesIndexedDB on the phoneThe holderThe holder
Scan cachesBrowser storageThe appThe app
Sign-in nonces, rate limits, monitor historyRedis (memory store outside production)Server routesServer routes
Contract addresses per chainsrc/contracts/v03/deployment.<chainId>.jsonDeployment scriptsApp, scripts, server

Source files​

  • src/services/index.ts, src/services/react/services-provider.tsx
  • src/lib/rpc/provider.ts
  • src/contracts/v03/manifest.ts
  • blockchain/contracts/v03/
  • src/app/api/