Decentralized governance forum for VEIL L1, backed by encrypted IPFS storage via OrbitDB. Fort Knox security model — end-to-end encrypted, wallet-authenticated, permissioned access.
- Runtime: Node.js + TypeScript
- Database: OrbitDB v1 (over Helia/IPFS)
- Encryption: AES-256-GCM per-record, NaCl box for DMs, Lit Protocol for access control
- Auth: EIP-4361 Sign-In with Ethereum (SIWE) — wallet signatures, no passwords
- Identity: DID:PKH (wallet-derived DIDs)
- Access Control: On-chain VEIL token gating + role NFTs
- Transport: libp2p (pubsub for real-time, direct for sync)
- Frontend: React + Vite (later)
- SIWE (Sign-In with Ethereum) — wallet signs a nonce
- Session tokens: JWT signed by server, 15min expiry, refresh via re-sign
- No email/password. No OAuth. Wallet only.
- Token-gated access: Must hold ≥1 VEIL to read, ≥100 VEIL to post, ≥10K VEIL to create proposals
- Role NFTs: Moderator, Council, Core — minted on VEIL L1
- On-chain verification: Contract call at auth time, cached 5min
- Every post/comment encrypted with AES-256-GCM before IPFS pinning
- Encryption key derived from forum-level symmetric key
- Forum key distributed via NaCl box to authorized wallets
- Key rotation on member removal
- libp2p noise protocol (TLS 1.3 equivalent)
- All pubsub messages encrypted with ephemeral keys
- Every record signed by author's wallet (EIP-712 typed data)
- OrbitDB CRDT guarantees convergence
- Merkle DAG provides tamper-evident history
- IPFS content-addressing — no single point of deletion
- Multiple pinning services (Pinata + local nodes)
- OrbitDB replication across authorized peers
veil-gov/proposals — DocumentStore (encrypted)
veil-gov/comments — DocumentStore (encrypted)
veil-gov/votes — KeyValueStore (encrypted)
veil-gov/members — KeyValueStore (public keys + roles)
veil-gov/metadata — KeyValueStore (forum config)
{
_id: string, // ULID
title: string, // encrypted
body: string, // encrypted (markdown)
author: string, // 0x address
authorSig: string, // EIP-712 signature
category: 'treasury' | 'protocol' | 'governance' | 'community',
status: 'draft' | 'active' | 'passed' | 'rejected' | 'executed',
requiredQuorum: number, // basis points
votingDeadline: number, // unix timestamp
createdAt: number,
updatedAt: number,
encryptedKey: string, // AES key encrypted to forum key
nonce: string, // AES-GCM nonce
}{
_id: string,
proposalId: string,
parentId: string | null, // threading
body: string, // encrypted
author: string,
authorSig: string,
createdAt: number,
nonce: string,
}{
// key: `${proposalId}:${voterAddress}`
choice: 'for' | 'against' | 'abstain',
weight: string, // VEIL balance at snapshot (bigint string)
sig: string, // EIP-712 signature
timestamp: number,
}veil-gov-forum/
├── src/
│ ├── db/
│ │ ├── orbit.ts — OrbitDB setup + Helia IPFS node
│ │ ├── stores.ts — proposal/comment/vote stores
│ │ └── replication.ts — peer sync config
│ ├── crypto/
│ │ ├── aes.ts — AES-256-GCM encrypt/decrypt
│ │ ├── nacl.ts — NaCl box for key exchange
│ │ ├── keys.ts — forum key management + rotation
│ │ └── signatures.ts — EIP-712 signing/verification
│ ├── auth/
│ │ ├── siwe.ts — SIWE authentication
│ │ ├── token-gate.ts — VEIL balance + role checks
│ │ └── session.ts — JWT session management
│ ├── governance/
│ │ ├── proposals.ts — CRUD + lifecycle
│ │ ├── comments.ts — threaded comments
│ │ ├── voting.ts — vote casting + tallying
│ │ └── snapshots.ts — balance snapshots for voting weight
│ ├── api/
│ │ ├── server.ts — Express/Fastify API
│ │ └── routes/
│ │ ├── auth.ts
│ │ ├── proposals.ts
│ │ ├── comments.ts
│ │ └── votes.ts
│ └── index.ts
├── package.json
├── tsconfig.json
└── .env.example