Skip to content

Repository files navigation

RWA Attestation Layer

Compliance Middleware for Real World Asset Tokenization

Solidity ERC-3643 License

A B2B decentralized attestation infrastructure for Real World Assets (RWA) built on Ethereum. This system enables trusted service providers to create attestations that other businesses can consume and verify, forming a shared trust layer for the RWA ecosystem.


🎯 Positioning

We are compliance middleware for RWAs — not a data oracle, not a general attestation service.

What We Are What We're NOT
Compliance layer for security tokens Chainlink alternative (price feeds)
Trust anchor for RWA documentation General-purpose attestation (like EAS)
ERC-3643 compatible identity registry KYC provider (we certify, not verify)
Economic security via staking/slashing Centralized compliance service

Target Market: RWA tokenization platforms, security token issuers, institutional DeFi.


🎯 What is This?

The RWA Attestation Layer is a trust and certification infrastructure — a notary layer for the blockchain ecosystem.

⚠️ Important Distinction: We do NOT perform verifications (KYC checks, property inspections, etc.). We attest that verifications done by authorized service providers are valid and anchor that proof on-chain.

┌───────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  Service Provider │     │  RWA Attestation │     │    Consumer      │
│    (Verifier)     │     │  Layer (Notary)  │     │   (DeFi, etc.)   │
├───────────────────┤     ├──────────────────┤     ├──────────────────┤
│                   │     │                  │     │                  │
│ Actually does     │────▶│ Certifies the    │────▶│ Trusts the       │
│ the verification  │     │ verification is  │     │ on-chain         │
│ (checks IDs,      │     │ valid & anchors  │     │ attestation      │
│  inspects props)  │     │ proof on-chain   │     │                  │
│                   │     │                  │     │                  │
└───────────────────┘     └──────────────────┘     └──────────────────┘
     VERIFIER               ATTESTER/NOTARY              CONSUMER

Think of us like a notary public — we don't write the document, we certify it's legitimate.

Businesses use this infrastructure to:

  • Certify verifications performed by authorized service providers
  • Anchor proof on-chain with document integrity via cryptographic hashes
  • Enable trust composability across the RWA tokenization ecosystem
┌─────────────────────────────────────────────────────────────────────────┐
│                         B2B ATTESTATION FLOW                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   ATTESTERS                      CONSUMERS                              │
│   (Service Providers)            (Business Clients)                     │
│                                                                         │
│   ┌─────────────────┐            ┌─────────────────┐                    │
│   │ KYC Providers   │            │ DeFi Protocols  │                    │
│   │ (Jumio, Onfido) │────┐  ┌────│ (Lending, DEXs) │                    │
│   └─────────────────┘    │  │    └─────────────────┘                    │
│                          │  │                                           │
│   ┌─────────────────┐    │  │    ┌─────────────────┐                    │
│   │ Title Companies │────┤  ├────│ RWA Tokenizers  │                    │
│   │ (First American)│    │  │    │ (RealT, Centri) │                    │
│   └─────────────────┘    │  │    └─────────────────┘                    │
│                          ▼  ▼                                           │
│   ┌─────────────────┐  ┌──────────────────┐  ┌─────────────────┐        │
│   │ Appraisal Firms │──│  RWA ATTESTATION │──│ Inst. Investors │        │
│   │                 │  │      LAYER       │  │ (Funds, DAOs)   │        │
│   └─────────────────┘  └──────────────────┘  └─────────────────┘        │
│                          ▲  ▲                                           │
│   ┌─────────────────┐    │  │    ┌─────────────────┐                    │
│   │ Insurance Cos   │────┤  ├────│ Compliance      │                    │
│   │                 │    │  │    │ Systems         │                    │
│   └─────────────────┘    │  │    └─────────────────┘                    │
│                          │  │                                           │
│   ┌─────────────────┐    │  │    ┌─────────────────┐                    │
│   │ Legal/Audit     │────┘  └────│ Real Estate     │                    │
│   │ Firms           │            │ Marketplaces    │                    │
│   └─────────────────┘            └─────────────────┘                    │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

💼 B2B Use Cases

How It Works

┌─────────────────────────────────────────────────────────────────────────┐
│                        ATTESTATION FLOW                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  1. SERVICE PROVIDER          2. ATTESTATION LAYER      3. CONSUMER     │
│     does verification            certifies it              uses it      │
│                                                                         │
│  ┌─────────────────┐         ┌─────────────────┐     ┌───────────────┐  │
│  │ KYC Provider    │         │                 │     │ DeFi Protocol │  │
│  │ checks user's   │────────▶│  Attests that   │────▶│ checks if     │  │
│  │ ID documents    │         │  KYC is valid   │     │ user has      │  │
│  └─────────────────┘         │                 │     │ valid KYC     │  │
│                              │   ON-CHAIN:     │     └───────────────┘  │
│  ┌─────────────────┐         │   - Hash anchor │                        │
│  │ Title Company   │         │   - Attester ID │     ┌───────────────┐  │
│  │ verifies        │────────▶│   - Expiration  │────▶│ Tokenization  │  │
│  │ property deed   │         │   - Schema ref  │     │ Platform      │  │
│  └─────────────────┘         │                 │     └───────────────┘  │
│                              │   OFF-CHAIN:    │                        │
│  ┌─────────────────┐         │   - Full doc    │     ┌───────────────┐  │
│  │ Appraiser       │         │   - IPFS stored │────▶│ Lender checks │  │
│  │ inspects &      │────────▶│   - Verifiable  │     │ collateral    │  │
│  │ values property │         │                 │     │ value         │  │
│  └─────────────────┘         └─────────────────┘     └───────────────┘  │
│                                                                         │
│     THEY DO THE WORK         WE CERTIFY IT          THEY TRUST IT       │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

For Service Providers (Verifiers → Attesters)

Service providers do the actual verification work, then use our platform to certify their findings:

Provider Type What They Verify What We Attest Business Value
KYC/AML Providers Check IDs, run sanctions screening "This KYC verification is valid" Portable KYC across DeFi
Title Companies Research deeds, verify ownership "This title is clear" On-chain title proof
Appraisal Firms Inspect & value properties "This valuation is certified" Trusted collateral values
Insurance Companies Underwrite policies "This coverage is active" Proof-of-insurance
Audit/Legal Firms Conduct audits, legal reviews "This entity is compliant" Verifiable compliance

For Consumers (Business Clients)

Business Type Attestations They Need Integration Benefit
DeFi Lending Protocols KYC, property title, appraisal Automate underwriting for RWA-backed loans
RWA Tokenization Platforms Title, appraisal, insurance Verify assets before tokenization
Institutional Investors KYC, compliance certs Meet regulatory requirements programmatically
Real Estate Marketplaces Title, appraisal, insurance Trust layer for property transactions
DAOs/Treasury Managers All attestation types Due diligence for RWA investments

Example: DeFi Lending Flow

┌─────────────────────────────────────────────────────────────────────────┐
│                     REAL-WORLD LOAN EXAMPLE                             │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  STEP 1: Verifications happen OFF our platform                          │
│  ════════════════════════════════════════════                           │
│  • Jumio verifies borrower's identity (KYC)                             │
│  • First American verifies property title                               │
│  • Licensed appraiser values the property at $500K                      │
│                                                                         │
│  STEP 2: Attestations created ON our platform                           │
│  ════════════════════════════════════════════                           │
│  • Jumio creates attestation: "User 0x123 passed KYC" (expires 6 mo)    │
│  • First American attests: "Property deed is clear"                     │
│  • Appraiser attests: "Property valued at $500K"                        │
│                                                                         │
│  STEP 3: DeFi protocol queries our attestations                         │
│  ════════════════════════════════════════════                           │
│                                                                         │
│    Protocol: "Can I lend to 0x123 against this property?"               │
│                              │                                          │
│                              ▼                                          │
│    ┌─────────────────────────────────────┐                              │
│    │  attestation.isValid(kycId)         │ ✓ KYC attested by Jumio      │
│    │  attestation.isExpired(kycId)       │ ✓ Not expired                │
│    │  getAttestation(titleId).attester   │ ✓ First American attested    │
│    │  getAttestation(appraisalId)        │ ✓ Value = $500K              │
│    └─────────────────────────────────────┘                              │
│                              │                                          │
│                              ▼                                          │
│    Loan approved: $350K (70% LTV of attested $500K value)               │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Key Point: The DeFi protocol trusts our attestations because:

  1. The attesters (Jumio, First American) are authorized on-chain
  2. The document hash matches (integrity verified)
  3. The attestation hasn't expired or been revoked

🌟 Overview

The RWA Attestation Layer provides a hybrid on-chain/off-chain architecture that:

  • Anchors document integrity on-chain via cryptographic hashes
  • Stores full attestation documents off-chain (IPFS/Pinata) for efficiency
  • Supports schema-based validation ensuring document structure compliance
  • Enables time-limited attestations with built-in expiration (e.g., 6-month KYC validity)
  • Provides role-based access control for authorized attesters per schema

🛡️ Trust Architecture

Economic Security (Staking & Slashing)

Attesters must stake ETH to participate. Fraudulent attestations result in slashed stakes.

┌─────────────────────────────────────────────────────────────────┐
│                    ECONOMIC SECURITY MODEL                      │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ATTESTER ONBOARDING                                            │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │ 1. Stake ETH (minimum required)                            │ │
│  │ 2. Get granted role for specific schema(s)                 │ │
│  │ 3. Can now create attestations                             │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                 │
│  IF ATTESTATION IS FRAUDULENT                                   │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │ 1. Anyone opens dispute (posts bond)                       │ │
│  │ 2. Dispute resolver investigates                           │ │
│  │ 3. If upheld: attester stake SLASHED (up to 50%)           │ │
│  │ 4. Attestation revoked                                     │ │
│  │ 5. Challenger bond returned + possible reward              │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                 │
│  WITHDRAWAL SAFEGUARDS                                          │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │ • 30-day initial lock period                               │ │
│  │ • 7-day withdrawal cooldown                                │ │
│  │ • Allows time to discover and dispute fraud                │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Trust Guarantees

Property Mechanism Result
Integrity Document hash on-chain Tamper-proof records
Accountability Attester identity recorded Reputation at stake
Economic Alignment Staking + slashing Cost of fraud > benefit
Dispute Resolution Bond-based challenges Community oversight
Compliance ERC-3643 integration Transfer restrictions enforced

See docs/THREAT_MODEL.md for full security analysis.

🏗️ Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        Off-Chain Layer                          │
├─────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐   ┌──────────────┐   ┌──────────────┐         │
│  │ JSON Schemas │   │  Attestation │   │    Schema    │         │
│  │  (Draft-07)  │   │  Documents   │   │  Validator   │         │
│  └──────┬───────┘   └──────┬───────┘   └──────┬───────┘         │
│         │                  │                  │                 │
│         └──────────────────┼──────────────────┘                 │
│                            │                                    │
│                     ┌──────▼───────┐                            │
│                     │ IPFS/Pinata  │                            │
│                     └──────┬───────┘                            │
└────────────────────────────┼────────────────────────────────────┘
                             │ CID / Hash
┌────────────────────────────┼────────────────────────────────────┐
│                        On-Chain Layer                           │
├────────────────────────────┼────────────────────────────────────┤
│                     ┌──────▼───────┐                            │
│                     │  Attestation │                            │
│                     │   Contract   │                            │
│                     └──────┬───────┘                            │
│                            │                                    │
│         ┌──────────────────┼──────────────────┐                 │
│         │                  │                  │                 │
│  ┌──────▼───────┐   ┌──────▼───────┐   ┌──────▼───────┐         │
│  │ SchemaRegistry│   │ AttesterRole │   │   Libraries  │        │
│  └──────────────┘   └──────────────┘   └──────────────┘         │
└─────────────────────────────────────────────────────────────────┘

📦 Project Structure

rwa-attestation-layer/
├── contracts/                    # Solidity smart contracts
│   ├── Attestation.sol           # Core attestation contract
│   ├── AttestationV2.sol         # Enhanced: delegation, disputes, indexing
│   ├── AttesterRole.sol          # Schema-scoped attester permissions
│   ├── AttesterStaking.sol       # Economic security: stake to attest
│   ├── RWASchemaRegistry.sol     # Schema registry with versioning
│   ├── RWACompliance.sol         # ERC-3643 security token integration
│   ├── interfaces/               # Contract interfaces
│   │   ├── IAttestation.sol
│   │   ├── IAttestationV2.sol
│   │   ├── IAttesterRole.sol
│   │   ├── ISchemaRegistry.sol
│   │   └── IERC3643Compliance.sol
│   └── libraries/                # Utility libraries
│       ├── HashUtils.sol         # Hashing helpers
│       └── SchemaValidator.sol   # On-chain validation
├── schemas/                      # JSON Schema definitions
│   ├── common-headers.json       # Shared attestation headers
│   ├── kyc.schema.json           # KYC/AML verification schema
│   ├── property.schema.json      # Real estate attestation schema
│   ├── appraisal.schema.json     # Property appraisal schema
│   └── insurance.schema.json     # Insurance attestation schema
├── sdk/                          # TypeScript SDK
│   └── src/
├── cli/                          # Command-line tools
│   └── src/
├── subgraph/                     # The Graph indexer
├── docs/                         # Documentation
│   ├── INTEGRATION.md            # Integration guide
│   ├── ATTESTER_GUIDE.md         # For attesters
│   └── THREAT_MODEL.md           # Security analysis
├── ipfs/                         # Off-chain tooling
│   ├── uploadAttestation.js      # Upload documents to IPFS
│   ├── verifyHash.js             # Verify on-chain vs off-chain hash
│   └── schema-validator.js       # JSON Schema validation
├── script/                       # Deployment scripts
│   ├── DeployAll.s.sol           # Full deployment
│   ├── DeployAttestation.s.sol
│   └── DeploySchemaRegistry.s.sol
├── test/                         # Test suites
│   ├── Attestation.t.sol
│   ├── AttesterRole.t.sol
│   ├── SchemaRegistry.t.sol
│   └── integrations/
│       └── EndToEndAttestationV2.t.sol
└── lib/                          # Dependencies (forge-std, OpenZeppelin)

🔧 Smart Contracts

Core Contracts

Attestation.sol

The main attestation contract that stores attestation records on-chain.

Key Features:

  • Create attestations with schema reference, subject, document hash, and optional URI
  • Support for time-limited attestations with expiresAt timestamp
  • Batch attestation and revocation (up to 50 per transaction)
  • Reference linking for attestation chains/history
  • Pausable operations for emergency scenarios

Data Structure:

struct AttestationRecord {
    bytes32 id;          // Unique attestation identifier
    bytes32 schemaId;    // Reference to registered schema
    address attester;    // Who created the attestation
    address subject;     // Who/what is being attested
    bytes32 docHash;     // Integrity hash of off-chain document
    string docURI;       // IPFS CID or URL for retrieval
    bytes32 refId;       // Optional reference to another attestation
    uint32 version;      // Document/schema version
    uint64 time;         // Creation timestamp
    uint64 expiresAt;    // Expiration timestamp (0 = never)
    bool revoked;        // Revocation status
    uint64 revokedTime;  // When revoked (0 if not revoked)
}

RWASchemaRegistry.sol

Registry for attestation schemas with versioning support.

Key Features:

  • Register schemas with hash and URI
  • Version management with monotonic incrementing
  • Activate/deactivate schemas
  • Role-based admin control

AttesterRole.sol

Schema-scoped role registry for authorized attesters.

Key Features:

  • Grant/revoke attester permissions per schema
  • OpenZeppelin AccessControl integration
  • Separate admin role for delegation

Libraries

HashUtils.sol

Lightweight hashing utilities:

  • keccakBytes() - Hash raw bytes
  • keccakString() - Hash UTF-8 strings
  • hashEnvelope() - Deterministic multi-field hashing

SchemaValidator.sol

Minimal on-chain validation helpers for basic invariant checks.

📋 Attestation Schemas

Schemas define the structure of off-chain attestation documents using JSON Schema (Draft-07).

Common Headers (common-headers.json)

Shared fields across all attestations:

  • attestationMeta: Schema ID, version, timestamps, references
  • attesterInfo: Attester address, name, credentials
  • subjectInfo: Subject identifier and type
  • signature: Cryptographic signature details

Available Schemas

Schema Description Default Validity
kyc.schema.json KYC/AML verification 6 months
property.schema.json Real estate property attestation N/A
appraisal.schema.json Property appraisal 1 year typical
insurance.schema.json Insurance coverage Policy period

KYC Schema Example

{
  "kyc": {
    "level": "enhanced",
    "status": "verified",
    "verifiedAt": "2026-01-15T10:30:00Z",
    "validUntil": "2026-07-15T10:30:00Z",
    "checks": {
      "identityVerified": true,
      "addressVerified": true,
      "amlScreening": "passed"
    }
  }
}

🛠️ Off-Chain Tooling

Upload Attestation (uploadAttestation.js)

Validates, hashes, and uploads attestation documents to IPFS via Pinata.

cd ipfs
npm install
node uploadAttestation.js --file my-kyc.json --schema kyc

Verify Hash (verifyHash.js)

Compares off-chain document hash with on-chain stored hash.

node verifyHash.js --attestation-id 0x... --contract 0x... --rpc https://...

Schema Validator (schema-validator.js)

Validates JSON documents against their schemas before upload.

import { validateDocument } from './schema-validator.js';

const result = await validateDocument(kycDoc, 'kyc.schema.json');
if (!result.valid) {
  console.error(result.errors);
}

🚀 Getting Started

Prerequisites

  • Foundry
  • Node.js 18+ (for IPFS tooling)
  • Pinata account (for IPFS uploads)

Installation

# Clone the repository
git clone https://github.com/your-org/rwa-attestation-layer.git
cd rwa-attestation-layer

# Install Foundry dependencies
forge install

# Install Node.js dependencies for IPFS tooling
cd ipfs && npm install && cd ..

Build

forge build

Test

forge test

Run Tests with Verbosity

forge test -vvv

Gas Snapshots

forge snapshot

Format Code

forge fmt

Local Development

Start a local Anvil node:

anvil

Deploy contracts locally:

forge script script/LocalMockSetup.s.sol --rpc-url http://localhost:8545 --broadcast

Deployment

Deploy to a network:

forge script script/DeployAttestation.s.sol \
  --rpc-url <RPC_URL> \
  --private-key <PRIVATE_KEY> \
  --broadcast \
  --verify

📝 Usage Flow

1. Register a Schema

bytes32 schemaId = keccak256("kyc.v1");
bytes32 schemaHash = keccak256(schemaJsonBytes);
string memory schemaUri = "ipfs://Qm...";

schemaRegistry.registerSchema(schemaId, schemaHash, schemaUri, 1);

2. Grant Attester Role

attesterRole.grantSchemaAttester(schemaId, attesterAddress);

3. Create Attestation Document

const kycDoc = {
  meta: { schemaId: "0x...", schemaVersion: 1, ... },
  attester: { address: "0x...", name: "KYC Provider" },
  subject: { identifier: "0x...", type: "ethereum-address" },
  kyc: { level: "enhanced", status: "verified", ... }
};

4. Upload to IPFS

const { cid, docHash } = await uploadAttestation(kycDoc, 'kyc');
// cid: "bafybeig..."
// docHash: "0x..."

5. Create On-Chain Attestation

bytes32 attestationId = attestation.attest(
    schemaId,           // Schema reference
    subjectAddress,     // Who is attested
    docHash,            // keccak256 of canonical JSON
    "ipfs://bafybeig...",  // Document URI
    bytes32(0),         // No reference
    1,                  // Version
    uint64(block.timestamp + 180 days)  // Expires in 6 months
);

6. Verify Attestation

const isValid = await verifyAttestation({
  attestationId: "0x...",
  contractAddress: "0x...",
  provider: ethersProvider
});

🔐 Security Considerations

  • Role-based Access: Only authorized attesters can create attestations for specific schemas
  • Document Integrity: Off-chain documents are integrity-verified via keccak256 hash anchoring
  • Expiration Support: Time-limited attestations prevent stale data usage
  • Pausable: Emergency pause functionality for all attestation operations
  • Revocation: Original attesters can revoke their attestations

� Business Model Opportunities

This infrastructure enables several B2B revenue models:

Model Description
Per-Attestation Fees Attesters charge for each verification issued
Subscription Access Consumers pay monthly for attestation queries
Revenue Sharing Protocol takes fee on attestation creation/verification
Enterprise Licensing White-label deployments for large institutions
Data Marketplace Aggregated anonymized attestation analytics

�📄 License

MIT License - see LICENSE for details.

🤝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

📚 Resources


🔬 Technical Deep Dive: How Everything Connects

This section explains every file in the project and how they work together.

System Overview

┌────────────────────────────────────────────────────────────────────────────────────────┐
│                              COMPLETE SYSTEM ARCHITECTURE                              │
├────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                        │
│  ┌─────────────────────────────────────────────────────────────────────────────────┐   │
│  │                           OFF-CHAIN LAYER (ipfs/)                               │   │
│  ├─────────────────────────────────────────────────────────────────────────────────┤   │
│  │                                                                                 │   │
│  │  ┌──────────────────┐    ┌──────────────────┐    ┌──────────────────┐           │   │
│  │  │ schema-validator │    │ uploadAttestation│    │   verifyHash     │           │   │
│  │  │       .js        │    │       .js        │    │      .js         │           │   │
│  │  ├──────────────────┤    ├──────────────────┤    ├──────────────────┤           │   │
│  │  │ Validates docs   │───▶│ Uploads to IPFS  │    │ Verifies on-chain│           │   │
│  │  │ against schemas  │    │ Returns CID+hash │    │ vs off-chain hash│           │   │
│  │  └──────────────────┘    └────────┬─────────┘    └────────▲─────────┘           │   │
│  │          │                        │                       │                     │   │
│  │          │ uses                   │ uploads to            │ fetches from        │   │
│  │          ▼                        ▼                       │                     │   │
│  │  ┌──────────────────┐    ┌──────────────────┐             │                     │   │
│  │  │ schemas/*.json   │    │  IPFS (Pinata)   │─────────────┘                     │   │
│  │  │ (JSON Schema)    │    │  Cloud Storage   │                                   │   │
│  │  └──────────────────┘    └────────┬─────────┘                                   │   │ 
│  │                                   │                                             │   │
│  └───────────────────────────────────┼─────────────────────────────────────────────┘   │
│                                      │ CID + docHash                                   │
│                                      ▼                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────────────┐   │
│  │                          ON-CHAIN LAYER (contracts/)                            │   │
│  ├─────────────────────────────────────────────────────────────────────────────────┤   │
│  │                                                                                 │   │
│  │                        ┌────────────────────────┐                               │   │
│  │                        │    Attestation.sol     │ ◄─── MAIN ENTRY POINT         │   │
│  │                        │   (Core Contract)      │                               │   │
│  │                        ├────────────────────────┤                               │   │
│  │                        │ • attest()             │                               │   │
│  │                        │ • batchAttest()        │                               │   │
│  │                        │ • revoke()             │                               │   │
│  │                        │ • isValid()            │                               │   │
│  │                        │ • getAttestation()     │                               │   │
│  │                        └───────────┬────────────┘                               │   │
│  │                                    │                                            │   │
│  │               ┌────────────────────┼────────────────────┐                       │   │
│  │               │                    │                    │                       │   │
│  │               ▼                    ▼                    ▼                       │   │
│  │  ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐           │   │
│  │  │ RWASchemaRegistry  │ │   AttesterRole     │ │    Libraries       │           │   │
│  │  │      .sol          │ │      .sol          │ │                    │           │   │
│  │  ├────────────────────┤ ├────────────────────┤ ├────────────────────┤           │   │
│  │  │ • registerSchema() │ │ • grantAttester()  │ │ • HashUtils.sol    │           │   │
│  │  │ • isActive()       │ │ • revokeAttester() │ │ • SchemaValidator  │           │   │
│  │  │ • schemaHash()     │ │ • isAuthorized()   │ │      .sol          │           │   │
│  │  └────────────────────┘ └────────────────────┘ └────────────────────┘           │   │
│  │                                                                                 │   │
│  └─────────────────────────────────────────────────────────────────────────────────┘   │
│                                                                                        │
└────────────────────────────────────────────────────────────────────────────────────────┘

📁 Smart Contracts (contracts/)

1. Attestation.sol - The Core Contract

Purpose: The main contract that stores and manages attestation records.

What it does:

Service Provider                    Attestation.sol                         Consumer
     │                                    │                                     │
     │  1. attest(schemaId, subject,      │                                     │
     │     docHash, docURI, ...)          │                                     │
     │───────────────────────────────────▶│                                     │
     │                                    │                                     │
     │                                    │  Validates:                         │
     │                                    │  ├─ Schema exists & active?         │
     │                                    │  ├─ Caller authorized for schema?   │
     │                                    │  ├─ Subject not zero address?       │
     │                                    │  └─ DocHash not empty?              │
     │                                    │                                     │
     │  2. Returns attestationId          │                                     │
     │◀───────────────────────────────────│                                     │
     │                                    │                                     │
     │                                    │  3. isValid(attestationId)?         │
     │                                    │◀────────────────────────────────────│
     │                                    │                                     │
     │                                    │  4. Returns true/false              │
     │                                    │─────────────────────────────────────▶│

Key Functions:

Function Who Calls It What It Does
attest() Authorized attesters Creates new attestation record
batchAttest() Authorized attesters Creates up to 50 attestations in one tx
revoke() Original attester only Marks attestation as revoked
isValid() Anyone (consumers) Returns true if: exists + not revoked + not expired
isExpired() Anyone Checks if past expiration timestamp
getAttestation() Anyone Returns full attestation record

Dependencies:

  • ISchemaRegistry → Checks if schema exists and is active
  • IAttesterRole → Checks if caller is authorized for the schema
  • Pausable → Emergency stop functionality
  • Ownable → Admin can pause/unpause

2. RWASchemaRegistry.sol - Schema Management

Purpose: Registry that tracks all valid attestation schemas.

Why it exists: Before anyone can create attestations, the schema must be registered. This ensures:

  • Only approved document types can be attested
  • Schema versions are tracked
  • Schemas can be deprecated

Data Stored:

struct SchemaRecord {
    bytes32 schemaHash;   // Hash of the JSON schema (integrity check)
    string schemaURI;     // IPFS link to the actual schema JSON
    uint64 createdAt;     // When registered
    uint32 version;       // Version number (1, 2, 3...)
    bool active;          // Can be deactivated to stop new attestations
}

How it connects:

Admin                     RWASchemaRegistry                    Attestation.sol
  │                              │                                   │
  │  registerSchema(             │                                   │
  │    schemaId,                 │                                   │
  │    schemaHash,               │                                   │
  │    schemaURI,                │                                   │
  │    version)                  │                                   │
  │─────────────────────────────▶│                                   │
  │                              │                                   │
  │                              │◀──────────────────────────────────│
  │                              │   exists(schemaId)?               │
  │                              │   isActive(schemaId)?             │
  │                              │──────────────────────────────────▶│
  │                              │   true/false                      │

3. AttesterRole.sol - Permission Management

Purpose: Controls WHO can create attestations for WHICH schemas.

Key Concept: Different schemas may have different authorized attesters:

Schema: "kyc.v1"      → Authorized: [Jumio, Onfido, Sumsub]
Schema: "property.v1" → Authorized: [FirstAmerican, Fidelity]
Schema: "appraisal.v1"→ Authorized: [LicensedAppraisers...]

How it works:

// Admin grants permission
attesterRole.grantSchemaAttester(
    keccak256("kyc.v1"),     // schemaId
    0x1234...                 // Jumio's address
);

// Later, when Jumio tries to attest:
// Attestation.sol calls:
attesterRole.isAuthorizedAttester(msg.sender, schemaId);
// Returns true only if msg.sender was granted role for that schema

Role Hierarchy:

DEFAULT_ADMIN_ROLE (OpenZeppelin built-in)
        │
        ▼
   ROLE_ADMIN ──────▶ Can grant/revoke schema attesters
        │
        ▼
ATTESTER_ROLE_{schemaId} ──────▶ Can create attestations for that schema

4. interfaces/ - Contract Interfaces

Purpose: Define the function signatures that contracts must implement.

Interface Defines Used By
IAttestation.sol Structs (AttestationRecord, AttestationRequest) + Events + Functions External integrations
ISchemaRegistry.sol SchemaRecord struct + Events + Functions Attestation.sol
IAttesterRole.sol isAuthorizedAttester() function Attestation.sol

Why interfaces matter:

// Attestation.sol doesn't care HOW these are implemented
// It just calls through the interface:
ISchemaRegistry public immutable SCHEMA_REGISTRY;
IAttesterRole public immutable ATTESTER_ROLE;

// This allows swapping implementations later

5. libraries/ - Utility Functions

HashUtils.sol:

// Used for hashing documents, URIs, etc.
HashUtils.keccakBytes(documentBytes);     // Hash raw bytes
HashUtils.keccakString("ipfs://...");     // Hash strings
HashUtils.hashEnvelope(...);              // Hash multiple fields together

SchemaValidator.sol:

// Basic on-chain validation (NOT full JSON schema validation - that's off-chain)
SchemaValidator.validateAttestationBasics(schemaId, docHash, version);
// Checks: schemaId != 0, docHash != 0

📁 JSON Schemas (schemas/)

Purpose: Define the STRUCTURE of off-chain attestation documents.

How Schemas Connect Everything:

┌─────────────────────────────────────────────────────────────────────────┐
│                         SCHEMA FLOW                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  1. DEFINE SCHEMA (off-chain)                                           │
│     schemas/kyc.schema.json                                             │
│     ┌─────────────────────────────────────┐                             │
│     │ {                                   │                             │
│     │   "kyc": {                          │                             │
│     │     "level": "enhanced",            │                             │
│     │     "status": "verified"            │                             │
│     │   }                                 │                             │
│     │ }                                   │                             │
│     └─────────────────────────────────────┘                             │
│                      │                                                  │
│                      ▼                                                  │
│  2. REGISTER SCHEMA (on-chain)                                          │
│     schemaRegistry.registerSchema(                                      │
│       schemaId: keccak256("kyc.v1"),                                    │
│       schemaHash: keccak256(schemaJsonBytes),  ◄── Integrity            │
│       schemaURI: "ipfs://Qm...",               ◄── Where to find it     │
│       version: 1                                                        │
│     )                                                                   │
│                      │                                                  │
│                      ▼                                                  │
│  3. VALIDATE DOCUMENT (off-chain)                                       │
│     schema-validator.js validates against kyc.schema.json               │
│                      │                                                  │
│                      ▼                                                  │
│  4. CREATE ATTESTATION (on-chain)                                       │
│     attestation.attest(schemaId, ..., docHash, ...)                     │
│     └── References the registered schema                                │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Schema Files Explained:

File Purpose Key Fields
common-headers.json Shared structure ALL attestations must have meta, attester, subject, signature
kyc.schema.json KYC verification structure kyc.level, kyc.status, identity, aml
property.schema.json Property title verification property, title, verification
appraisal.schema.json Property valuation appraisal, valuation, methodology
insurance.schema.json Insurance coverage policy, coverage, insuredAsset

Common Headers (every attestation has these):

{
  "meta": {
    "schemaId": "0x...",          // Links to on-chain schema
    "schemaVersion": 1,
    "createdAt": "2026-01-17T..."
  },
  "attester": {
    "address": "0x...",           // Who created this
    "name": "Jumio Inc"
  },
  "subject": {
    "address": "0x...",           // Who/what is being attested
    "type": "individual"
  }
}

📁 IPFS Tooling (ipfs/)

1. schema-validator.js - Pre-Upload Validation

Purpose: Validates documents against JSON schemas BEFORE uploading.

// Usage:
const result = await validateDocument('kyc', kycDocument);
// result: { valid: true/false, errors: [...] }

Flow:

Document JSON ──▶ Load Schema ──▶ AJV Validator ──▶ Valid? ──▶ Proceed to upload
                      │                                │
                      │                                └── If invalid, stop & show errors
                      │
                      └── Uses common-headers.json for shared fields

2. uploadAttestation.js - IPFS Upload

Purpose: Uploads validated documents to IPFS and returns the hash needed for on-chain attestation.

What it does:

Document JSON                uploadAttestation.js                    IPFS (Pinata)
     │                              │                                     │
     │  uploadAttestation(doc)      │                                     │
     │─────────────────────────────▶│                                     │
     │                              │                                     │
     │                              │  1. Canonicalize JSON               │
     │                              │     (sorted keys, no whitespace)    │
     │                              │                                     │
     │                              │  2. Compute keccak256 hash          │
     │                              │     docHash = keccak256(canonical)  │
     │                              │                                     │
     │                              │  3. Upload to Pinata                │
     │                              │─────────────────────────────────────▶│
     │                              │                                     │
     │                              │◀─────────────────────────────────────│
     │                              │  CID returned                       │
     │                              │                                     │
     │◀─────────────────────────────│                                     │
     │  { cid, docHash, uri }       │                                     │
     │                              │                                     │
     │  USE docHash in attest() call on-chain                             │

Critical Point: The docHash returned here is what you pass to Attestation.attest(). This links the on-chain record to the off-chain document.


3. verifyHash.js - Integrity Verification

Purpose: Consumers use this to verify an attestation is legitimate.

Verification Flow:

┌─────────────────────────────────────────────────────────────────────────┐
│                      VERIFICATION PROCESS                               │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Consumer wants to verify attestation 0xABC...                          │
│                           │                                             │
│                           ▼                                             │
│  ┌─────────────────────────────────────────────────────────┐            │
│  │ 1. Fetch on-chain attestation                           │            │
│  │    contract.getAttestation(0xABC...)                    │            │
│  │    Returns: { docHash: 0x123..., docURI: "ipfs://..." } │            │
│  └─────────────────────────────────────────────────────────┘            │
│                           │                                             │
│                           ▼                                             │
│  ┌─────────────────────────────────────────────────────────┐            │
│  │ 2. Fetch off-chain document from IPFS                   │            │
│  │    fetch(docURI) → JSON document                        │            │
│  └─────────────────────────────────────────────────────────┘            │
│                           │                                             │
│                           ▼                                             │
│  ┌─────────────────────────────────────────────────────────┐            │
│  │ 3. Compute hash of fetched document                     │            │
│  │    computedHash = keccak256(canonicalize(document))     │            │
│  └─────────────────────────────────────────────────────────┘            │
│                           │                                             │
│                           ▼                                             │
│  ┌─────────────────────────────────────────────────────────┐            │
│  │ 4. Compare hashes                                       │            │
│  │    computedHash === onChainDocHash ?                    │            │
│  │    ├─ YES → Document hasn't been tampered               │            │
│  │    └─ NO  → Document was modified! Don't trust it       │            │
│  └─────────────────────────────────────────────────────────┘            │
│                           │                                             │
│                           ▼                                             │
│  ┌─────────────────────────────────────────────────────────┐            │
│  │ 5. Additional checks                                    │            │
│  │    • Is attestation revoked? (r.revoked == false)       │            │
│  │    • Is attestation expired? (block.timestamp < expiry) │            │
│  └─────────────────────────────────────────────────────────┘            │
│                           │                                             │
│                           ▼                                             │
│                    ATTESTATION VALID ✓                                  │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

🔗 Complete Data Flow Example

Let's trace a KYC attestation from start to finish:

┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                    END-TO-END: KYC ATTESTATION LIFECYCLE                                │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                         │
│  PHASE 1: SETUP (One-time by Admin)                                                     │
│  ═══════════════════════════════════                                                    │
│                                                                                         │
│  1. Deploy contracts                                                                    │
│     RWASchemaRegistry deployed at 0xAAA...                                              │
│     AttesterRole deployed at 0xBBB...                                                   │
│     Attestation deployed at 0xCCC... (linked to above)                                  │
│                                                                                         │
│  2. Register KYC schema                                                                 │
│     schemaRegistry.registerSchema(                                                      │
│       keccak256("kyc.v1"),                // schemaId                                   │
│       keccak256(kycSchemaJson),           // schemaHash                                 │
│       "ipfs://QmKYCSchema...",            // schemaURI                                  │
│       1                                    // version                                   │
│     )                                                                                   │
│                                                                                         │
│  3. Authorize Jumio as attester for KYC                                                 │
│     attesterRole.grantSchemaAttester(                                                   │
│       keccak256("kyc.v1"),                // schemaId                                   │
│       0xJUMIO...                          // Jumio's address                            │
│     )                                                                                   │
│                                                                                         │
│  ─────────────────────────────────────────────────────────────────────────────────────  │
│                                                                                         │
│  PHASE 2: ATTESTATION CREATION (By Jumio)                                               │
│  ═════════════════════════════════════════                                              │
│                                                                                         │
│  4. Jumio verifies user's identity (OFF-CHAIN, their own systems)                       │
│     └── Checks passport, runs AML screening, etc.                                       │
│                                                                                         │
│  5. Jumio creates attestation document                                                  │
│     {                                                                                   │
│       "meta": { "schemaId": "0x...", "createdAt": "..." },                              │
│       "attester": { "address": "0xJUMIO", "name": "Jumio" },                            │
│       "subject": { "address": "0xUSER", "type": "individual" },                         │
│       "kyc": { "level": "enhanced", "status": "verified", ... }                         │ 
│     }                                                                                   │
│                                                                                         │
│  6. Validate document against schema                                                    │
│     validateDocument('kyc', document) → { valid: true }                                 │
│                                                                                         │
│  7. Upload to IPFS                                                                      │
│     uploadAttestation(document, 'kyc')                                                  │
│     → { cid: "bafybei...", docHash: "0xDOCHASH...", uri: "ipfs://bafybei..." }          │
│                                                                                         │
│  8. Create on-chain attestation                                                         │
│     attestation.attest(                                                                 │
│       keccak256("kyc.v1"),     // schemaId                                              │
│       0xUSER,                   // subject                                              │
│       0xDOCHASH,               // docHash (from step 7)                                 │
│       "ipfs://bafybei...",     // docURI                                                │
│       bytes32(0),               // no reference                                         │
│       1,                        // version                                              │
│       block.timestamp + 180 days // expires in 6 months                                 │
│     )                                                                                   │
│     → Returns attestationId: 0xATTEST...                                                │
│                                                                                         │
│  ─────────────────────────────────────────────────────────────────────────────────────  │
│                                                                                         │
│  PHASE 3: VERIFICATION (By DeFi Protocol)                                               │
│  ═════════════════════════════════════════                                              │
│                                                                                         │
│  9. DeFi protocol checks if user has valid KYC                                          │
│     attestation.isValid(0xATTEST...) → true                                             │
│                                                                                         │
│  10. Protocol fetches full details                                                      │
│      attestation.getAttestation(0xATTEST...)                                            │
│      → {                                                                                │
│          attester: 0xJUMIO,        // Trusted KYC provider                              │
│          subject: 0xUSER,          // The user                                          │
│          docHash: 0xDOCHASH,       // For integrity check                               │
│          docURI: "ipfs://...",     // To fetch full doc                                 │
│          expiresAt: 1752710400,    // July 2026                                         │
│          revoked: false                                                                 │
│        }                                                                                │
│                                                                                         │
│  11. Protocol verifies document integrity (optional deep check)                         │
│      verifyAttestation({                                                                │
│        attestationId: "0xATTEST...",                                                    │
│        contractAddress: "0xCCC...",                                                     │
│        rpcUrl: "https://..."                                                            │
│      })                                                                                 │
│      → { valid: true, hashMatch: true, notRevoked: true, notExpired: true }             │
│                                                                                         │
│  12. Protocol trusts the attestation and allows user to proceed                         │
│                                                                                         │
└─────────────────────────────────────────────────────────────────────────────────────────┘

📁 Other Files

File/Folder Purpose
foundry.toml Foundry configuration (compiler version, optimizer settings, etc.)
remappings.txt Solidity import path mappings (@openzeppelin/lib/openzeppelin-contracts/)
script/ Deployment scripts for Forge
test/ Foundry test files (.t.sol)
lib/ Git submodules: forge-std, openzeppelin-contracts
ipfs/pinata.config.json IPFS gateway and API configuration
ipfs/package.json Node.js dependencies for off-chain tools

Contract Dependency Graph

                              ┌─────────────────┐
                              │   Attestation   │
                              │      .sol       │
                              └────────┬────────┘
                                       │
                    ┌──────────────────┼──────────────────┐
                    │                  │                  │
                    ▼                  ▼                  ▼
          ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
          │ ISchemaRegistry │ │  IAttesterRole  │ │    Pausable     │
          │  (interface)    │ │   (interface)   │ │   Ownable       │
          └────────┬────────┘ └────────┬────────┘ │  (OpenZeppelin) │
                   │                   │          └─────────────────┘
                   │                   │
                   ▼                   ▼
          ┌─────────────────┐ ┌─────────────────┐
          │RWASchemaRegistry│ │  AttesterRole   │
          │      .sol       │ │      .sol       │
          └────────┬────────┘ └────────┬────────┘
                   │                   │
                   ▼                   ▼
          ┌─────────────────┐ ┌─────────────────┐
          │  AccessControl  │ │  AccessControl  │
          │    Pausable     │ │  (OpenZeppelin) │
          │  (OpenZeppelin) │ └─────────────────┘
          └─────────────────┘

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages