Skip to content
This repository was archived by the owner on Jul 31, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 224 additions & 0 deletions docs/deep_dive/architecture.md
Original file line number Diff line number Diff line change
@@ -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.
Loading