diff --git a/docs/deep_dive/architecture.md b/docs/deep_dive/architecture.md
new file mode 100644
index 0000000..84bafa9
--- /dev/null
+++ b/docs/deep_dive/architecture.md
@@ -0,0 +1,224 @@
+---
+title: Architecture Overview
+description: Understanding the Nitrolite system architecture and design principles
+keywords: [architecture, system design, nitrolite, state channels, erc7824]
+---
+
+# Architecture Overview
+
+Nitrolite's architecture represents a carefully balanced set of design decisions that prioritize performance, security, and usability while managing the inherent trade-offs in distributed systems.
+
+## Architectural Philosophy
+
+### Hybrid On-Chain/Off-Chain Design
+
+Nitrolite implements a **three-layer separation of concerns** where each layer is optimized for its specific role:
+
+- **Smart contracts** handle custody and dispute resolution
+- **ClearNode** manages high-frequency off-chain operations
+- **TypeScript SDK** provides developer-friendly abstractions
+
+**Design Rationale**: This separation allows the system to achieve high throughput (1000+ TPS per channel) while maintaining blockchain-level security guarantees. By keeping most operations off-chain, users pay gas fees only twice: when opening and closing channels.
+
+### Two-Party Channel Architecture
+
+Rather than supporting arbitrary n-party channels, Nitrolite implements a **fixed Creator/Broker model**:
+
+```solidity
+uint256 constant PART_NUM = 2;
+uint256 constant CLIENT_IDX = 0; // Channel creator
+uint256 constant SERVER_IDX = 1; // Broker in clearnet context
+```
+
+**Design Rationale**:
+- **Complexity reduction**: Two-party channels eliminate exponential complexity growth seen in n-party protocols
+- **Hub efficiency**: Brokers act as liquidity hubs, enabling users to interact with all other users through a single channel
+- **UX optimization**: Users maintain one channel instead of managing multiple peer connections
+- **Capital efficiency**: Liquidity is consolidated rather than fragmented across many channels
+
+## Core Design Decisions
+
+### Magic Number Protocol
+
+Nitrolite uses explicit "magic numbers" to indicate state transition intentions:
+
+```solidity
+uint32 constant CHANOPEN = 7877; // Funding state
+uint32 constant CHANCLOSE = 7879; // Closing state
+uint32 constant CHANRESIZE = 7883; // Resize state
+```
+
+**Design Rationale**: This prevents accidental state transitions and provides clear semantic meaning. Instead of inferring intent from state changes, the protocol requires explicit declaration, improving safety and debuggability.
+
+### Chain-Agnostic Signature Model
+
+The protocol deliberately avoids [EIP-191](https://eips.ethereum.org/EIPS/eip-191) message prefixing:
+
+> "For signature verification, the stateHash is bare signed without [EIP-191](https://eips.ethereum.org/EIPS/eip-191) since the protocol is intended to be chain-agnostic."
+
+**Design Rationale**: This enables identical protocol logic across all EVM-compatible chains without modification, supporting the multi-chain vision where users can choose their preferred blockchain based on fees and speed.
+
+### Double-Entry Ledger System
+
+ClearNode implements traditional double-entry accounting for off-chain balance tracking:
+
+```go
+type Entry struct {
+ AccountID string
+ Credit decimal.Decimal
+ Debit decimal.Decimal
+ // Credits always equal debits across the system
+}
+```
+
+**Design Rationale**:
+- **Auditability**: Complete transaction history with immutable records
+- **Consistency**: Mathematical guarantee that books balance
+- **Compliance**: Follows established financial accounting practices
+- **Precision**: Uses decimal arithmetic to avoid floating-point errors in financial calculations
+
+## Security Architecture
+
+### Challenge-Response Dispute Resolution
+
+Instead of requiring real-time monitoring, Nitrolite uses **optimistic execution** with challenge periods:
+
+```solidity
+function challenge(bytes32 channelId, State calldata candidate, State[] calldata proofs) external {
+ // Economic security through time-locked disputes
+ meta.challengeExpire = block.timestamp + meta.chan.challenge;
+ meta.stage = ChannelStatus.DISPUTE;
+}
+```
+
+**Design Rationale**: This provides economic security while allowing participants to be offline for extended periods. The system assumes good behavior but provides recourse through cryptographically verifiable challenges.
+
+### Interface Segregation Pattern
+
+The protocol separates concerns through focused interfaces:
+
+```solidity
+interface IChannel { // Channel lifecycle
+interface IDeposit { // Token custody
+interface IAdjudicator { // Application logic
+interface IComparable { // State ordering
+```
+
+**Design Rationale**: This modularity allows applications to implement only the interfaces they need, reducing attack surface and enabling compositability.
+
+## Virtual Application Architecture
+
+### Session Keys and Delegation
+
+Nitrolite supports "session keys" where channel creators can be different from fund providers:
+
+```solidity
+// NOTE: it is allowed for depositor (and wallet) to be different from channel creator (participant)
+// This enables logic of "session keys" where a user can create a channel on behalf of another account
+```
+
+**Design Rationale**: This separation improves UX by allowing high-frequency signing without exposing main wallet private keys. Applications can use hot wallets for state updates while keeping funds secured by cold storage.
+
+### Quorum-Based Virtual Ledger Channels
+
+Applications create isolated accounting contexts within channels:
+
+```go
+// Virtual applications require quorum approval for state transitions
+if totalWeight < int64(appSession.Quorum) {
+ return fmt.Errorf("quorum not met: %d / %d", totalWeight, appSession.Quorum)
+}
+```
+
+**Design Rationale**: This enables complex multi-party applications (games, voting, auctions) while maintaining the simplicity of two-party channels. Virtual applications handle business logic while the underlying channel provides security guarantees.
+
+## Multi-Chain Strategy
+
+### Asset Management Philosophy
+
+Each token-chain combination is treated as a distinct asset:
+
+```go
+type Asset struct {
+ Token string `gorm:"column:token;primaryKey"`
+ ChainID uint32 `gorm:"column:chain_id;primaryKey"`
+ Symbol string `gorm:"column:symbol;not null"`
+ Decimals uint8 `gorm:"column:decimals;not null"`
+}
+```
+
+**Design Rationale**: This prevents cross-chain confusion and enables proper decimal handling. Users explicitly choose their blockchain based on preferences for fees, speed, and finality.
+
+### Independent Chain Operation
+
+Each blockchain maintains separate custody contracts and event listeners:
+
+```go
+// Concurrent event listeners for multiple chains
+for name, network := range config.networks {
+ go client.ListenEvents(context.Background())
+}
+```
+
+**Design Rationale**: Chain independence reduces systemic risk and allows the protocol to continue operating even if individual blockchains experience issues.
+
+## Trade-off Analysis
+
+### Centralization vs. User Experience
+
+**Trade-off**: Uses broker hub model instead of fully peer-to-peer architecture
+
+Nitrolite's adoption of a broker hub model represents a fundamental architectural decision that prioritizes user experience over pure decentralization. While this approach introduces potential central points of failure where brokers could become unavailable or act maliciously, it delivers substantial user experience improvements by enabling users to maintain a single channel rather than managing multiple peer connections, while providing instant liquidity access to the entire network.
+
+The system mitigates centralization risks through economic incentives and technical safeguards. Users retain custody of their funds through on-chain smart contracts, ensuring that brokers cannot steal funds even if they act maliciously. Additionally, the protocol design allows multiple brokers to compete within the same ecosystem, preventing monopolization and providing users with choice in their infrastructure providers.
+
+### Flexibility vs. Complexity
+
+**Trade-off**: Fixed 2-party channels instead of n-party support
+
+The decision to implement fixed 2-party channels rather than supporting arbitrary n-party configurations represents a calculated trade-off between flexibility and complexity management. While this constraint prevents direct support for complex multi-party protocols at the channel level, it eliminates the exponential complexity growth that plagues n-party state channel implementations, enabling easier security analysis and more reliable implementations.
+
+Virtual ledger channels provide an elegant solution to this limitation, allowing arbitrary multi-party applications to operate within the security guarantees of 2-party channels. This approach combines the simplicity and security of bilateral channels with the functionality required for complex distributed applications.
+
+### Performance vs. Decentralization
+
+**Trade-off**: Go backend service instead of pure smart contract execution
+
+Utilizing a Go backend service rather than relying purely on smart contract execution introduces trust assumptions regarding ClearNode operators, as participants must trust that the service will process transactions honestly and remain available. However, this architectural choice enables the implementation of complex business logic that would be prohibitively expensive on-chain, achieves high transaction throughput measured in thousands of transactions per second, and delivers superior user experience through real-time interactions.
+
+The challenge/response mechanism provides critical protection against malicious operators by ensuring that all participants can validate and contest any state changes through cryptographically verifiable proofs. This trustless dispute resolution capability means that while participants must trust operators for liveness, they need not trust them for safety, as funds remain secure through on-chain enforcement.
+
+## Protocol Innovation
+
+### Array-Based RPC Messages
+
+Uses deterministic array serialization instead of object-based JSON:
+
+```json
+{
+ "req": [REQUEST_ID, METHOD, [PARAMETERS], TIMESTAMP],
+ "sig": ["SIGNATURE"]
+}
+```
+
+**Design Rationale**: Arrays provide deterministic serialization order, ensuring consistent signature generation across different JSON implementations. This prevents signature verification failures due to property ordering differences.
+
+### Intent-Based State Validation
+
+Different state types follow different validation rules:
+
+```go
+type Intent uint8
+const (
+ IntentOPERATE Intent = 0 // Normal application states
+ IntentINITIALIZE Intent = 1 // Channel funding states
+ IntentRESIZE Intent = 2 // Capacity adjustment states
+ IntentFINALIZE Intent = 3 // Channel closing states
+)
+```
+
+**Design Rationale**: This provides type safety and enables protocol evolution. New intent types can be added without breaking existing validation logic, supporting future protocol upgrades.
+
+---
+
+This architecture represents a pragmatic approach to state channels that prioritizes practical usability while maintaining cryptographic security guarantees. Each design decision reflects careful consideration of the trade-offs inherent in distributed financial systems.
diff --git a/docs/deep_dive/deployment.md b/docs/deep_dive/deployment.md
new file mode 100644
index 0000000..edbb90b
--- /dev/null
+++ b/docs/deep_dive/deployment.md
@@ -0,0 +1,231 @@
+---
+title: Production Deployment
+description: Guide for deploying Nitrolite applications to production
+keywords: [deployment, production, infrastructure, devops, scaling]
+---
+
+# Production Deployment
+
+Guide for deploying Nitrolite applications and ClearNode infrastructure to production environments.
+
+## Deployment Overview
+
+### Architecture Components
+
+
+```mermaid
+graph TB
+ subgraph "Client Applications"
+ A[Web App] --> B[TypeScript SDK]
+ C[Mobile App] --> B
+ B --> D[WebSocket Connection]
+ end
+
+ subgraph "ClearNode Infrastructure"
+ D --> E[ClearNode Server]
+ E --> F[PostgreSQL/SQLite]
+ E --> G[Prometheus Metrics]
+ end
+
+ subgraph "Blockchain Infrastructure"
+ E --> H[Ethereum RPC]
+ H --> I[Custody Contracts]
+ E --> J[Multi-Chain Support]
+ end
+
+ style A fill:#e3f2fd
+ style E fill:#f3e5f5
+ style H fill:#fff3e0
+```
+
+
+## Prerequisites
+
+### ClearNode Requirements
+
+**Minimum Production Environment:**
+- **Compute:** 2 vCPU, 4GB RAM for ClearNode
+- **Storage:** 50GB SSD with automated backups
+- **Network:** Stable internet connection with WebSocket support
+- **Database:** PostgreSQL 13+ or SQLite for development
+
+**Recommended Production Environment:**
+- **Compute:** 4 vCPU, 8GB RAM with monitoring
+- **Storage:** 200GB SSD with daily backups
+- **Network:** Load balancer with SSL termination
+- **Monitoring:** Prometheus metrics collection
+
+### Software Dependencies
+
+**ClearNode Server:**
+- **Go:** 1.21+ for building ClearNode
+- **Database:** PostgreSQL 13+ (production) or SQLite (development)
+- **RPC Access:** Infura, Alchemy, or self-hosted Ethereum nodes
+
+## Environment Configuration
+
+### ClearNode Environment Variables
+
+```bash
+# Core Configuration
+BROKER_PRIVATE_KEY=0x1234567890123456789012345678901234567890123456789012345678901234
+DATABASE_DRIVER=postgres
+DATABASE_URL=postgresql://user:password@localhost:5432/clearnode
+LOG_LEVEL=info
+HTTP_PORT=8000
+METRICS_PORT=4242
+
+# Multi-Chain Network Configuration
+POLYGON_INFURA_URL=https://polygon-mainnet.infura.io/v3/YOUR_INFURA_KEY
+POLYGON_CUSTODY_CONTRACT_ADDRESS=0xDB33fEC4e2994a675133320867a6439Da4A5acD8
+
+CELO_INFURA_URL=https://celo-mainnet.infura.io/v3/YOUR_INFURA_KEY
+CELO_CUSTODY_CONTRACT_ADDRESS=0xDB33fEC4e2994a675133320867a6439Da4A5acD8
+
+BASE_INFURA_URL=https://base-mainnet.infura.io/v3/YOUR_INFURA_KEY
+BASE_CUSTODY_CONTRACT_ADDRESS=0xYOUR_BASE_CONTRACT_ADDRESS
+
+ETH_SEPOLIA_INFURA_URL=https://sepolia.infura.io/v3/YOUR_INFURA_KEY
+ETH_SEPOLIA_CUSTODY_CONTRACT_ADDRESS=0xYOUR_SEPOLIA_CONTRACT_ADDRESS
+
+# Optional Configuration
+MSG_EXPIRY_TIME=60 # Message timestamp expiry in seconds
+```
+
+
+## ClearNode Deployment
+
+## 1. Database Setup
+
+### PostgreSQL
+
+Start PostgreSQL container:
+```bash
+docker run --rm -e POSTGRES_PASSWORD=postgres -e POSTGRES_HOST_AUTH_METHOD=trust -p 5432:5432 --name postgres postgres:16
+```
+
+### SQLite
+
+```bash
+# For development, ClearNode can use SQLite
+DATABASE_DRIVER=sqlite
+DATABASE_URL=clearnode.db
+```
+
+### Building from Source
+
+```bash
+# Clone the repository
+git clone https://github.com/erc7824/nitrolite.git
+cd nitrolite/clearnode
+
+# Set environment variables
+cp .env.example .env
+# Edit .env with your configuration
+
+# Build the binary
+go build -o clearnode ./...
+
+# Run ClearNode
+./clearnode
+```
+
+### Docker Deployment
+
+```bash
+# Build and run with Docker
+docker build -t clearnode .
+
+# Start ClearNode
+docker run -p 8000:8000 -p 4242:4242 --env-file .env clearnode
+```
+
+## Monitoring and Observability
+
+### Prometheus Metrics
+
+ClearNode provides built-in Prometheus metrics on port 4242:
+
+```bash
+# Access metrics endpoint
+curl http://localhost:4242/metrics
+```
+
+### Key Metrics
+
+```prometheus
+# Channel and ledger metrics
+clearnode_channels_total
+clearnode_active_connections
+clearnode_ledger_balance_total
+clearnode_rpc_requests_total
+clearnode_errors_total
+
+# System metrics
+clearnode_memory_usage_bytes
+clearnode_cpu_usage_percent
+clearnode_database_connections
+```
+
+## Security and Maintenance
+
+### ClearNode Security
+
+**Private Key Management:**
+- Store `BROKER_PRIVATE_KEY` securely using environment variables
+- Use hardware security modules (HSMs) for production private keys
+
+**Network Security:**
+- Use WSS for WebSocket connections in production
+- Configure firewall to allow only ports 8000 (HTTP) and 4242 (metrics)
+
+### Database Backup and Recovery
+
+```bash
+# PostgreSQL backup
+pg_dump -h localhost -U clearnode_user clearnode > clearnode_backup.sql
+
+# Restore from backup
+psql -h localhost -U clearnode_user clearnode < clearnode_backup.sql
+```
+
+### Health Checks
+
+**ClearNode Health Checks:**
+```bash
+# Check if ClearNode is responding
+curl -f http://localhost:8000/health || exit 1
+
+# Check WebSocket connectivity
+# npm install -g wscat
+wscat -c ws://localhost:8000/ws
+
+# Check metrics endpoint
+curl http://localhost:4242/metrics
+```
+
+## Troubleshooting
+
+### Common Issues
+
+**ClearNode Port Conflicts:**
+```bash
+# Check what's using port 8000
+lsof -i :8000
+
+# Change ClearNode HTTP port
+HTTP_PORT=8080
+```
+
+**ClearNode Database Issues:**
+```bash
+# Test PostgreSQL connectivity
+psql $DATABASE_URL -c "SELECT 1;"
+
+# Check if ClearNode migrations ran
+# ClearNode runs migrations automatically on startup
+```
+
+## Next Steps
+
+For ClearNode support, refer to the [ClearNode documentation](https://github.com/erc7824/nitrolite/tree/main/clearnode) or join [Discord](https://discord.gg/yellownetwork).
diff --git a/docs/deep_dive/faq.md b/docs/deep_dive/faq.md
new file mode 100644
index 0000000..8e28d79
--- /dev/null
+++ b/docs/deep_dive/faq.md
@@ -0,0 +1,349 @@
+---
+title: Technical FAQ
+description: Technical questions and implementation details for Nitrolite developers
+keywords: [faq, technical, implementation, state channels, nitrolite, developers]
+---
+
+# Technical FAQ
+
+Implementation details and technical questions for developers building with Nitrolite.
+
+## Protocol Implementation
+
+
+ How does the ClearNode RPC protocol work?
+
+
ClearNode uses JSON-RPC over WebSocket with deterministic array serialization:
+
+```json
+{
+ "req": [REQUEST_ID, METHOD, [PARAMETERS], TIMESTAMP],
+ "sig": ["ECDSA_SIGNATURE"]
+}
+```
+
+
Key Features:
+
+ - Array-based structure ensures deterministic serialization across JSON implementations
+ - Timestamp validation with 60-second expiry prevents replay attacks
+ - Session-based routing via
AppSessionID for virtual application isolation
+ - Challenge-response authentication using [EIP-712](https://eips.ethereum.org/EIPS/eip-712) structured signing
+
+
+
+
+
+
+ How does signature verification work across different chains?
+
+
Nitrolite uses chain-agnostic signature verification without [EIP-191](https://eips.ethereum.org/EIPS/eip-191) prefixing:
+
+```go
+// Raw ECDSA signing without chain-specific prefixes
+messageHash := crypto.Keccak256Hash(stateBytes)
+signature, _ := crypto.Sign(messageHash.Bytes(), privateKey)
+```
+
+
Implementation Details:
+
+ - ECDSA with secp256k1 curve (Ethereum-compatible)
+ - Keccak256 hashing for message digests
+ - 65-byte signature format (r,s,v) with v adjustment
+ - Address recovery using
crypto.SigToPub() for authentication
+
+
+
+
+
+
+ What is the channel state encoding format?
+
+
States are ABI-encoded with a specific structure:
+
+```go
+// State encoding: (channelID, intent, version, stateData, allocations[])
+args := abi.Arguments{
+ {Type: abi.Type{T: abi.FixedBytesTy, Size: 32}}, // channelID
+ {Type: intentType}, // intent (uint8)
+ {Type: versionType}, // version (uint256)
+ {Type: abi.Type{T: abi.BytesTy}}, // stateData
+ {Type: allocationType}, // allocations (tuple[])
+}
+```
+
+
Intent Types:
+
+ OPERATE(0): Normal application states
+ INITIALIZE(1): Channel funding states
+ RESIZE(2): Capacity adjustment states
+ FINALIZE(3): Channel closing states
+
+
+
+
+
+## Virtual Ledger System
+
+
+ How does the double-entry accounting work?
+
+
ClearNode implements traditional double-entry bookkeeping with DECIMAL(64,18) precision:
+
+```sql
+CREATE TABLE ledger_entries (
+ account_id VARCHAR NOT NULL,
+ wallet VARCHAR NOT NULL,
+ asset_symbol VARCHAR NOT NULL,
+ credit DECIMAL(64,18) NOT NULL,
+ debit DECIMAL(64,18) NOT NULL
+);
+```
+
+
Balance Calculation:
+
+```go
+// Balance = SUM(credit) - SUM(debit) for each (wallet, asset) pair
+balance := totalCredits.Sub(totalDebits)
+```
+
+
Account Types:
+
+ - Participant accounts: User wallet balances
+ - Virtual app accounts: Isolated application contexts
+ - System accounts: Protocol-level operations
+
+
+
+
+
+
+ How do virtual applications achieve consensus?
+
+
Virtual apps use weighted quorum-based consensus configured during channel creation:
+
+```go
+// Check if combined signature weights meet quorum threshold
+if totalWeight < int64(appSession.Quorum) {
+ return fmt.Errorf("quorum not met: %d / %d", totalWeight, appSession.Quorum)
+}
+```
+
+
Weight Configuration:
+
+```go
+type App struct {
+ Participants []address // Array of participants in the app
+ Weights []uint8 // Signers weights [50, 50, 80, 20, 20]
+ Quorum uint64 // Example: 100 would be the signature threshold
+}
+```
+
+
Consensus Flow:
+
+ - State proposal by any participant
+ - Signature collection from participants until weight threshold met
+ - Validation of weighted quorum achievement
+ - Ledger update with atomic balance transfers
+
+
+
Example Scenarios:
+
+ - Simple majority: Weights [50, 50], Quorum 51
+ - Supermajority: Weights [25, 25, 25, 25], Quorum 75
+ - Dictator + veto: Weights [80, 20], Quorum 100
+
+
+
+
+
+## Security Model
+
+
+ How does challenge/response dispute resolution work?
+
+
The system uses optimistic execution with challenge periods:
+
+```solidity
+function challenge(bytes32 channelId, State calldata candidate, State[] calldata proofs) external {
+ // Validate state via adjudicator
+ if (!IAdjudicator(meta.chan.adjudicator).adjudicate(meta.chan, candidate, proofs))
+ revert InvalidState();
+
+ // Set challenge period
+ meta.challengeExpire = block.timestamp + meta.chan.challenge;
+ meta.stage = ChannelStatus.DISPUTE;
+}
+```
+
+
Security Guarantees:
+
+ - Economic security: Funds locked in custody contracts
+ - Temporal security: Challenge periods prevent hasty closures
+ - Cryptographic security: All state transitions require valid signatures
+
+
+
+
+
+
+ How do session keys work?
+
+
Session keys enable delegation without custody transfer:
+
+```go
+// NOTE: it is allowed for depositor (and wallet) to be different from channel creator (participant)
+// This enables logic of "session keys" where a user can create a channel on behalf of another account
+```
+
+
Implementation:
+
+ - Signer mapping:
signers table maps session keys to wallet addresses
+ - Authentication flow: [EIP-712](https://eips.ethereum.org/EIPS/eip-712) structured signing for challenge-response
+ - Session management: 24-hour TTL with renewal capability
+ - Scope limitation: Session keys cannot withdraw funds, only sign state updates
+
+
+
+
+
+## Performance and Scaling
+
+
+ What are the performance bottlenecks?
+
+
+
Identified Constraints:
+
+ - Single WebSocket per wallet: Limits concurrent connections
+ - Synchronous signature verification: CPU-bound operation for each message
+ - Database balance queries: Not cached, requires computation
+ - Memory-based sessions: Cannot distribute across multiple ClearNode instances
+
+
+
+
+
+
+ How does multi-chain asset handling work?
+
+
Each token-chain combination is treated as a distinct asset:
+
+```go
+type Asset struct {
+ Token string `gorm:"column:token;primaryKey"`
+ ChainID uint32 `gorm:"column:chain_id;primaryKey"`
+ Symbol string `gorm:"column:symbol;not null"`
+ Decimals uint8 `gorm:"column:decimals;not null"`
+}
+```
+
+
Precision Handling:
+
+ - Consistent DECIMAL(64,18) across all monetary calculations
+ - Chain-specific decimals stored per asset
+ - Token address normalization per chain
+ - Independent custody contracts per supported chain
+
+
+
+
+
+
+ How does the system prevent replay attacks?
+
+
+
Multi-layer Protection:
+
+ - Timestamp validation: Messages expire after 60 seconds
+ - State version monotonicity: Version numbers must strictly increase
+ - Nonce progression: Channel nonces prevent duplicate operations
+ - Challenge periods: Time-locked dispute resolution
+
+
+
+
+
+## Integration Considerations
+
+
+ How do you handle WebSocket connection management?
+
+
+
Connection Lifecycle:
+
+```go
+// Authentication-first connection establishment
+func (h *UnifiedWSHandler) authenticateConnection(ws *websocket.Conn) error {
+ // Challenge-response authentication
+ // Session token generation
+ // Connection registration per wallet
+}
+```
+
+
Features:
+
+ - One connection per wallet: Latest connection replaces previous
+ - Message forwarding: Based on app session participants
+ - Graceful error handling: Structured error responses
+ - Metrics tracking: Connections, messages, auth events
+
+
+
+
+
+
+ What database schema optimizations are recommended?
+
+
+
Critical Indexes:
+
+```sql
+-- Balance calculation optimization
+CREATE INDEX idx_ledger_wallet_asset ON ledger_entries(wallet, asset_symbol);
+
+-- Channel lookup optimization
+CREATE INDEX idx_channels_participant ON channels(participant);
+
+-- Session routing optimization
+CREATE INDEX idx_app_sessions_participants ON app_sessions USING gin(participants);
+```
+
+
Schema Considerations:
+
+ - DECIMAL precision: Use DECIMAL(64,18) for all monetary values
+ - UUID vs incremental IDs: UUIDs for app sessions, incremental for performance-critical tables
+ - Partitioning: Consider partitioning ledger_entries by time for large deployments
+
+
+
+
+
+
+ How do you implement custom adjudicators?
+
+
Custom adjudicators must implement the IAdjudicator interface:
+
+```solidity
+interface IAdjudicator {
+ function adjudicate(
+ Channel calldata chan,
+ State calldata candidate,
+ State[] calldata proofs
+ ) external view returns (bool valid);
+}
+```
+
+
Implementation Patterns:
+
+ - Stateless validation: Pure functions based on provided proofs
+ - State transition rules: Validate moves from previous to current state
+ - Business logic: Game rules, payment conditions, etc.
+ - Proof requirements: Define what constitutes valid state transitions
+
+
+
+
+
+---
+
+For additional technical details, consult the [Architecture Overview](architecture/) or examine the [ClearNode source code](https://github.com/erc7824/nitrolite/tree/main/clearnode).
\ No newline at end of file
diff --git a/docs/deep_dive/index.mdx b/docs/deep_dive/index.mdx
new file mode 100644
index 0000000..e249a35
--- /dev/null
+++ b/docs/deep_dive/index.mdx
@@ -0,0 +1,48 @@
+---
+title: Deep Dive
+description: Technical deep dive into Nitrolite implementation and architecture
+keywords: [deep dive, technical, architecture, implementation, advanced]
+---
+
+import { Card, CardGrid } from '@site/src/components/Card';
+
+# Deep Dive
+
+Technical deep dive documentation for developers building with Nitrolite, operating ClearNode infrastructure, and implementing virtual applications.
+
+
+
+
+
+
+
+
+
+---
+
+These documents are intended for technical experts who need to understand implementation details, security considerations, and operational requirements when working with Nitrolite.
\ No newline at end of file
diff --git a/docs/deep_dive/security.md b/docs/deep_dive/security.md
new file mode 100644
index 0000000..be36621
--- /dev/null
+++ b/docs/deep_dive/security.md
@@ -0,0 +1,475 @@
+---
+title: Virtual Application Security
+description: Security considerations for building secure virtual applications on Nitrolite
+keywords: [security, virtual applications, adjudicators, consensus, quorum, state validation]
+---
+
+# Virtual Application Security
+
+Security considerations and implementation patterns for developers building virtual applications on Nitrolite's virtual ledger system.
+
+## Adjudicator Security Patterns
+
+### Signature Validation Requirements
+
+Virtual applications must implement robust signature validation in their adjudicators:
+
+```solidity
+contract MyGameAdjudicator is IAdjudicator {
+ function adjudicate(Channel calldata chan, State calldata candidate, State[] calldata proofs)
+ external view override returns (bool valid) {
+
+ // CRITICAL: Always validate unanimous signatures for state transitions
+ if (!candidate.validateUnanimousSignatures(chan)) {
+ return false;
+ }
+
+ // Validate application-specific business logic
+ return validateGameMove(candidate, proofs);
+ }
+}
+```
+
+**Common Vulnerabilities**
+
+**The most critical vulnerability pattern in virtual application development involves inadequate signature validation. Applications that accept states without proper signature verification create immediate attack vectors for malicious actors.** This risk is compounded when developers fail to validate that all required participants have properly signed state transitions, potentially allowing unauthorized state changes.
+
+Equally dangerous is the failure to enforce version progression in state validation, which enables signature replay attacks where previously valid signatures are reused to manipulate application state.
+
+### State Transition Validation
+
+Implement strict state transition logic to prevent manipulation:
+
+```solidity
+function _validateTransition(State memory previous, State memory current) internal pure returns (bool) {
+ // CRITICAL: Enforce version progression
+ if (current.version != previous.version + 1) {
+ return false;
+ }
+
+ // CRITICAL: Validate allocation conservation
+ if (!_validateAllocationConservation(previous.allocations, current.allocations)) {
+ return false;
+ }
+
+ // Application-specific transition rules
+ return _validateBusinessLogic(previous, current);
+}
+```
+
+## Quorum-Based Consensus Vulnerabilities
+
+### Weight Manipulation Attacks
+
+Virtual applications use weighted quorum consensus that can be vulnerable to manipulation:
+
+```go
+// Vulnerable: Accepting weight configurations without validation
+type VirtualApp struct {
+ Participants []string `json:"participants"`
+ Weights []uint64 `json:"weights"` // Potential manipulation vector
+ Quorum uint64 `json:"quorum"` // Must validate against total weights
+}
+```
+
+**Attack Vectors**
+
+**Weight manipulation represents one of the most sophisticated attack vectors against quorum-based consensus systems. Malicious actors may attempt to assign disproportionate weights to compromised participants, effectively granting themselves outsized control over consensus decisions.** This is often combined with quorum threshold bypass attacks, where the required consensus threshold is deliberately set lower than the combined weight of honest participants.
+
+```mermaid
+graph TB
+ subgraph "Legitimate Configuration"
+ A1["Alice: 25%"]
+ B1["Bob: 25%"]
+ C1["Carol: 25%"]
+ D1["Dave: 25%"]
+ Q1["Quorum: 67% (3 participants)"]
+ end
+
+ subgraph "Manipulated Configuration"
+ A2["Alice: 10%"]
+ B2["Bob: 10%"]
+ C2["Carol: 10%"]
+ M1["Mallory: 35%"]
+ M2["Mallory Alt: 35%"]
+ Q2["Quorum: 51% (Mallory controls)"]
+ end
+
+ subgraph "Zero Weight Attack"
+ A3["Alice: 50%"]
+ B3["Bob: 50%"]
+ Z1["Zero1: 0%"]
+ Z2["Zero2: 0%"]
+ Z3["Zero3: 0%"]
+ Q3["Quorum: 51% (confusion in validation)"]
+ end
+```
+
+A particularly subtle attack involves including participants with zero weight to dilute consensus calculations. While these participants cannot directly influence voting outcomes, they can be used to manipulate quorum calculations and create confusion in consensus validation logic.
+
+**Mitigation Patterns:**
+```go
+func validateQuorumConfiguration(participants []string, weights []uint64, quorum uint64) error {
+ if len(participants) != len(weights) {
+ return fmt.Errorf("participants and weights length mismatch")
+ }
+
+ totalWeight := uint64(0)
+ for _, weight := range weights {
+ if weight == 0 {
+ return fmt.Errorf("zero weights not allowed")
+ }
+ totalWeight += weight
+ }
+
+ // Require supermajority for security
+ minQuorum := (totalWeight * 2) / 3 + 1
+ if quorum < minQuorum {
+ return fmt.Errorf("quorum too low: %d, minimum: %d", quorum, minQuorum)
+ }
+
+ return nil
+}
+```
+
+### Consensus Bypassing
+
+ClearNode validates consensus but applications must implement additional checks:
+
+```go
+// In virtual application handler
+if totalWeight < int64(appSession.Quorum) {
+ return fmt.Errorf("quorum not met: %d / %d", totalWeight, appSession.Quorum)
+}
+```
+
+**Security Requirements**
+
+Robust quorum-based consensus requires careful attention to signature weight aggregation, ensuring that weights from valid signatures are correctly summed and verified against participant configurations. **The system must implement strict threshold enforcement, automatically rejecting any state transitions that fail to meet established quorum requirements.**
+
+Participant validation forms a critical component of security, requiring verification that all signers are legitimate participants with correctly assigned weights. This validation must occur before any consensus calculations to prevent unauthorized participants from influencing application state.
+
+## Fund Isolation and Balance Security
+
+### Virtual Ledger Manipulation
+
+Virtual applications create isolated accounting contexts that can be vulnerable:
+
+```sql
+-- Virtual app accounts use session IDs as account identifiers
+INSERT INTO ledger_entries (account_id, wallet, asset_symbol, credit, debit)
+VALUES ('session_abc123', 'participant_wallet', 'USDC', 0, 100.0);
+```
+
+**Attack Vectors**
+
+**Double spending attacks represent the most direct threat, where malicious participants attempt to spend the same funds simultaneously across multiple virtual applications.** This is particularly dangerous in systems where balance validation occurs independently within each application context.
+
+```mermaid
+sequenceDiagram
+ participant U as User
+ participant A1 as Virtual App 1
+ participant A2 as Virtual App 2
+ participant VL as Virtual Ledger
+
+ Note over U,VL: Double Spending Attack
+ U->>A1: Spend 100 USDC
+ U->>A2: Spend 100 USDC (same funds)
+
+ A1->>VL: Validate balance: 100 USDC
+ VL-->>A1: ✓ Valid (independent check)
+ A2->>VL: Validate balance: 100 USDC
+ VL-->>A2: ✓ Valid (independent check)
+
+ Note over A1,A2: Both apps accept transaction
+ A1->>VL: Debit 100 USDC
+ A2->>VL: Debit 100 USDC
+
+ Note over VL: Balance: -100 USDC (compromised)
+```
+
+Balance inflation attacks exploit weaknesses in double-entry accounting implementations, where attackers create credits without corresponding debits, effectively creating funds from nothing. Cross-session leakage represents a more sophisticated attack where participants gain unauthorized access to funds from virtual applications they should not be able to access.
+
+**Security Implementation:**
+```go
+func (vl *VirtualLedger) TransferFunds(from, to, asset string, amount decimal.Decimal) error {
+ return vl.db.Transaction(func(tx *gorm.DB) error {
+ // CRITICAL: Atomic balance validation and transfer
+ fromBalance, err := vl.GetBalance(from, asset)
+ if err != nil {
+ return err
+ }
+
+ if fromBalance.LessThan(amount) {
+ return fmt.Errorf("insufficient balance: %s < %s", fromBalance, amount)
+ }
+
+ // CRITICAL: Atomic debit/credit operations
+ if err := vl.RecordTransaction(from, asset, amount.Neg(), tx); err != nil {
+ return err
+ }
+
+ return vl.RecordTransaction(to, asset, amount, tx)
+ })
+}
+```
+
+### Session Isolation Enforcement
+
+Ensure virtual applications cannot access funds from other sessions:
+
+```go
+func validateSessionAccess(sessionID string, participantWallet string, appSession *AppSession) error {
+ // CRITICAL: Verify participant is authorized for this session
+ for _, participant := range appSession.ParticipantWallets {
+ if participant == participantWallet {
+ return nil
+ }
+ }
+ return fmt.Errorf("unauthorized access to session %s", sessionID)
+}
+```
+
+## Application State Validation
+
+### Business Logic Security
+
+Implement comprehensive validation for application-specific state transitions:
+
+```solidity
+contract TicTacToeAdjudicator is IAdjudicator {
+ struct GameState {
+ uint8[9] board; // 0=empty, 1=player1, 2=player2
+ uint8 currentPlayer; // 1 or 2
+ bool gameEnded;
+ }
+
+ function adjudicate(Channel calldata chan, State calldata candidate, State[] calldata proofs)
+ external view override returns (bool valid) {
+
+ if (proofs.length != 1) return false;
+
+ GameState memory prevGame = abi.decode(proofs[0].data, (GameState));
+ GameState memory currGame = abi.decode(candidate.data, (GameState));
+
+ // CRITICAL: Validate turn order
+ if (currGame.currentPlayer == prevGame.currentPlayer) {
+ return false; // Same player cannot move twice
+ }
+
+ // CRITICAL: Validate single move
+ uint8 moveCount = 0;
+ for (uint i = 0; i < 9; i++) {
+ if (prevGame.board[i] != currGame.board[i]) {
+ if (prevGame.board[i] != 0) return false; // Cannot overwrite
+ if (currGame.board[i] != prevGame.currentPlayer) return false; // Wrong player
+ moveCount++;
+ }
+ }
+
+ return moveCount == 1; // Exactly one move allowed
+ }
+}
+```
+
+### State Encoding Security
+
+Use proper ABI encoding to prevent state manipulation:
+
+```solidity
+// GOOD: Structured encoding
+struct ApplicationData {
+ uint256 gameId;
+ bytes32 moveHash;
+ uint64 timestamp;
+}
+
+// BAD: Raw bytes that can be manipulated
+// bytes applicationData;
+```
+
+## Session Management Security
+
+### Authentication in Virtual Applications
+
+Virtual applications inherit ClearNode's authentication but should implement additional checks:
+
+```go
+func (h *VirtualAppHandler) validateParticipant(sessionID string, walletAddress string) error {
+ // CRITICAL: Verify participant is part of this virtual application
+ appSession, err := h.getAppSession(sessionID)
+ if err != nil {
+ return err
+ }
+
+ for _, participant := range appSession.ParticipantWallets {
+ if strings.EqualFold(participant, walletAddress) {
+ return nil
+ }
+ }
+
+ return fmt.Errorf("wallet %s not authorized for session %s", walletAddress, sessionID)
+}
+```
+
+### Session Lifecycle Security
+
+Implement proper session creation and termination:
+
+```go
+func createVirtualApplication(participants []string, weights []uint64, quorum uint64) error {
+ // CRITICAL: Validate all participants have active channels with broker
+ for _, participant := range participants {
+ if !h.hasActiveChannel(participant) {
+ return fmt.Errorf("participant %s has no active channel", participant)
+ }
+ }
+
+ // CRITICAL: Validate quorum configuration
+ if err := validateQuorumConfiguration(participants, weights, quorum); err != nil {
+ return err
+ }
+
+ // CRITICAL: Ensure sufficient funds for virtual application
+ return h.validateSufficientFunds(participants)
+}
+```
+
+## Race Conditions and Atomicity
+
+### Concurrent State Updates
+
+Virtual applications must handle concurrent updates safely:
+
+```go
+func (vl *VirtualLedger) UpdateState(sessionID string, newState ApplicationState) error {
+ // CRITICAL: Use database transactions for atomicity
+ return vl.db.Transaction(func(tx *gorm.DB) error {
+ // Lock session for update
+ var session AppSession
+ if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
+ Where("session_id = ?", sessionID).First(&session).Error; err != nil {
+ return err
+ }
+
+ // Validate state version progression
+ if newState.Version != session.Version + 1 {
+ return fmt.Errorf("invalid version progression")
+ }
+
+ // Apply state update atomically
+ session.Version = newState.Version
+ return tx.Save(&session).Error
+ })
+}
+```
+
+### Fund Transfer Atomicity
+
+Ensure fund transfers are atomic across multiple operations:
+
+```go
+func (vl *VirtualLedger) ExecuteMultiPartyTransfer(transfers []Transfer) error {
+ return vl.db.Transaction(func(tx *gorm.DB) error {
+ // CRITICAL: Validate all transfers before executing any
+ for _, transfer := range transfers {
+ balance, err := vl.GetBalanceInTx(transfer.From, transfer.Asset, tx)
+ if err != nil {
+ return err
+ }
+ if balance.LessThan(transfer.Amount) {
+ return fmt.Errorf("insufficient balance for %s", transfer.From)
+ }
+ }
+
+ // Execute all transfers atomically
+ for _, transfer := range transfers {
+ if err := vl.ExecuteTransferInTx(transfer, tx); err != nil {
+ return err // Automatic rollback
+ }
+ }
+
+ return nil
+ })
+}
+```
+
+## Security Guidelines for Virtual Application Developers
+
+### Adjudicator Implementation Security
+
+**Secure adjudicator implementation forms the foundation of virtual application security. Every state transition must undergo unanimous signature validation to ensure all required participants have authorized the change.** This validation must be coupled with strict version progression enforcement, where each new state version must exactly equal the previous version plus one, preventing both replay attacks and state manipulation.
+
+```mermaid
+flowchart TD
+ A["State Transition Request"] --> B["Check Signatures"]
+ B --> C["Check Version"]
+ C --> D["Check Allocation"]
+ D --> F["Check Business Logic"]
+ F --> G["Check ABI Encoding"]
+ G --> H["✅ Accept State"]
+
+ B -.->|❌ Invalid| E["❌ Reject"]
+ C -.->|❌ Invalid| E
+ D -.->|❌ Invalid| E
+ F -.->|❌ Invalid| E
+ G -.->|❌ Invalid| E
+
+ style A fill:#e3f2fd
+ style H fill:#c8e6c9
+ style E fill:#ffcdd2
+```
+
+Allocation conservation represents a critical financial security requirement, ensuring that the total value within the system remains constant across state transitions. Application-specific business logic validation must be implemented comprehensively to prevent manipulation of game rules or payment conditions. All state data should utilize structured ABI encoding to prevent ambiguity and ensure deterministic serialization across different implementations.
+
+### Quorum Configuration Security
+
+Proper quorum configuration requires meticulous validation of participant and weight configurations. The system must verify that participant counts exactly match weight counts to prevent configuration errors that could compromise consensus. **Zero or negative weights must be explicitly rejected, as they can be exploited to manipulate consensus calculations or create undefined behavior.**
+
+Minimum quorum thresholds should enforce supermajority requirements, typically requiring at least 67% of total weight for security-critical operations. Total weight calculations must be validated to prevent overflow conditions or mathematical errors that could compromise consensus integrity. Critical operations should implement enhanced supermajority requirements to provide additional security against coordinated attacks.
+
+### Fund Management Security
+
+**Financial security requires atomic database transactions for all fund operations to prevent race conditions and ensure consistency.** Every transfer operation must validate sufficient balances before execution, preventing overdraft conditions that could compromise system integrity. Session isolation must be properly implemented to prevent unauthorized access to funds from different virtual applications.
+
+Regular auditing of virtual ledger balance calculations helps detect discrepancies or computational errors that could indicate security breaches or implementation bugs. Cross-session fund access must be prevented through strict access controls and session validation to maintain the isolation guarantees that enable secure multi-tenancy.
+
+### Session Security Management
+
+Participant authorization validation ensures that only legitimate users can access virtual applications they are authorized to participate in. **Session lifecycle management must be implemented comprehensively, covering creation, operation, and termination phases with appropriate security controls at each stage.**
+
+```mermaid
+stateDiagram-v2
+ [*] --> Creation
+ Creation --> AuthValidation: Validate participants
+ AuthValidation --> QuorumCheck: Check weights & quorum
+ QuorumCheck --> Operation: Session active
+
+ Operation --> StateUpdate: Process transactions
+ StateUpdate --> SignatureVerify: Validate signatures
+ SignatureVerify --> Operation: Continue session
+
+ Operation --> Timeout: Session expires
+ Operation --> Termination: Manual close
+
+ Timeout --> Cleanup: Force cleanup
+ Termination --> FinalSettlement: Settle balances
+ FinalSettlement --> Cleanup: Clean resources
+ Cleanup --> [*]
+
+ AuthValidation --> [*]: Validation failed
+ QuorumCheck --> [*]: Quorum invalid
+ SignatureVerify --> [*]: Signature invalid
+```
+
+Database locking mechanisms are essential for handling concurrent state updates safely, preventing race conditions that could lead to inconsistent state or financial discrepancies. State version progression must be validated continuously to maintain the temporal ordering that underlies the security model. Session timeout mechanisms provide protection against abandoned sessions and help prevent resource exhaustion attacks.
+
+### Business Logic Security
+
+**Application-specific validation must encompass all possible state transitions according to the defined rules of the virtual application.** Turn-based applications require special consideration to prevent players from taking multiple consecutive actions or skipping opponents' turns. Comprehensive validation prevents illegal moves or state manipulations that could compromise fair play or financial integrity.
+
+Deterministic state encoding ensures that all participants interpret application state identically, preventing disputes arising from encoding ambiguities. Game and application termination conditions must be properly implemented to ensure clean resource cleanup and final settlement of participant balances.
+
+---
+
+These security guidelines provide a comprehensive framework for developing secure virtual applications on Nitrolite. For practical implementation examples demonstrating these principles, examine the [Consensus](https://github.com/erc7824/nitrolite/blob/main/contract/src/adjudicators/Consensus.sol) and [Remittance](https://github.com/erc7824/nitrolite/blob/main/contract/src/adjudicators/Remittance.sol) adjudicators in the Nitrolite repository.
diff --git a/docs/deep_dive/troubleshooting.md b/docs/deep_dive/troubleshooting.md
new file mode 100644
index 0000000..497802a
--- /dev/null
+++ b/docs/deep_dive/troubleshooting.md
@@ -0,0 +1,519 @@
+---
+title: Troubleshooting
+description: Common issues and solutions when working with Nitrolite
+keywords: [troubleshooting, debug, errors, common issues, nitrolite, support]
+---
+
+# Troubleshooting
+
+Common issues and solutions when working with the Nitrolite SDK.
+
+## Installation Issues
+
+### Node.js Version Compatibility
+
+**Problem:** Getting errors during installation or runtime related to Node.js version.
+
+**Solution:**
+```bash
+# Check your current Node.js version
+node --version
+
+# Nitrolite requires Node.js 18+
+# Install using nvm (recommended)
+nvm install 18
+nvm use 18
+npm install @erc7824/nitrolite
+```
+
+### Package Resolution Errors
+
+**Problem:** `Cannot resolve module` or `Module not found` errors.
+
+**Solution:**
+```bash
+# Clear npm cache
+npm cache clean --force
+
+# Delete node_modules and reinstall
+rm -rf node_modules package-lock.json
+npm install
+
+# For yarn users
+yarn cache clean
+rm -rf node_modules yarn.lock
+yarn install
+```
+
+### Webpack/Bundler Issues
+
+**Problem:** Build errors in React, Vue, or other frameworks.
+
+**Solution for Webpack 5:**
+```javascript
+// webpack.config.js or next.config.js
+module.exports = {
+ resolve: {
+ fallback: {
+ "crypto": require.resolve("crypto-browserify"),
+ "stream": require.resolve("stream-browserify"),
+ "buffer": require.resolve("buffer"),
+ "process": require.resolve("process/browser"),
+ }
+ },
+ plugins: [
+ new webpack.ProvidePlugin({
+ Buffer: ['buffer', 'Buffer'],
+ process: 'process/browser',
+ }),
+ ],
+};
+```
+
+## Connection Issues
+
+### WebSocket Connection Failed
+
+**Problem:** Cannot connect to ClearNode.
+
+**Solution:**
+```javascript
+// Check your WebSocket URL format
+const ws = new WebSocket('wss://your-clearnode-domain.com/ws');
+
+ws.onerror = (error) => {
+ console.error('WebSocket connection failed:', error);
+
+ // Check if ClearNode is running
+ console.log('ClearNode should be running on port 8000');
+
+ // Implement retry logic
+ if (ws.readyState === WebSocket.CLOSED) {
+ setTimeout(() => {
+ console.log('Retrying connection...');
+ // Retry connection with exponential backoff
+ }, Math.min(1000 * Math.pow(2, retryCount), 30000));
+ }
+};
+
+// For local development
+const localWs = new WebSocket('ws://localhost:8000/ws');
+```
+
+### Provider Connection Issues
+
+**Problem:** Ethereum provider not connecting or throwing errors.
+
+**Solution:**
+```javascript
+// Check if MetaMask is installed
+if (typeof window.ethereum === 'undefined') {
+ throw new Error('MetaMask not installed');
+}
+
+// Request account access
+try {
+ await window.ethereum.request({ method: 'eth_requestAccounts' });
+} catch (error) {
+ if (error.code === 4001) {
+ console.error('User rejected the request');
+ } else {
+ console.error('Unexpected error:', error);
+ }
+}
+
+// Check network (example for Polygon)
+const chainId = await window.ethereum.request({ method: 'eth_chainId' });
+if (chainId !== '0x89') { // Polygon Mainnet
+ // Request network switch
+ await window.ethereum.request({
+ method: 'wallet_switchEthereumChain',
+ params: [{ chainId: '0x89' }],
+ });
+}
+```
+
+## Channel Operations
+
+### Channel Creation Failing
+
+**Problem:** Channel creation transactions fail or timeout.
+
+**Common Causes & Solutions:**
+
+1. **Insufficient Gas:**
+```typescript
+// Use Viem for gas estimation
+import { estimateGas } from 'viem/actions';
+
+const gasEstimate = await estimateGas(publicClient, {
+ account: account.address,
+ to: custodyContractAddress,
+ data: callData,
+});
+
+// Add 20% buffer
+const gasLimit = (gasEstimate * 120n) / 100n;
+```
+
+2. **Insufficient Balance:**
+```typescript
+// Check balance before operations
+import { getBalance } from 'viem/actions';
+
+const balance = await getBalance(publicClient, {
+ address: account.address,
+});
+
+const requiredAmount = parseEther("0.1");
+if (balance < requiredAmount) {
+ throw new Error(`Insufficient balance. Required: ${formatEther(requiredAmount)} ETH`);
+}
+```
+
+3. **Wrong Network:**
+```typescript
+// Verify you're on the correct network
+const chainId = await publicClient.getChainId();
+const expectedChainId = 137; // Polygon
+
+if (chainId !== expectedChainId) {
+ throw new Error(`Wrong network. Expected ${expectedChainId}, got ${chainId}`);
+}
+```
+
+### State Update Failures
+
+**Problem:** Off-chain state updates not being accepted.
+
+**Solution:**
+```typescript
+// Check state version progression
+const currentState = await channel.getState();
+console.log('Current version:', currentState.version);
+
+// Ensure proper participant signing
+const expectedSigner = currentState.version % 2 === 0 ? creatorAddress : brokerAddress;
+console.log('Expected signer:', expectedSigner);
+
+// Verify signature with Viem
+import { verifyMessage } from 'viem';
+
+const isValid = await verifyMessage({
+ address: expectedSigner,
+ message: stateHash,
+ signature: signature
+});
+
+if (!isValid) {
+ throw new Error('Invalid signature');
+}
+```
+
+## Common Error Codes
+
+### Error: `INVALID_SIGNATURE`
+
+**Cause:** Signature verification failed.
+
+**Solution:**
+```typescript
+// Ensure you're signing the correct state hash format
+import { keccak256, encodePacked } from 'viem';
+
+const stateHash = keccak256(encodePacked(
+ ['bytes32', 'bytes', 'uint256', 'tuple(address,address,uint256)[]'],
+ [channelId, state.data, state.version, state.allocations]
+));
+
+const signature = await walletClient.signMessage({
+ account,
+ message: { raw: stateHash }
+});
+
+// Verify signature locally
+const isValid = await verifyMessage({
+ address: account.address,
+ message: { raw: stateHash },
+ signature
+});
+```
+
+### Error: `CHANNEL_NOT_FOUND`
+
+**Cause:** Trying to operate on a non-existent channel.
+
+**Solution:**
+```typescript
+// Verify channel exists on-chain
+import { readContract } from 'viem/actions';
+
+const channelExists = await readContract(publicClient, {
+ address: custodyContractAddress,
+ abi: custodyAbi,
+ functionName: 'channelExists',
+ args: [channelId]
+});
+
+if (!channelExists) {
+ console.error('Channel does not exist:', channelId);
+ // Create channel first or verify channel ID calculation
+}
+
+// Check channel status
+const channelStatus = await readContract(publicClient, {
+ address: custodyContractAddress,
+ abi: custodyAbi,
+ functionName: 'getChannelStatus',
+ args: [channelId]
+});
+```
+
+### Error: `INSUFFICIENT_FUNDS`
+
+**Cause:** Not enough funds in channel for operation.
+
+**Solution:**
+```javascript
+// Check channel balance
+const balance = await nitroliteClient.getChannelBalance(channelId);
+console.log('Channel balance:', balance);
+
+// Check individual allocations
+const allocations = await nitroliteClient.getAllocations(channelId);
+console.log('Current allocations:', allocations);
+
+// Resize channel if needed
+if (balance.lt(requiredAmount)) {
+ await nitroliteClient.resizeChannel({
+ channelId,
+ additionalAmount: requiredAmount.sub(balance),
+ });
+}
+```
+
+## Performance Issues
+
+### Slow Transaction Processing
+
+**Problem:** Transactions taking too long to process.
+
+**Solutions:**
+
+1. **Optimize Gas Settings:**
+```javascript
+// Use [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) gas pricing
+const tx = await nitroliteClient.deposit({
+ // ... other params
+ maxFeePerGas: ethers.parseUnits('20', 'gwei'),
+ maxPriorityFeePerGas: ethers.parseUnits('2', 'gwei'),
+});
+```
+
+2. **Batch Operations:**
+```javascript
+// Instead of multiple single operations
+const operations = [
+ { type: 'transfer', to: addr1, amount: '100' },
+ { type: 'transfer', to: addr2, amount: '200' },
+];
+
+// Batch them in a single state update
+await nitroliteClient.batchOperations(channelId, operations);
+```
+
+### Memory Leaks
+
+**Problem:** Memory usage growing over time.
+
+**Solution:**
+```javascript
+// Properly close WebSocket connections
+const cleanup = () => {
+ if (ws) {
+ ws.close();
+ ws = null;
+ }
+
+ // Remove event listeners
+ window.removeEventListener('beforeunload', cleanup);
+};
+
+window.addEventListener('beforeunload', cleanup);
+
+// Clean up client resources
+await nitroliteClient.disconnect();
+```
+
+## Development Environment
+
+### TypeScript Errors
+
+**Problem:** Type errors when using TypeScript.
+
+**Solution:**
+```bash
+# Install type definitions
+npm install --save-dev @types/node @types/ws
+
+# Add to tsconfig.json
+{
+ "compilerOptions": {
+ "moduleResolution": "node",
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true
+ }
+}
+```
+
+### Hot Reload Issues
+
+**Problem:** Changes not reflecting during development.
+
+**Solution:**
+```javascript
+// For webpack-dev-server
+module.exports = {
+ devServer: {
+ hot: true,
+ // Add polling for file changes
+ watchOptions: {
+ poll: 1000,
+ },
+ },
+};
+```
+
+## ClearNode Issues
+
+### ClearNode Won't Start
+
+**Problem:** ClearNode binary fails to start.
+
+**Solution:**
+```bash
+# Check if required environment variables are set
+echo $BROKER_PRIVATE_KEY
+echo $DATABASE_URL
+
+# Check if ports are available
+lsof -i :8000 # HTTP port
+lsof -i :4242 # Metrics port
+
+# Check database connectivity
+psql $DATABASE_URL -c "SELECT 1;"
+
+# Start with debug logging
+LOG_LEVEL=debug ./clearnode
+```
+
+### Database Connection Errors
+
+**Problem:** ClearNode can't connect to database.
+
+**Solution:**
+```bash
+# For PostgreSQL
+psql $DATABASE_URL -c "SELECT version();"
+
+# Check database permissions
+psql $DATABASE_URL -c "CREATE TABLE test_table (id int);"
+psql $DATABASE_URL -c "DROP TABLE test_table;"
+
+# For SQLite
+DATABASE_DRIVER=sqlite DATABASE_URL=clearnode.db ./clearnode
+```
+
+### RPC Connection Issues
+
+**Problem:** Blockchain RPC calls failing.
+
+**Solution:**
+```bash
+# Test RPC connectivity
+curl -X POST $POLYGON_INFURA_URL \
+ -H "Content-Type: application/json" \
+ -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
+
+# Check rate limits
+echo "Check your Infura/Alchemy rate limits"
+
+# Use alternative RPC providers
+POLYGON_INFURA_URL=https://polygon-rpc.com ./clearnode
+```
+
+## Getting Debug Information
+
+### Enable Debug Logging
+
+```bash
+# For ClearNode
+LOG_LEVEL=debug ./clearnode
+
+# For client applications
+localStorage.setItem('debug', 'nitrolite:*');
+```
+
+### Inspect WebSocket Messages
+
+```javascript
+// Log all WebSocket messages
+const originalSend = WebSocket.prototype.send;
+WebSocket.prototype.send = function(data) {
+ console.log('WS Send:', data);
+ return originalSend.call(this, data);
+};
+
+ws.addEventListener('message', (event) => {
+ console.log('WS Receive:', event.data);
+});
+```
+
+### ClearNode Metrics
+
+```bash
+# Check ClearNode health
+curl http://localhost:4242/metrics
+
+# Monitor key metrics
+curl http://localhost:4242/metrics | grep clearnode_errors_total
+curl http://localhost:4242/metrics | grep clearnode_active_connections
+```
+
+### Export Debug Information
+
+```typescript
+// Generate debug report for client issues
+const debugInfo = {
+ sdkVersion: '@erc7824/nitrolite@1.0.0',
+ chainId: await publicClient.getChainId(),
+ blockNumber: await publicClient.getBlockNumber(),
+ userAddress: account.address,
+ balance: await getBalance(publicClient, { address: account.address }),
+ timestamp: new Date().toISOString(),
+};
+
+console.log('Debug Info:', JSON.stringify(debugInfo, null, 2));
+```
+
+## Getting Help
+
+If you can't resolve your issue:
+
+1. **Check existing issues:** [GitHub Issues](https://github.com/erc7824/nitrolite/issues)
+2. **Search documentation:** Use the search function on this site
+3. **Join the community:** [Discord](https://discord.gg/yellownetwork)
+4. **Report a bug:** Include debug information and steps to reproduce
+
+### When Reporting Issues
+
+Please include:
+- Nitrolite SDK version (`@erc7824/nitrolite`)
+- ClearNode version (if self-hosting)
+- Node.js/browser version
+- Operating system
+- Network and contract addresses
+- Code snippet that reproduces the issue
+- Error messages and stack traces
+- Debug information and metrics
\ No newline at end of file
diff --git a/docs/nitrolite_client/advanced/abstract-accounts.md b/docs/nitrolite_client/advanced/abstract-accounts.md
index ce7b5e4..d717f08 100644
--- a/docs/nitrolite_client/advanced/abstract-accounts.md
+++ b/docs/nitrolite_client/advanced/abstract-accounts.md
@@ -33,7 +33,7 @@ These methods allow you to prepare transactions for the entire channel lifecycle
`}
example={`// Prepare deposit transaction(s) - may include ERC20 approval
@@ -51,7 +51,7 @@ for (const tx of txs) {
`}
example={`// Prepare approval transaction
diff --git a/docs/nitrolite_client/advanced/index.md b/docs/nitrolite_client/advanced/index.md
index 01f03d6..6917d12 100644
--- a/docs/nitrolite_client/advanced/index.md
+++ b/docs/nitrolite_client/advanced/index.md
@@ -20,7 +20,7 @@ The NitroliteClient is built on top of specialized services that can be used dir
### Account Abstraction Integration
-- [Abstract Accounts](./abstract-accounts.md) - Using NitroliteClient with ERC-4337 Account Abstraction for smart contract wallets
+- [Abstract Accounts](./abstract-accounts.md) - Using NitroliteClient with [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) Account Abstraction for smart contract wallets
## When to Use Advanced Features
diff --git a/docs/nitrolite_client/index.mdx b/docs/nitrolite_client/index.mdx
index d56e022..cb016cc 100644
--- a/docs/nitrolite_client/index.mdx
+++ b/docs/nitrolite_client/index.mdx
@@ -11,6 +11,53 @@ import { Card, CardGrid } from '@site/src/components/Card';
The `NitroliteClient` class is the main entry point for interacting with Nitrolite state channels. It provides a comprehensive set of methods for managing channels, deposits, and funds.
+
+```mermaid
+flowchart TB
+ User["User Application"]
+
+ subgraph Client["Nitrolite Client"]
+ API["Client API"]
+ NService["Nitrolite Service"]
+ ERC20Service["ERC20 Service"]
+ Wallet["State Wallet"]
+ end
+
+ subgraph Communication["Communication Layer"]
+ RPC["Nitrolite RPC"]
+ Messaging["Message Creation API"]
+ end
+
+ subgraph External["External Components"]
+ ClearNode["ClearNode"]
+ Blockchain["Blockchain"]
+ NitroContract["Nitro Contract"]
+ Token["Token Contract"]
+ end
+
+ User <--> API
+ API <--> NService
+ API <--> ERC20Service
+ NService <--> Wallet
+ ERC20Service <--> Wallet
+ Wallet <--> RPC
+ RPC <--> Messaging
+ Messaging <--> ClearNode
+ Messaging <--> Blockchain
+ ClearNode <--> Blockchain
+ Blockchain <--> NitroContract
+ Blockchain <--> Token
+
+ classDef clientNode fill:#d0e8ff,stroke:#3080cf
+ classDef commNode fill:#ffe8d0,stroke:#cf8030
+ classDef extNode fill:#d0ffe8,stroke:#30cf80
+
+ class API,NService,ERC20Service,Wallet clientNode
+ class RPC,Messaging commNode
+ class ClearNode,Blockchain,NitroContract,Token extNode
+```
+
+
- */}
\ No newline at end of file
+ */}
diff --git a/docs/nitrolite_client/methods.mdx b/docs/nitrolite_client/methods.mdx
index d533197..e2b28a7 100644
--- a/docs/nitrolite_client/methods.mdx
+++ b/docs/nitrolite_client/methods.mdx
@@ -22,7 +22,7 @@ The deposit phase includes methods for managing funds in the custody contract an
diff --git a/docs/nitrolite_client/types.md b/docs/nitrolite_client/types.md
index 3eb8533..e4d7a1a 100644
--- a/docs/nitrolite_client/types.md
+++ b/docs/nitrolite_client/types.md
@@ -9,6 +9,56 @@ keywords: [erc7824, statechannels, state channels, nitrolite, ethereum scaling,
This page documents the core types used throughout the `@erc7824/nitrolite` SDK. Understanding these types is essential for effectively working with the `NitroliteClient`.
+
+```mermaid
+classDiagram
+ class ChannelState {
+ +turnNum: number
+ +isFinal: boolean
+ +appDefinition: address
+ +appData: bytes
+ +outcome: Outcome
+ }
+
+ class Outcome {
+ +assetType: AssetType
+ +allocations: Allocation[]
+ }
+
+ class Allocation {
+ +destination: address
+ +amount: uint256
+ +metadata: bytes
+ }
+
+ class AssetType {
+ <>
+ ETH
+ ERC20
+ ERC721
+ }
+
+ class StateSignature {
+ +signer: address
+ +signature: bytes
+ }
+
+ class Channel {
+ +participants: address[]
+ +channelNonce: uint256
+ +chainId: uint256
+ +states: ChannelState[]
+ +signatures: StateSignature[]
+ }
+
+ Channel "1" *-- "many" ChannelState
+ Channel "1" *-- "many" StateSignature
+ ChannelState "1" *-- "1" Outcome
+ Outcome "1" *-- "many" Allocation
+ Outcome "1" *-- "1" AssetType
+```
+
+
## Core Types
### ChannelId
@@ -44,7 +94,7 @@ Represents a cryptographic signature used for signing state channel states.
```typescript
interface Allocation {
destination: Address; // Where funds are sent on channel closure
- token: Address; // ERC-20 token address (zero address for ETH)
+ token: Address; // [ERC-20](https://eips.ethereum.org/EIPS/eip-20) token address (zero address for ETH)
amount: bigint; // Token amount allocated
}
```
@@ -99,16 +149,16 @@ Represents a complete state channel state, including allocations and signatures.
interface NitroliteClientConfig {
// Required: viem PublicClient for reading blockchain data
publicClient: PublicClient;
-
+
// Required: viem WalletClient for sending transactions and account context
walletClient: WalletClient>;
-
+
// Optional: Separate wallet client for signing states
stateWalletClient?: WalletClient>;
-
+
// Required: Contract addresses
addresses: ContractAddresses;
-
+
// Required: Challenge duration in seconds
challengeDuration?: bigint;
}
@@ -230,10 +280,10 @@ const allowance: bigint = await client.getTokenAllowance()
```typescript
// Create channel
-const result: {
- channelId: ChannelId;
- initialState: State;
- txHash: Hash
+const result: {
+ channelId: ChannelId;
+ initialState: State;
+ txHash: Hash
} = await client.createChannel({
initialAllocationAmounts: [bigint, bigint],
stateData: Hex
@@ -343,4 +393,4 @@ const finalState = {
],
sigs: [userSig, guestSig]
};
-```
\ No newline at end of file
+```
diff --git a/docs/nitrolite_rpc/index.md b/docs/nitrolite_rpc/index.md
index 75d0d1f..f29607d 100644
--- a/docs/nitrolite_rpc/index.md
+++ b/docs/nitrolite_rpc/index.md
@@ -12,6 +12,40 @@ import MethodDetails from '@site/src/components/MethodDetails';
The NitroliteRPC provides a secure, reliable real-time communication protocol for state channel applications. It enables off-chain message exchange, state updates, and channel management. This system is built around the `NitroliteRPC` class, which provides the foundational methods for message construction, signing, parsing, and verification.
+
+```mermaid
+sequenceDiagram
+ participant A as Alice
+ participant C as ClearNode
+ participant B as Bob
+
+ Note over A,B: Channel Creation
+ A->>C: CreateChannel(channelId, participants, allocation)
+ C->>B: NotifyChannelCreation(channelId, participants, allocation)
+ B->>C: AcknowledgeChannel(channelId)
+ C->>A: ChannelReady(channelId)
+
+ Note over A,B: Application Session
+ A->>C: ProposeAppSession(channelId, appDefinition)
+ C->>B: ForwardAppSession(channelId, appDefinition)
+ B->>C: AcceptAppSession(channelId, appDefinition)
+ C->>A: AppSessionAccepted(channelId)
+
+ Note over A,B: State Updates
+ A->>C: UpdateState(channelId, state, signature)
+ C->>B: ForwardStateUpdate(channelId, state, signature)
+ B->>C: CountersignState(channelId, state, signature)
+ C->>A: StateFinalized(channelId, state, signatures)
+
+ Note over A,B: Channel Closure
+ A->>C: ProposeClose(channelId, finalState)
+ C->>B: ForwardCloseProposal(channelId, finalState)
+ B->>C: AgreeToClose(channelId, finalState, signature)
+ C->>A: CloseApproved(channelId, signatures)
+ A->>C: SubmitClosure(channelId, finalState, signatures)
+```
+
+
-
\ No newline at end of file
+
diff --git a/docs/nitrolite_rpc/message_creation_api.md b/docs/nitrolite_rpc/message_creation_api.md
index 052dd2f..05b9759 100644
--- a/docs/nitrolite_rpc/message_creation_api.md
+++ b/docs/nitrolite_rpc/message_creation_api.md
@@ -272,12 +272,6 @@ const resizeMsg = await createResizeChannelMessage(signer, resizeParams);
// Send resizeMsg via WebSocket
`}
/>
-// ...existing code...
-// Assuming 'signer' and 'resizeParams' are defined
-const resizeMsg = await createResizeChannelMessage(signer, resizeParams);
-// Send resizeMsg via WebSocket
-`}
-/>
## Advanced: Creating a Local Signer for Development
@@ -361,7 +355,7 @@ export const createEthersSigner = (privateKey: string): WalletSigner => {
const messageToSign = JSON.stringify(payload);
const messageHash = ethers.utils.id(messageToSign); // ethers.utils.id performs keccak256
const messageBytes = ethers.utils.arrayify(messageHash);
-
+
const flatSignature = await wallet._signingKey().signDigest(messageBytes);
const signature = ethers.utils.joinSignature(flatSignature);
return signature as Hex;
@@ -389,6 +383,6 @@ async function setupSigner() {
```
**Important Considerations for `createEthersSigner`:**
-* **Hashing Consistency:** The `sign` method within `createEthersSigner` must hash the payload in a way that is **identical** to how the `NitroliteRPC` class (specifically `NitroliteRPC.hashMessage`) expects messages to be hashed before signing. The example above uses `ethers.utils.id(JSON.stringify(payload))`. It's crucial to verify if the SDK's internal hashing uses a specific message prefix (e.g., EIP-191 personal_sign prefix) or a different serialization method. If the SDK does *not* use a standard EIP-191 prefix, or uses a custom one, your local signer's hashing logic must replicate this exactly for signatures to be valid. Using `NitroliteRPC.hashMessage(payload)` directly (if `payload` matches the `NitroliteRPCMessage` structure) is the safest way to ensure consistency.
+* **Hashing Consistency:** The `sign` method within `createEthersSigner` must hash the payload in a way that is **identical** to how the `NitroliteRPC` class (specifically `NitroliteRPC.hashMessage`) expects messages to be hashed before signing. The example above uses `ethers.utils.id(JSON.stringify(payload))`. It's crucial to verify if the SDK's internal hashing uses a specific message prefix (e.g., [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal_sign prefix) or a different serialization method. If the SDK does *not* use a standard [EIP-191](https://eips.ethereum.org/EIPS/eip-191) prefix, or uses a custom one, your local signer's hashing logic must replicate this exactly for signatures to be valid. Using `NitroliteRPC.hashMessage(payload)` directly (if `payload` matches the `NitroliteRPCMessage` structure) is the safest way to ensure consistency.
* **Type Compatibility:** Ensure the `Address` type expected by functions like `createAuthRequestMessage` is compatible with `localSigner.address`. The example uses `localSigner.address as Address` assuming `Address` is `0x${string}`.
* **Error Handling:** The provided examples include basic error logging. Robust applications should implement more sophisticated error handling.
diff --git a/docs/quick_start/connect_to_the_clearnode.md b/docs/quick_start/connect_to_the_clearnode.md
index efcc17b..95891cc 100644
--- a/docs/quick_start/connect_to_the_clearnode.md
+++ b/docs/quick_start/connect_to_the_clearnode.md
@@ -256,7 +256,7 @@ const messageSigner = async (payload) => {
const messageBytes = ethers.getBytes(digestHex);
// Sign the bytes with the wallet's signing key
- // Note: This uses the raw signing method, not the EIP-191 prefixed signing!
+ // Note: This uses the raw signing method, not the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) prefixed signing!
const { serialized: signature } = client.stateWalletClient.wallet.signingKey.sign(messageBytes);
return signature;
@@ -1632,7 +1632,7 @@ When working with ClearNodes and state channels, keep these security best practi
| Authentication failure | Invalid state wallet, incorrect signing | Verify your state wallet is properly initialized and signing correctly |
| Frequent disconnections | Unstable network, server-side issues | Monitor connection events and implement automatic reconnection |
| Message delivery failures | Connection issues, invalid message format | Add message queuing and confirmation mechanism |
-| Invalid signature errors | EIP-191 prefix issues | Ensure you're signing raw message bytes without the EIP-191 prefix |
+| Invalid signature errors | [EIP-191](https://eips.ethereum.org/EIPS/eip-191) prefix issues | Ensure you're signing raw message bytes without the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) prefix |
## Next Steps
@@ -1640,5 +1640,5 @@ After successfully connecting to a ClearNode, you can:
1. [View and manage channel assets](balances)
2. [Create an application session](application_session)
-3. [Start transacting off-chain](application_session#sending-transactions)
+3. [Start transacting off-chain](application_session)
4. [Explore advanced channel operations](resize_channel)
\ No newline at end of file
diff --git a/docs/quick_start/deposit_and_create_channel.md b/docs/quick_start/deposit_and_create_channel.md
index 15d5b0e..294b07e 100644
--- a/docs/quick_start/deposit_and_create_channel.md
+++ b/docs/quick_start/deposit_and_create_channel.md
@@ -12,6 +12,37 @@ import TabItem from '@theme/TabItem';
Creating a state channel involves depositing funds into a smart contract and establishing the channel parameters. This guide walks through the complete process of depositing USDC and creating a functional state channel.
+
+```mermaid
+flowchart TD
+ User["User Wallet"]
+ Chain["Blockchain"]
+ Contract["Nitro Contract"]
+ Channel["State Channel"]
+ Other["Other Participants"]
+
+ User -->|1\. Deposit| Chain
+ Chain -->|2\. Lock in Contract| Contract
+ Contract -->|3\. Channel Creation| Channel
+ Channel -->|4\. Off-chain Transfers| Channel
+ Channel -->|5\. Off-chain Exchange| Other
+ Channel -->|6\. Final State| Contract
+ Contract -->|7\. Release Funds| Chain
+ Chain -->|8\. Withdraw| User
+ Chain -->|9\. Withdraw| Other
+
+ classDef wallet fill:#ffcccc,stroke:#ff0000
+ classDef blockchain fill:#ccffcc,stroke:#00cc00
+ classDef contract fill:#ccccff,stroke:#0000ff
+ classDef channel fill:#ffffcc,stroke:#ffcc00
+
+ class User,Other wallet
+ class Chain blockchain
+ class Contract contract
+ class Channel channel
+```
+
+
## Understanding State Channels in Nitrolite
A state channel is a secure off-chain communication pathway between two participants:
@@ -65,7 +96,7 @@ const depositAmount = 100000000n; // 100 USDC (with 6 decimals)
try {
const depositTx = await client.deposit(depositAmount);
console.log('Deposit transaction submitted:', depositTx);
-
+
// The deposit function waits for transaction confirmation internally
console.log('USDC tokens successfully deposited to custody contract');
} catch (error) {
@@ -82,7 +113,7 @@ try {
// 1. Check current allowance
const currentAllowance = await client.getTokenAllowance();
console.log('Current USDC allowance:', currentAllowance);
-
+
// 2. Approve USDC if needed
if (currentAllowance < depositAmount) {
const approvalTx = await client.approveTokens(depositAmount);
@@ -90,7 +121,7 @@ try {
// Wait for approval to be confirmed
// (typically you would wait for the transaction to be mined)
}
-
+
// 3. Deposit USDC
const depositTx = await client.deposit(depositAmount);
console.log('Deposit transaction submitted:', depositTx);
@@ -119,7 +150,7 @@ const channelParams = {
try {
// Create the channel
const { channelId, initialState, txHash } = await client.createChannel(channelParams);
-
+
console.log('Channel created with ID:', channelId);
console.log('Initial state:', initialState);
console.log('Transaction hash:', txHash);
@@ -165,13 +196,13 @@ const channelParams = {
};
try {
- const {
- channelId,
- initialState,
- depositTxHash,
- createChannelTxHash
+ const {
+ channelId,
+ initialState,
+ depositTxHash,
+ createChannelTxHash
} = await client.depositAndCreateChannel(depositAmount, channelParams);
-
+
console.log('USDC deposited with transaction:', depositTxHash);
console.log('Channel created with ID:', channelId);
console.log('Channel creation transaction:', createChannelTxHash);
@@ -208,4 +239,4 @@ After creating your channel, you can:
2. [View channel assets](balances) to monitor your funds
3. [Create an application session](application_session) to start transacting
-For advanced channel operations, see the [Resize Channel](resize_channel) guide.
\ No newline at end of file
+For advanced channel operations, see the [Resize Channel](resize_channel) guide.
diff --git a/docs/quick_start/index.mdx b/docs/quick_start/index.mdx
index d7618b4..4001f90 100644
--- a/docs/quick_start/index.mdx
+++ b/docs/quick_start/index.mdx
@@ -19,7 +19,7 @@ Before you begin working with Nitrolite, ensure that you have:
- **Node.js**: Version 16 or later
- **Package Manager**: npm, yarn, or pnpm
- **Web3 Development Knowledge**: Basic understanding of Ethereum and smart contracts
-- **Development Environment**:
+- **Development Environment**:
- For frontend: React, Vue, or similar framework
- For backend: Node.js environment
- **Ethereum Wallet**: MetaMask or another web3 provider for testing
@@ -72,6 +72,34 @@ We have generated a [llms-full.txt](https://erc7824.org/llms-full.txt) file that
Channels follow a clear lifecycle that involves several key steps:
+
+```mermaid
+flowchart TB
+ subgraph OnChain["On-Chain Actions"]
+ A[Deposit Funds] --> B[Create Channel]
+ F[Challenge State] -.-> G[Respond to Challenge]
+ H[Close Channel] --> I[Withdraw Funds]
+ end
+
+ subgraph OffChain["Off-Chain Actions"]
+ C[Initialize Application Session] --> D[Update Channel State]
+ D -->|New state| D
+ D --> E[Propose Channel Closure]
+ end
+
+ B --> C
+ E --> H
+ E -.->|Dispute| F
+ G --> H
+
+ classDef onchain fill:#ffcccc,stroke:#ff0000
+ classDef offchain fill:#ccffcc,stroke:#00cc00
+
+ class A,B,F,G,H,I onchain
+ class C,D,E offchain
+```
+
+
1. **[Client Initialization](initializing_client)**: Set up the client with your desired configuration
2. **[Deposit and Channel Creation](deposit_and_create_channel)**: Fund your channel and establish it with participants
3. **[ClearNode Connection](connect_to_the_clearnode)**: Connect to a ClearNode for off-chain messaging
diff --git a/docs/quick_start/initializing_client.md b/docs/quick_start/initializing_client.md
index bb42c5d..d9db43c 100644
--- a/docs/quick_start/initializing_client.md
+++ b/docs/quick_start/initializing_client.md
@@ -29,11 +29,11 @@ Nitrolite uses separate wallet clients for on-chain and off-chain operations for
- **User Experience**: Allows state channel operations without requiring wallet confirmation for every message
- **Persistence**: The state wallet needs to be accessible across sessions without requiring frequent user approval
-## The EIP-191 Prefix Issue
+## The [EIP-191](https://eips.ethereum.org/EIPS/eip-191) Prefix Issue
A critical detail when implementing the state wallet is handling message signing correctly:
-- **Standard wallets** (like MetaMask) automatically add an EIP-191 prefix to messages (`"\x19Ethereum Signed Message:\n" + message.length + message`)
+- **Standard wallets** (like MetaMask) automatically add an [EIP-191](https://eips.ethereum.org/EIPS/eip-191) prefix to messages (`"\x19Ethereum Signed Message:\n" + message.length + message`)
- **State channel protocols** often require signing raw messages WITHOUT this prefix for consensus compatibility
- **Nitrolite requires** direct signing of raw message bytes for correct off-chain state validation
@@ -98,13 +98,13 @@ async function initializeNitrolite() {
const stateWalletAccount = privateKeyToAccount(stateWalletPrivateKey);
// Create a state wallet client with the signing capabilities Nitrolite needs
- // IMPORTANT: We need to sign raw messages WITHOUT the EIP-191 prefix
+ // IMPORTANT: We need to sign raw messages WITHOUT the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) prefix
const stateWalletClient = {
account: {
address: stateWalletAccount.address,
},
signMessage: async ({ message: { raw } }) => {
- // Using ethers.js to sign the raw message without EIP-191 prefix
+ // Using ethers.js to sign the raw message without [EIP-191](https://eips.ethereum.org/EIPS/eip-191) prefix
const wallet = new ethers.Wallet(stateWalletPrivateKey);
const { serialized: signature } = wallet.signingKey.sign(raw);
return signature;
diff --git a/package-lock.json b/package-lock.json
index 569fb82..cca5258 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15770,6 +15770,13 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/search-insights": {
+ "version": "2.17.3",
+ "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz",
+ "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
@@ -16752,6 +16759,20 @@
"is-typedarray": "^1.0.0"
}
},
+ "node_modules/typescript": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
"node_modules/ufo": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",