Back to Documentation Overview
Technical Architecture

System Architecture & Soroban Smart Contracts

CredChain is built natively on the Stellar Soroban WASM execution environment. Below is the visual component flow illustrating how client applications, wallet providers, Soroban RPC nodes, and smart contract ledgers interact seamlessly.

Component Flow Architecture
End-to-end data pipeline from user interface to Stellar ledger settlement.
1
Client Layer

Next.js UI & WalletKit

Connects user wallets (Freighter, Albedo, xBull) to construct XDR transaction payloads and handle user signatures.

2
Gateway Layer

Stellar Soroban RPC Node

Dispatches JSON-RPC requests (sendTransaction, getLatestLedger) and polls on-chain events.

3
Settlement Layer

Rust Soroban WASM Contract

Executes state checks, updates persistent storage with extend_ttl, and emits immutable ledger event logs.

Frictionless Execution: Verification queries run directly against the Soroban RPC gateway without requiring gas fees or wallet signatures.
1. Rust Soroban Smart Contract Design

The smart contract is written in Rust using the official soroban-sdk. It implements explicit state isolation and persistent storage extensions:

  • Storage TTL Extension: Soroban ledger entries are archived if left untouched. Every write invokes extend_ttl(5000, 10000) on the entry it touched, so active records stay live.
  • Checks-Effects-Interactions Pattern: Contract methods perform input validation and signature authentication before mutating storage or emitting events.
  • Checked Arithmetic: Protects against integer overflows and underflows during sequence or total count updates.
  • Admin Authority Transfer: Includes transfer_admin to allow smooth governance handovers without locking out institutions.
2. Web3 Error Decoder & Transaction Validity Windows

Web3 transactions often fail with cryptic XDR codes. CredChain integrates a centralized error decoder (error-decoder.ts):

  • Translates Soroban revert codes (1=NotRegistered through 6=InvalidInput) and Stellar Horizon errors into human-readable titles, codes, and remedies. The mapping is pinned by unit tests against the contract enum so the two cannot drift.
  • Expands transaction validity windows to 300 seconds to prevent tx_too_late expirations when users sign via hardware or extension wallets.
  • Provides global React Error Boundaries (error.tsx) and component-level diagnostic alerts (Web3ErrorAlert.tsx).
3. Self-Contained Credential Metadata

The contract stores only id, issuer, recipient, metadata_uri, issued_at, and revoked. Human-readable detail lives inside metadata_uri as a base64 data URI:

data:application/json;base64,...
{ "holder": "Ada Lovelace", "title": "BSc Computer Science" }

Verification therefore performs no external fetch — the whole credential is on the ledger. An HTTPS or IPFS pointer would instead make every verifier trust a host that could change or lose the content.

The issuer's name is deliberately absent from the payload. It is read from get_institution(issuer) on-chain, so whoever wrote the metadata cannot forge it. Credentials carrying a plain-string URI still verify; the page falls back to displaying the raw value.

4. Derived Reads: Registry & Activity History

The contract exposes no certificate list and no total counter, and adding one would require a redeploy — which mints a new address and abandons all existing state. The registry derives both instead, from two invariants:

  • Certificate ids are sequential from 1, since NextCertId only ever increments and nothing deletes.
  • revoke_certificate flips a flag but never decrements cert_count.

Together those make the sum of every institution's cert_count exactly the highest id in existence, so the registry can fetch ids 1..total with no probing. Reads are chunked to bound RPC fan-out.

The activity feed backfills the full RPC retention window on load, paging by cursor from the floor that getHealth reports. Because RPC retains roughly seven days of events, older account history is read from Horizon, which keeps far more.