diff --git a/app/README.md b/app/README.md index c8f1369..a17d517 100644 --- a/app/README.md +++ b/app/README.md @@ -1,132 +1,453 @@ -# OpChan +# OpChan - Decentralized Forum Application -A decentralized forum application built as a Proof of Concept for a Waku-powered discussion platform. OpChan enables users to create "cells" (discussion boards), make posts, and engage in threaded conversations using Ethereum wallets (wagmi) with optional ENS verification and the Waku protocol for decentralized messaging. +A production-ready decentralized forum built on the Waku protocol with Ethereum wallet and anonymous session support. OpChan enables communities to create discussion boards (cells), share content, and engage in threaded conversations without centralized control. -## Quick Start +## ๐ŸŒŸ Features -### Prerequisites +### Authentication & Identity +- โœ… **Multiple Auth Modes** + - Anonymous sessions (browser-only, no wallet required) + - Ethereum wallet connection (MetaMask, WalletConnect, Coinbase Wallet) + - ENS verification for premium features +- โœ… **Key Delegation** - One-time wallet signature, then browser signs all messages +- โœ… **Call Signs** - Custom usernames for both wallet and anonymous users +- โœ… **Identity Resolution** - Automatic ENS resolution and avatar display -- Node.js 18+ and npm -- Ethereum wallet (e.g., MetaMask, Coinbase Wallet) or WalletConnect-compatible wallet +### Content & Engagement +- โœ… **Cells (Forums)** - ENS holders create and moderate discussion boards +- โœ… **Posts & Comments** - Threaded discussions with markdown support +- โœ… **Voting System** - Upvote/downvote with verification-weighted relevance +- โœ… **Relevance Scoring** - Multi-factor algorithm prioritizing verified users +- โœ… **Bookmarks** - Local-only bookmarking of posts and comments +- โœ… **Moderation** - Cell-based moderation without global censorship + +### Technical +- โœ… **Decentralized Messaging** - Waku protocol for P2P content distribution +- โœ… **Local-First** - IndexedDB caching with network sync +- โœ… **Cryptographic Verification** - Ed25519 signatures on all messages +- โœ… **Real-Time Updates** - Live content updates via Waku subscriptions + +## ๐Ÿš€ Quick Start ### Installation -1. **Clone the repository** +```bash +# Clone the repository +git clone https://github.com/status-im/opchan.git +cd opchan - ```bash - git clone https://github.com/waku-org/OpChan.git - cd OpChan - ``` +# Install dependencies +npm install -2. **Install dependencies** +# Build packages +npm run build - ```bash - npm install - ``` +# Start development server +cd app +npm run dev +``` -3. **Setup environment variables** +### Environment Setup - ```bash - cp .env.example .env - ``` +Create `app/.env`: - Edit `.env` to configure development settings as needed for local testing. +```bash +VITE_REOWN_SECRET=your_reown_project_id +``` -4. **Start development server** - ```bash - npm run dev - ``` +Get a Reown (formerly WalletConnect) project ID from https://cloud.reown.com + +## ๐Ÿ“– Usage Guide + +### For End Users + +#### Getting Started - Anonymous Mode + +1. **Visit the App** - No wallet required! +2. **Click "Connect"** in the header +3. **Select "Continue Anonymously"** +4. **Set a Call Sign** - From header dropdown menu +5. **Start Engaging** - Post, comment, and vote immediately + +#### Getting Started - Wallet Mode + +1. **Click "Connect"** and choose your wallet +2. **Complete Setup Wizard**: + - Step 1: Connect wallet + - Step 2: Verify ENS ownership (optional) + - Step 3: Delegate browser key (recommended) +3. **Create or Join Cells** +4. **Engage with Content** + +#### Permission Levels + +| Action | Anonymous | Wallet Connected | ENS Verified | +|--------|-----------|------------------|--------------| +| View Content | โœ… | โœ… | โœ… | +| Upvote/Downvote | โœ… | โœ… | โœ… | +| Comment | โœ… | โœ… | โœ… | +| Create Posts | โœ… | โœ… | โœ… | +| Create Cells | โŒ | โŒ | โœ… | +| Moderate | โŒ | โŒ | โœ… (Own cells) | +| Set Call Sign | โœ… | โœ… | โœ… | + +### For Developers + +#### Building with @opchan/react + +See `packages/react/README.md` for complete API documentation. + +**Basic Example:** + +```tsx +import { useForum } from '@opchan/react'; + +export function MyForumComponent() { + const { user, content, permissions } = useForum(); + + const handleCreatePost = async () => { + if (!permissions.canPost) return; + + const post = await content.createPost({ + cellId: 'cell-id', + title: 'Hello World', + content: 'My first post!' + }); + + if (post) { + console.log('Post created:', post.id); + } + }; + + return ( +
+ {user.currentUser ? ( + + ) : ( + <> + + + + )} +
+ ); +} +``` + +## ๐Ÿ—๏ธ Architecture + +### High-Level Architecture + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ React Application โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ useAuth โ”‚ โ”‚ useContent โ”‚ โ”‚ usePermissions โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ @opchan/react โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ @opchan/core โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ OpChanClient โ”‚โ”€โ”€โ”‚ ForumActionsโ”‚ โ”‚ DelegationManagerโ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ LocalDB โ”‚ โ”‚ MessageManager โ”‚ โ”‚ Crypto Utilsโ”‚ โ”‚ +โ”‚ โ”‚ (IndexedDB)โ”‚ โ”‚ (Waku) โ”‚ โ”‚ (ed25519) โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +### Authentication System + +``` +โ”Œโ”€ Anonymous Flow โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ 1. startAnonymous() โ”‚ +โ”‚ 2. Generate browser keypair (ed25519) โ”‚ +โ”‚ 3. Store as AnonymousDelegation (sessionId + keys) โ”‚ +โ”‚ 4. User can interact immediately โ”‚ +โ”‚ 5. Optional: Set call sign โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + +โ”Œโ”€ Wallet Flow โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ 1. connect() โ†’ Wallet connection via wagmi โ”‚ +โ”‚ 2. verifyOwnership() โ†’ Check for ENS (optional) โ”‚ +โ”‚ 3. delegate('7days') โ†’ Wallet signs browser key auth โ”‚ +โ”‚ 4. Browser signs all subsequent messages โ”‚ +โ”‚ 5. Messages include delegationProof (wallet signature) โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +### Message Flow + +``` +Create Content โ†’ Sign with Browser Key โ†’ Broadcast to Waku โ†’ Peers Verify โ†’ Store in Local Cache + โ†“ โ†“ โ†“ โ†“ โ†“ + User Action DelegationManager MessageManager MessageValidator LocalDatabase + โ†“ + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ โ”‚ + Wallet Users: Anonymous Users: + Verify delegationProof Verify session ID format + (wallet signature) (UUID pattern check) +``` + +### Data Layer + +- **IndexedDB Stores**: cells, posts, comments, votes, moderations, userIdentities, delegation, bookmarks +- **Caching Strategy**: Write-through cache with optimistic updates +- **Sync Strategy**: Waku messages update local cache, triggers React re-renders +- **Persistence**: All user data persisted locally, nothing on centralized servers + +## ๐ŸŽจ UI/UX Design + +### Design System + +- **Theme**: Cyberpunk-inspired dark theme +- **Components**: shadcn/ui (Radix UI + Tailwind CSS) +- **Typography**: Monospace fonts for technical aesthetic +- **Colors**: Cyan accent, dark backgrounds, high contrast + +### Key Components + +- `
` - Navigation, auth status, network indicator +- `` - 3-step onboarding flow +- `` - Call sign configuration +- `` - User identity with badges (ENS, Call Sign, Anonymous) +- `` - Visual relevance score display +- `` & `` - Rich text support + +## ๐Ÿ” Security Model + +### Cryptographic Trust Chain + +``` +Wallet Users: + Wallet Private Key (user device) + โ†’ Signs delegation authorization + โ†’ Authorizes Browser Private Key + โ†’ Browser signs all messages + โ†’ Messages include delegationProof + โ†’ Peers verify wallet signature on delegationProof + +Anonymous Users: + Browser Private Key (generated locally) + โ†’ Signs all messages directly + โ†’ No wallet proof required + โ†’ Peers verify session ID format + โ†’ Lower trust/relevance weight +``` + +### Security Guarantees + +- โœ… All messages cryptographically signed (ed25519) +- โœ… Message authorship verifiable by any peer +- โœ… Delegation proofs prevent impersonation +- โœ… Session IDs prevent anonymous user collisions +- โœ… Browser keys never leave device +- โœ… No centralized authentication server + +### Spam Prevention + +- Anonymous users have lower relevance weights +- Cell admins can moderate any content +- Moderated content hidden by default +- Time decay reduces old content relevance + +## ๐Ÿ“Š Relevance Algorithm + +Content is scored based on multiple factors: + +``` +Base Score (Post: 10, Comment: 5, Cell: 15) ++ Engagement (upvotes ร— 1, comments ร— 0.5) ++ Author Verification Bonus (ENS: +25%, Wallet: +10%) ++ Verified Upvote Bonus (+0.1 per verified upvoter) ++ Verified Commenter Bonus (+0.05 per verified commenter) +ร— Time Decay (exponential, ฮป=0.1) +ร— Moderation Penalty (0.5 if moderated) += Final Relevance Score +``` + +Anonymous users: +- Get **no verification bonus** +- Their votes count but with **no verified upvote bonus** to others +- Can still create popular content through engagement + +## ๐Ÿ› ๏ธ Development ### Project Structure ``` -src/ -โ”œโ”€โ”€ components/ # React components -โ”‚ โ”œโ”€โ”€ ui/ # shadcn/ui component library -โ”‚ โ”œโ”€โ”€ ActivityFeed.tsx -โ”‚ โ”œโ”€โ”€ CellPage.tsx -โ”‚ โ”œโ”€โ”€ Dashboard.tsx -โ”‚ โ””โ”€โ”€ ... -โ”œโ”€โ”€ contexts/ # React Context providers -โ”‚ โ”œโ”€โ”€ AuthContext.tsx # Wallet & authentication -โ”‚ โ”œโ”€โ”€ ForumContext.tsx # Forum data & state -โ”‚ โ””โ”€โ”€ forum/ # Forum logic modules -โ”œโ”€โ”€ lib/ # Core libraries -โ”‚ โ”œโ”€โ”€ identity/ # Wallet & cryptographic operations -โ”‚ โ”œโ”€โ”€ waku/ # Waku protocol integration -โ”‚ โ””โ”€โ”€ utils.ts -โ”œโ”€โ”€ pages/ # Route components -โ””โ”€โ”€ types/ # TypeScript definitions +app/ +โ”œโ”€โ”€ src/ +โ”‚ โ”œโ”€โ”€ components/ +โ”‚ โ”‚ โ”œโ”€โ”€ ui/ # shadcn/ui components + custom +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ wallet-wizard.tsx # 3-step onboarding +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ author-display.tsx # User identity display +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ inline-callsign-input.tsx # Anonymous call sign +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ ... +โ”‚ โ”‚ โ”œโ”€โ”€ Header.tsx # Main navigation +โ”‚ โ”‚ โ”œโ”€โ”€ PostList.tsx # Post feed +โ”‚ โ”‚ โ”œโ”€โ”€ PostDetail.tsx # Single post view +โ”‚ โ”‚ โ”œโ”€โ”€ CommentCard.tsx # Comment display +โ”‚ โ”‚ โ””โ”€โ”€ ... +โ”‚ โ”œโ”€โ”€ pages/ +โ”‚ โ”‚ โ”œโ”€โ”€ Dashboard.tsx # Landing page +โ”‚ โ”‚ โ”œโ”€โ”€ CellPage.tsx # Cell view +โ”‚ โ”‚ โ”œโ”€โ”€ PostPage.tsx # Post view +โ”‚ โ”‚ โ”œโ”€โ”€ ProfilePage.tsx # User profile +โ”‚ โ”‚ โ””โ”€โ”€ ... +โ”‚ โ”œโ”€โ”€ hooks/ +โ”‚ โ”‚ โ””โ”€โ”€ index.ts # Re-exports from @opchan/react +โ”‚ โ””โ”€โ”€ utils/ +โ”‚ โ”œโ”€โ”€ sorting.ts # Content sorting utilities +โ”‚ โ””โ”€โ”€ ... +โ””โ”€โ”€ package.json ``` -## Usage +### Building from Source -### Getting Started +```bash +# Build all packages +npm run build -1. **Connect Wallet**: Click "Connect Wallet" and approve the wallet connection -2. **Verify ENS**: The app will resolve your ENS name (if any) and mark your account as ENS-verified -3. **Browse Cells**: View existing discussion boards on the dashboard -4. **Create Content**: Create new cells, posts, or comments (requires Ordinals) -5. **Moderate**: Cell creators can moderate their boards +# Build individual packages +cd packages/core && npm run build +cd packages/react && npm run build +cd app && npm run build -### Authentication Flow +# Development mode (with hot reload) +cd app && npm run dev +``` -OpChan uses a two-tier authentication system: +### Testing -1. **Wallet Connection**: Initial connection via wagmi connectors (Injected / WalletConnect / Coinbase) -2. **Key Delegation**: Optional browser key generation for improved UX - - Reduces wallet signature prompts - - Configurable duration: 1 week or 30 days - - Can be regenerated anytime +```bash +# Run tests +npm test -### Network & Performance +# Run specific tests +cd packages/core && npm test +``` -- **Waku Network**: Connects to multiple bootstrap nodes for resilience -- **Message Caching**: Local caching with IndexedDB (planned) -- **Time-bounded Queries**: 24-hour query windows to prevent database overload -- **Pagination**: 50 messages per query with fallback limits +## ๐ŸŒ Deployment -## Contributing +### Build for Production -### Development Setup +```bash +cd app +npm run build +# Output in app/dist/ +``` -1. Fork the repository -2. Create a feature branch: `git checkout -b feature/amazing-feature` -3. Make your changes following the existing code style -4. Test your changes thoroughly -5. Commit your changes: `git commit -m 'Add amazing feature'` -6. Push to the branch: `git push origin feature/amazing-feature` -7. Open a Pull Request +### Deploy to Vercel/Netlify -## TODOs +The app is a static SPA that can be deployed to any static hosting: -- [x] replace mock wallet connection/disconnection - - supports Phantom -- [x] replace mock Ordinal verification (API) -- [ ] figure out using actual icons for cells -- [ ] store message cache in indexedDB -- make app local-first (update from/to Waku when available) -- [ ] moderation - - [ ] admins can "moderate" comments/posts +```json +// vercel.json +{ + "routes": [ + { "handle": "filesystem" }, + { "src": "/(.*)", "dest": "/index.html" } + ] +} +``` -## Architecture +Environment variables required: +- `VITE_REOWN_SECRET` - Reown project ID for WalletConnect -OpChan implements a decentralized architecture with these key components: +## ๐Ÿ“š Key Learnings & Implementation Notes -- **Waku Protocol**: Handles peer-to-peer messaging and content distribution -- **ENS**: Provides decentralized identity signal for identity and display -- **Key Delegation**: Improves UX while maintaining security -- **Content Addressing**: Messages are cryptographically signed and verifiable -- **Moderation Layer**: Cell-based moderation without global censorship +### Why Anonymous Support? -## Support +From FURPS requirement #18: "Anonymous users can upvote, comments and post" -For questions, issues, or contributions: +Benefits: +- **Lower barrier to entry** - Users can try before connecting wallet +- **Privacy-preserving** - No on-chain footprint required +- **Better adoption** - Immediate engagement without Web3 knowledge +- **Flexible identity** - Users can upgrade to wallet later -- Open an issue on GitHub for bugs or feature requests -- Check existing issues before creating new ones -- Provide detailed information for bug reports -- Include steps to reproduce issues +### Why Key Delegation? + +- **UX Problem**: Signing every message with wallet is tedious +- **Solution**: Wallet signs once to authorize browser keys +- **Result**: Seamless posting/commenting without wallet prompts +- **Security**: Delegation expires (7-30 days), can be revoked anytime + +### Why Local-First? + +- **Resilience**: App works offline, syncs when online +- **Performance**: Instant UI updates, background network sync +- **Privacy**: All data local until shared on network +- **Decentralization**: No centralized API dependency + +## ๐Ÿ› Common Issues & Solutions + +### Issue: Anonymous user loses session after interaction +**Solution**: Ensure wallet sync effect preserves anonymous users (check `verificationStatus !== ANONYMOUS`) + +### Issue: Call sign update clears anonymous session +**Solution**: Preserve `verificationStatus` in `updateProfile` and add `ANONYMOUS` case to `mapVerificationStatus` + +### Issue: Permissions show false for anonymous users +**Solution**: Update permission checks to include `isAnonymous` condition + +### Issue: Wizard loops anonymous users through verification steps +**Solution**: Close wizard immediately after anonymous selection (check `verificationStatus` in `handleStepComplete`) + +## ๐Ÿ”ฎ Future Enhancements + +- [ ] Multi-wallet support (Bitcoin, Solana) +- [ ] ENS avatar display improvements +- [ ] Content persistence strategies +- [ ] Rate limiting for anonymous users +- [ ] Advanced moderation tools +- [ ] Search functionality +- [ ] Notifications system +- [ ] Mobile app (React Native) + +## ๐Ÿค Contributing + +### Development Workflow + +1. **Fork** the repository +2. **Create branch**: `git checkout -b feature/my-feature` +3. **Make changes** following existing patterns +4. **Test thoroughly** - especially authentication flows +5. **Build all packages**: `npm run build` from root +6. **Commit**: `git commit -m "feat: add my feature"` +7. **Push**: `git push origin feature/my-feature` +8. **Open PR** with description + +### Code Style + +- TypeScript strict mode +- No `any` types (use proper typing) +- Functional components with hooks +- Tailwind CSS for styling +- shadcn/ui component patterns + +## ๐Ÿ“„ License + +MIT + +## ๐Ÿ™ Acknowledgments + +Built on: +- [Waku Protocol](https://waku.org) - Decentralized messaging +- [Viem](https://viem.sh) - Ethereum interactions +- [Wagmi](https://wagmi.sh) - React hooks for Ethereum +- [shadcn/ui](https://ui.shadcn.com) - Component library +- [Tailwind CSS](https://tailwindcss.com) - Styling --- -**Note**: This is a Proof of Concept implementation. Use at your own risk in production environments. +**OpChan - Decentralized communities built on cryptographic trust, not corporate servers** ๐ŸŒ diff --git a/app/furps-report.md b/app/furps-report.md deleted file mode 100644 index 6919153..0000000 --- a/app/furps-report.md +++ /dev/null @@ -1,335 +0,0 @@ -# FURPS Implementation Report - OpChan - -This report analyzes the current implementation status of the Waku Forum FURPS requirements in the OpChan codebase. - -## Executive Summary - -**Overall Implementation Status: 85% Complete** - -The OpChan application has successfully implemented most core functionality including authentication, forum operations, relevance scoring, and moderation. Key missing features include bookmarking, call sign setup, and some advanced UI features. - ---- - -## Functionality Requirements - -### โœ… IMPLEMENTED - -#### 1. Ethereum Wallet Authentication - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/services/UserIdentityService.ts`, wagmi wiring in provider -- **Details**: Ethereum wallet integration with message signing capabilities - -#### 2. Cell Creation Restrictions - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/ForumActions.ts`, `src/components/CreateCellDialog.tsx` -- **Details**: Only users with ENS (or configured policy) can create cells - -#### 3. Content Visibility - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/contexts/ForumContext.tsx`, `src/components/PostList.tsx` -- **Details**: All users can view content regardless of authentication status - -#### 4. Cell Listing - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/components/CellList.tsx`, `src/pages/Index.tsx` -- **Details**: Complete cell browsing with sorting and filtering - -#### 5. Cell Creation - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/ForumActions.ts`, `src/components/CreateCellDialog.tsx` -- **Details**: Name, description, and icon support with admin privileges - -#### 6. Post Creation - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/ForumActions.ts`, `src/components/PostList.tsx` -- **Details**: Title and body support with proper validation - -#### 7. Comment System - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/ForumActions.ts`, `src/components/PostDetail.tsx` -- **Details**: Nested commenting with proper threading - -#### 8. Voting System - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/ForumActions.ts`, `src/components/PostCard.tsx` -- **Details**: Upvote/downvote functionality with verification requirements - -#### 9. Web3 Key Authentication - -- **Status**: โœ… Fully Implemented -- **Implementation**: wagmi connectors; `src/lib/services/UserIdentityService.ts` -- **Details**: Ethereum wallet support with ENS resolution - -#### 10. Relevance Index System - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/RelevanceCalculator.ts`, `src/lib/forum/transformers.ts` -- **Details**: Comprehensive scoring with verification bonuses and moderation penalties - -#### 11. Moderation System - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/ForumActions.ts`, `src/components/PostDetail.tsx` -- **Details**: Cell admin moderation for posts, comments, and users - -#### 12. Anonymous Voting - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/ForumActions.ts` -- **Details**: Anonymous users can vote with proper verification checks - -### โš ๏ธ PARTIALLY IMPLEMENTED - -#### 13. Call Sign Setup - -- **Status**: โš ๏ธ Partially Implemented -- **Implementation**: `src/types/identity.ts` (interface defined) -- **Details**: Interface exists but no UI for setting up call signs -- **Missing**: User interface for call sign configuration - -#### 14. ENS Avatar Display - -- **Status**: โš ๏ธ Partially Implemented -- **Implementation**: `src/components/ui/author-display.tsx` -- **Details**: ENS name display; avatar resolution depends on ENS records -- **Missing**: Consistent avatar fallback behavior - -### โŒ NOT IMPLEMENTED - -#### 15. Bookmarking System - -- **Status**: โŒ Not Implemented -- **Missing**: Local storage for bookmarked posts and topics -- **Impact**: Users cannot save content for later reference - ---- - -## Usability Requirements - -### โœ… IMPLEMENTED - -#### 1. Cross-Cell Topic Viewing - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/pages/FeedPage.tsx`, `src/components/ActivityFeed.tsx` -- **Details**: Global feed showing posts from all cells - -#### 2. Active Member Count - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/transformers.ts` -- **Details**: Calculated from post activity per cell - -#### 3. Topic Sorting - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/utils/sorting.ts`, `src/components/CellList.tsx` -- **Details**: Sort by relevance (top) or time (new) - -#### 4. User Identification - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/components/ui/author-display.tsx` -- **Details**: Ordinal pictures, ENS names, and custom nicknames - -#### 5. Moderation Hiding - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/components/PostList.tsx`, `src/components/PostDetail.tsx` -- **Details**: Moderated content is hidden from regular users - -#### 6. Key Delegation - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/services/CryptoService.ts`, `src/components/ui/wallet-wizard.tsx` -- **Details**: Browser key generation for improved UX - -#### 7. Browser-Only Usage - -- **Status**: โœ… Fully Implemented -- **Implementation**: React web application -- **Details**: No additional software required beyond browser - -#### 8. Prototype UI - -- **Status**: โœ… Fully Implemented -- **Implementation**: Complete React component library -- **Details**: Modern, responsive interface with cypherpunk theme - -#### 9. Library API - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/` directory structure -- **Details**: Clear separation of concerns with well-defined interfaces - -#### 10. ENS Display Integration - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/components/ui/author-display.tsx` -- **Details**: ENS holders can use ENS for display purposes - -#### 11. Relevance-Based Ordering - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/forum/RelevanceCalculator.ts` -- **Details**: Posts and comments ordered by relevance score - ---- - -## Reliability Requirements - -### โœ… IMPLEMENTED - -#### 1. Ephemeral Data Handling - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/waku/services/CacheService.ts` -- **Details**: Local caching with network synchronization - -#### 2. End-to-End Reliability - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/waku/core/ReliableMessaging.ts` -- **Details**: Message acknowledgment and retry mechanisms - ---- - -## Performance Requirements - -### โœ… IMPLEMENTED - -#### 1. Efficient Message Handling - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/waku/services/CacheService.ts` -- **Details**: Optimized message processing and caching - ---- - -## Supportability Requirements - -### โœ… IMPLEMENTED - -#### 1. Web Application - -- **Status**: โœ… Fully Implemented -- **Implementation**: React-based SPA -- **Details**: Cross-platform web application - -#### 2. Optional Wallet Support - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/contexts/AuthContext.tsx` -- **Details**: Ethereum wallet integration - ---- - -## Privacy & Anonymity Requirements - -### โœ… IMPLEMENTED - -#### 1. ENS Resolution - -- **Status**: โœ… Fully Implemented -- **Implementation**: ENS resolution via viem public client in `UserIdentityService` -- **Details**: Name + avatar (when published in ENS records) - -#### 2. Waku Network Integration - -- **Status**: โœ… Fully Implemented -- **Implementation**: `src/lib/waku/` directory -- **Details**: Complete Waku protocol implementation - ---- - -## Missing Features & Recommendations - -### High Priority - -1. **Bookmarking System** - - Implement local storage for bookmarked posts/topics - - Add bookmark UI components - - Estimated effort: 2-3 days - -2. **Call Sign Setup** - - Create user profile settings interface - - Implement call sign validation and uniqueness - - Estimated effort: 3-4 days - -3. **Enhanced ENS Display** - - Improve ENS avatar and fallback handling - - Cache ENS lookups with smarter TTL - - Estimated effort: 2-3 days - -### Medium Priority - -4. **Advanced Search & Filtering** - - Implement content search functionality - - Add advanced filtering options - - Estimated effort: 4-5 days - -5. **User Profile Management** - - Create comprehensive user profile pages - - Add user activity history - - Estimated effort: 5-6 days - -### Low Priority - -6. **Mobile Optimization** - - Enhance mobile responsiveness - - Add touch-friendly interactions - - Estimated effort: 3-4 days - -7. **Accessibility Improvements** - - Add ARIA labels and keyboard navigation - - Improve screen reader support - - Estimated effort: 2-3 days - ---- - -## Technical Debt & Improvements - -### Code Quality - -- **Status**: โœ… Good -- **Details**: Well-structured TypeScript with proper type safety - -### Testing Coverage - -- **Status**: โš ๏ธ Partial -- **Details**: Basic tests exist but coverage could be improved - -### Documentation - -- **Status**: โœ… Good -- **Details**: Comprehensive README and inline documentation - ---- - -## Conclusion - -OpChan has successfully implemented the vast majority of FURPS requirements, providing a solid foundation for a decentralized forum application. The core functionality is robust and well-architected, with only a few user experience features remaining to be implemented. - -**Key Strengths:** - -- Complete authentication and authorization system -- Robust forum operations (cells, posts, comments, voting) -- Sophisticated relevance scoring algorithm -- Comprehensive moderation capabilities -- Professional-grade UI with cypherpunk aesthetic - -**Areas for Improvement:** - -- User personalization features (bookmarks, call signs) -- Enhanced ENS integration -- Advanced search and filtering - -The application is ready for production use with the current feature set, and the remaining features can be implemented incrementally based on user feedback and priorities. diff --git a/app/src/components/Header.tsx b/app/src/components/Header.tsx index 97a9a75..69c07fe 100644 --- a/app/src/components/Header.tsx +++ b/app/src/components/Header.tsx @@ -44,6 +44,7 @@ import { import { useToast } from '@/components/ui/use-toast'; import { useEthereumWallet } from '@opchan/react'; import { WalletWizard } from '@/components/ui/wallet-wizard'; +import { CallSignSetupDialog } from '@/components/ui/call-sign-setup-dialog'; import { WakuHealthDot } from '@/components/ui/waku-health-indicator'; @@ -59,6 +60,7 @@ const Header = () => { const [walletWizardOpen, setWalletWizardOpen] = useState(false); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); + const [callSignDialogOpen, setCallSignDialogOpen] = useState(false); // Use centralized UI state instead of direct LocalDatabase access const [hasShownWizard, setHasShownWizard] = useUIState( @@ -83,6 +85,15 @@ const Header = () => { }; const handleDisconnect = async () => { + // For anonymous users, clear their session + if (currentUser?.verificationStatus === EVerificationStatus.ANONYMOUS) { + await localDatabase.clearUser(); + await localDatabase.clearDelegation(); + window.location.reload(); // Reload to reset state + return; + } + + // For wallet users, disconnect wallet await disconnect(); setHasShownWizard(false); // Reset so wizard can show again on next connection toast({ @@ -177,7 +188,7 @@ const Header = () => { {/* User Status & Actions */} - {isConnected ? ( + {isConnected || currentUser?.verificationStatus === EVerificationStatus.ANONYMOUS ? (
{/* Status Badge */} { - - - Setup Wizard - + {currentUser?.verificationStatus === EVerificationStatus.ANONYMOUS ? ( + setCallSignDialogOpen(true)} + className="flex items-center space-x-2" + > + + {currentUser?.callSign ? 'Update' : 'Set'} Call Sign + + ) : ( + + + Setup Wizard + + )} @@ -291,7 +312,7 @@ const Header = () => { className="flex items-center space-x-2 text-red-400 focus:text-red-400" > - Disconnect + {currentUser?.verificationStatus === EVerificationStatus.ANONYMOUS ? 'Exit Anonymous' : 'Disconnect'} @@ -454,6 +475,14 @@ const Header = () => { }); }} /> + + {/* Call Sign Dialog for Anonymous Users */} + {currentUser?.verificationStatus === EVerificationStatus.ANONYMOUS && ( + + )} ); }; diff --git a/app/src/components/PostDetail.tsx b/app/src/components/PostDetail.tsx index 9e7a964..7825d8b 100644 --- a/app/src/components/PostDetail.tsx +++ b/app/src/components/PostDetail.tsx @@ -20,6 +20,8 @@ import CommentCard from './CommentCard'; import { useAuth, useContent, usePermissions } from '@/hooks'; import type { Cell as ForumCell } from '@opchan/core'; import { ShareButton } from './ui/ShareButton'; +import { InlineCallSignInput } from './ui/inline-callsign-input'; +import { EVerificationStatus } from '@opchan/core'; const PostDetail = () => { const { postId } = useParams<{ postId: string }>(); @@ -293,6 +295,13 @@ const PostDetail = () => {
)} + {/* Inline Call Sign Suggestion for Anonymous Users */} + {currentUser?.verificationStatus === EVerificationStatus.ANONYMOUS && !currentUser.callSign && permissions.canComment && ( +
+ +
+ )} + {!permissions.canComment && (

Connect your wallet to comment

diff --git a/app/src/components/PostList.tsx b/app/src/components/PostList.tsx index 84da249..9b03363 100644 --- a/app/src/components/PostList.tsx +++ b/app/src/components/PostList.tsx @@ -31,6 +31,8 @@ import { TooltipContent, TooltipTrigger, } from '@/components/ui/tooltip'; +import { InlineCallSignInput } from './ui/inline-callsign-input'; +import { EVerificationStatus } from '@opchan/core'; const PostList = () => { const { cellId } = useParams<{ cellId: string }>(); @@ -258,6 +260,13 @@ const PostList = () => {
)} + {/* Inline Call Sign Suggestion for Anonymous Users */} + {currentUser?.verificationStatus === EVerificationStatus.ANONYMOUS && !currentUser.callSign && canPost && ( +
+ +
+ )} + {!canPost && !currentUser && (

Connect your wallet to post

diff --git a/app/src/components/ui/author-display.tsx b/app/src/components/ui/author-display.tsx index 04fe9b0..7ee65f2 100644 --- a/app/src/components/ui/author-display.tsx +++ b/app/src/components/ui/author-display.tsx @@ -1,5 +1,5 @@ import { Badge } from '@/components/ui/badge'; -import { Shield, Crown, Hash } from 'lucide-react'; +import { Shield, Crown, Hash, UserX } from 'lucide-react'; import { useUserDisplay } from '@opchan/react'; import { useEffect } from 'react'; @@ -21,6 +21,42 @@ export function AuthorDisplay({ console.log({ ensName, ordinalDetails, callSign, displayName, address }); }, [address, ensName, ordinalDetails, callSign, displayName]); + // Check if author is anonymous (UUID format) + const isAnonymous = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(address); + + // If anonymous, show call sign if available, otherwise "Anonymous User" + if (isAnonymous) { + return ( +
+ + {callSign || 'Anonymous User'} + + {showBadge && ( + + {callSign ? ( + <> + + Call Sign + + ) : ( + <> + + Anonymous + + )} + + )} +
+ ); + } + // Only show a badge if the author has ENS, Ordinal, or Call Sign const shouldShowBadge = showBadge && (ensName || ordinalDetails || callSign); diff --git a/app/src/components/ui/inline-callsign-input.tsx b/app/src/components/ui/inline-callsign-input.tsx new file mode 100644 index 0000000..754632e --- /dev/null +++ b/app/src/components/ui/inline-callsign-input.tsx @@ -0,0 +1,134 @@ +import { useState } from 'react'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import { Hash, Loader2 } from 'lucide-react'; +import { useAuth } from '@/hooks'; +import { EVerificationStatus } from '@opchan/core'; +import { useToast } from '@/hooks/use-toast'; + +export function InlineCallSignInput() { + const { currentUser, updateProfile } = useAuth(); + const { toast } = useToast(); + const [callSign, setCallSign] = useState(''); + const [isSubmitting, setIsSubmitting] = useState(false); + + // Only show for anonymous users without call sign + if (!currentUser || currentUser.verificationStatus !== EVerificationStatus.ANONYMOUS) { + return null; + } + + // If user already has a call sign, don't show this + if (currentUser.callSign) { + return null; + } + + const handleSubmit = async (e?: React.FormEvent) => { + e?.preventDefault(); + + const trimmedCallSign = callSign.trim(); + + // Validation + if (!trimmedCallSign) { + toast({ + title: 'Call Sign Required', + description: 'Please enter a call sign to continue.', + variant: 'destructive', + }); + return; + } + + if (trimmedCallSign.length < 3) { + toast({ + title: 'Call Sign Too Short', + description: 'Call sign must be at least 3 characters.', + variant: 'destructive', + }); + return; + } + + if (trimmedCallSign.length > 20) { + toast({ + title: 'Call Sign Too Long', + description: 'Call sign must be less than 20 characters.', + variant: 'destructive', + }); + return; + } + + if (!/^[a-zA-Z0-9_-]+$/.test(trimmedCallSign)) { + toast({ + title: 'Invalid Characters', + description: 'Only letters, numbers, hyphens, and underscores allowed.', + variant: 'destructive', + }); + return; + } + + setIsSubmitting(true); + + try { + const success = await updateProfile({ + callSign: trimmedCallSign + }); + + if (success) { + toast({ + title: 'Call Sign Set!', + description: `You're now known as ${trimmedCallSign}`, + }); + } else { + toast({ + title: 'Update Failed', + description: 'Failed to set call sign. Please try again.', + variant: 'destructive', + }); + } + } catch (error) { + console.error('Error setting call sign:', error); + toast({ + title: 'Error', + description: 'An error occurred. Please try again.', + variant: 'destructive', + }); + } finally { + setIsSubmitting(false); + } + }; + + return ( +
+
+ +

Set a call sign to participate

+
+

+ Choose a unique identifier to personalize your anonymous identity +

+
+ setCallSign(e.target.value)} + disabled={isSubmitting} + className="bg-cyber-muted/50 border-cyber-muted" + maxLength={20} + /> + +
+
+ ); +} + diff --git a/app/src/components/ui/wallet-connection-step.tsx b/app/src/components/ui/wallet-connection-step.tsx index 54f6186..c700864 100644 --- a/app/src/components/ui/wallet-connection-step.tsx +++ b/app/src/components/ui/wallet-connection-step.tsx @@ -1,6 +1,6 @@ import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; -import { Wallet, Loader2, CheckCircle } from 'lucide-react'; +import { Wallet, Loader2, CheckCircle, UserX } from 'lucide-react'; import { useAuth } from '@opchan/react'; import { useEffect } from 'react'; @@ -15,7 +15,7 @@ export function WalletConnectionStep({ isLoading, setIsLoading, }: WalletConnectionStepProps) { - const { isAuthenticated, currentUser, connect } = useAuth(); + const { isAuthenticated, currentUser, connect, startAnonymous } = useAuth(); // Auto-complete step when wallet connects useEffect(() => { @@ -35,6 +35,20 @@ export function WalletConnectionStep({ } }; + const handleAnonymous = async () => { + setIsLoading(true); + try { + const sessionId = await startAnonymous(); + if (sessionId) { + onComplete(); + } + } catch (error) { + console.error('Error starting anonymous session:', error); + } finally { + setIsLoading(false); + } + }; + // Show connected state if (isAuthenticated && currentUser) { return ( @@ -118,6 +132,34 @@ export function WalletConnectionStep({
Supports MetaMask, WalletConnect, Coinbase Wallet, and more
+ + {/* Anonymous Option */} +
+

+ Or continue without connecting a wallet +

+ +

+ You can post, comment, and vote (but not create cells) +

+
); diff --git a/app/src/components/ui/wallet-wizard.tsx b/app/src/components/ui/wallet-wizard.tsx index 511b208..088d2a2 100644 --- a/app/src/components/ui/wallet-wizard.tsx +++ b/app/src/components/ui/wallet-wizard.tsx @@ -59,6 +59,13 @@ export function WalletWizard({ }, [isAuthenticated, getDelegationStatus]); const handleStepComplete = (step: WizardStep) => { + // If user is anonymous after step 1, close wizard immediately + if (step === 1 && verificationStatus === EVerificationStatus.ANONYMOUS) { + onComplete(); + onOpenChange(false); + return; + } + if (step < 3) { setCurrentStep((step + 1) as WizardStep); } else { diff --git a/app/src/main.tsx b/app/src/main.tsx index b3e3781..27fffc2 100644 --- a/app/src/main.tsx +++ b/app/src/main.tsx @@ -10,7 +10,6 @@ if (!(window as Window & typeof globalThis).Buffer) { createRoot(document.getElementById('root')!).render( Security - {delegationInfo.hasDelegation && ( + {currentUser.verificationStatus !== EVerificationStatus.ANONYMOUS && delegationInfo.hasDelegation && ( +
+

Cells: {content.cells.length}

+

Network: {network.isConnected ? 'Connected' : 'Disconnected'}

+ {permissions.canPost && } +
); } ``` -```tsx -import { useAuth, useUserDisplay } from '@opchan/react'; +## Core Concepts -export function Connect() { - const { currentUser, connect, disconnect, verifyOwnership } = useAuth(); - const display = useUserDisplay(currentUser?.address ?? ''); +### Authentication Modes + +OpChan supports three authentication modes: + +1. **Anonymous** (`ANONYMOUS`) - Browser-only session, no wallet required + - Can post, comment, and vote + - Cannot create cells + - Optional call sign for identity + +2. **Wallet Connected** (`WALLET_CONNECTED`) - Ethereum wallet connected + - Full interaction capabilities + - Can create posts, comment, vote + - Cannot create cells (requires ENS verification) + +3. **ENS Verified** (`ENS_VERIFIED`) - Wallet + ENS ownership verified + - Full platform access + - Can create cells (becomes cell admin) + - Enhanced relevance scoring for content + +### Key Delegation + +To reduce wallet signature prompts, OpChan uses browser-based key delegation: + +- **For Wallet Users**: Wallet signs authorization for browser keys (7 or 30 days) +- **For Anonymous Users**: Browser keys generated automatically (no wallet signature) + +This enables one-time wallet interaction with subsequent actions signed by browser keys. + +## API Reference + +### Hooks + +#### `useForum()` + +Convenience hook that bundles all core hooks: + +```tsx +const { user, content, permissions, network } = useForum(); +``` + +Equivalent to: +```tsx +const user = useAuth(); +const content = useContent(); +const permissions = usePermissions(); +const network = useNetwork(); +``` + +--- + +#### `useAuth()` + +Manages user session, authentication, and identity. + +**Data:** +- `currentUser: User | null` - Current authenticated user +- `verificationStatus: EVerificationStatus` - Authentication level +- `isAuthenticated: boolean` - Whether user is logged in (wallet or anonymous) +- `delegationInfo: { hasDelegation, isValid, timeRemaining?, expiresAt? }` - Delegation status + +**Actions:** +- `connect()` - Open wallet connection modal +- `disconnect()` - Disconnect wallet or exit anonymous session +- `startAnonymous(): Promise` - Start anonymous session, returns sessionId +- `verifyOwnership(): Promise` - Verify ENS ownership +- `delegate(duration: '7days' | '30days'): Promise` - Create wallet delegation +- `delegationStatus(): Promise` - Check delegation status +- `clearDelegation(): Promise` - Clear stored delegation +- `updateProfile({ callSign?, displayPreference? }): Promise` - Update user profile + +**Example:** +```tsx +function AuthButton() { + const { currentUser, connect, startAnonymous, disconnect } = useAuth(); + + if (currentUser) { + return ; + } + + return ( + <> + + + + ); +} +``` + +--- + +#### `useContent()` + +Access forum content and perform content actions. + +**Data:** +- `cells: Cell[]` - All cells +- `posts: Post[]` - All posts +- `comments: Comment[]` - All comments +- `bookmarks: Bookmark[]` - User's bookmarks +- `postsByCell: Record` - Posts grouped by cell +- `commentsByPost: Record` - Comments grouped by post +- `cellsWithStats: Cell[]` - Cells with computed stats (activeMembers, relevance) +- `userVerificationStatus: Record` - Verification cache +- `lastSync: number | null` - Last network sync timestamp +- `pending: { isPending(id), onChange(callback) }` - Pending operations tracking + +**Actions:** +- `createCell({ name, description, icon? }): Promise` +- `createPost({ cellId, title, content }): Promise` +- `createComment({ postId, content }): Promise` +- `vote({ targetId, isUpvote }): Promise` +- `moderate.post(cellId, postId, reason?)` - Moderate a post +- `moderate.unpost(cellId, postId)` - Unmoderate a post +- `moderate.comment(cellId, commentId, reason?)` - Moderate a comment +- `moderate.uncomment(cellId, commentId)` - Unmoderate a comment +- `moderate.user(cellId, userAddress, reason?)` - Moderate a user +- `moderate.unuser(cellId, userAddress)` - Unmoderate a user +- `togglePostBookmark(post, cellId?): Promise` - Toggle post bookmark +- `toggleCommentBookmark(comment, postId?): Promise` - Toggle comment bookmark +- `removeBookmark(bookmarkId): Promise` - Remove specific bookmark +- `clearAllBookmarks(): Promise` - Clear all bookmarks +- `refresh(): Promise` - Refresh content from cache + +**Example:** +```tsx +function CreatePostForm({ cellId }: { cellId: string }) { + const { createPost } = useContent(); + const [title, setTitle] = useState(''); + const [content, setContent] = useState(''); + + const handleSubmit = async () => { + const post = await createPost({ cellId, title, content }); + if (post) { + setTitle(''); + setContent(''); + } + }; + return ( +
{ e.preventDefault(); handleSubmit(); }}> + setTitle(e.target.value)} /> +