From a4960634bb428ceeeff591337f4cb15b79894ead Mon Sep 17 00:00:00 2001 From: Maharshi Mishra Date: Thu, 27 Nov 2025 13:59:14 +0530 Subject: [PATCH 1/5] Learn restructuring: added intro and core concepts --- docs/learn/core-concepts/_category_.json | 7 + docs/learn/core-concepts/app-sessions.md | 177 +++++++++ .../learn/core-concepts/challenge-response.md | 148 ++++++++ docs/learn/core-concepts/message-envelope.md | 140 +++++++ docs/learn/core-concepts/session-keys.md | 222 +++++++++++ .../core-concepts/state-channels-vs-l1-l2.md | 136 +++++++ docs/learn/deprecated/_category_.json | 8 + .../learn/deprecated/advanced/_category_.json | 6 + .../{ => deprecated}/advanced/architecture.md | 0 .../{ => deprecated}/advanced/deployment.md | 0 docs/learn/{ => deprecated}/advanced/index.md | 0 .../{ => deprecated}/advanced/multi-party.md | 0 .../{ => deprecated}/advanced/security.md | 0 .../learn/deprecated/beginner/_category_.json | 6 + .../beginner/app-session-management.md | 0 .../deprecated/introduction/_category_.json | 6 + .../introduction/what-is-yellow-sdk.md | 0 .../introduction/yellow-apps.md | 0 docs/learn/getting-started/_category_.json | 7 + docs/learn/getting-started/key-terms.md | 337 +++++++++++++++++ docs/learn/getting-started/prerequisites.md | 345 ++++++++++++++++++ docs/learn/getting-started/quickstart.md | 341 +++++++++++++++++ docs/learn/index.md | 68 +++- docs/learn/introduction/_category_.json | 2 +- .../introduction/architecture-at-a-glance.md | 250 +++++++++++++ docs/learn/introduction/what-yellow-solves.md | 136 +++++++ sidebars.ts | 23 +- 27 files changed, 2357 insertions(+), 8 deletions(-) create mode 100644 docs/learn/core-concepts/_category_.json create mode 100644 docs/learn/core-concepts/app-sessions.md create mode 100644 docs/learn/core-concepts/challenge-response.md create mode 100644 docs/learn/core-concepts/message-envelope.md create mode 100644 docs/learn/core-concepts/session-keys.md create mode 100644 docs/learn/core-concepts/state-channels-vs-l1-l2.md create mode 100644 docs/learn/deprecated/_category_.json create mode 100644 docs/learn/deprecated/advanced/_category_.json rename docs/learn/{ => deprecated}/advanced/architecture.md (100%) rename docs/learn/{ => deprecated}/advanced/deployment.md (100%) rename docs/learn/{ => deprecated}/advanced/index.md (100%) rename docs/learn/{ => deprecated}/advanced/multi-party.md (100%) rename docs/learn/{ => deprecated}/advanced/security.md (100%) create mode 100644 docs/learn/deprecated/beginner/_category_.json rename docs/learn/{ => deprecated}/beginner/app-session-management.md (100%) create mode 100644 docs/learn/deprecated/introduction/_category_.json rename docs/learn/{ => deprecated}/introduction/what-is-yellow-sdk.md (100%) rename docs/learn/{ => deprecated}/introduction/yellow-apps.md (100%) create mode 100644 docs/learn/getting-started/_category_.json create mode 100644 docs/learn/getting-started/key-terms.md create mode 100644 docs/learn/getting-started/prerequisites.md create mode 100644 docs/learn/getting-started/quickstart.md create mode 100644 docs/learn/introduction/architecture-at-a-glance.md create mode 100644 docs/learn/introduction/what-yellow-solves.md diff --git a/docs/learn/core-concepts/_category_.json b/docs/learn/core-concepts/_category_.json new file mode 100644 index 0000000..53585cb --- /dev/null +++ b/docs/learn/core-concepts/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Core Concepts", + "position": 3, + "collapsible": false, + "collapsed": false +} + diff --git a/docs/learn/core-concepts/app-sessions.md b/docs/learn/core-concepts/app-sessions.md new file mode 100644 index 0000000..95eeae9 --- /dev/null +++ b/docs/learn/core-concepts/app-sessions.md @@ -0,0 +1,177 @@ +--- +sidebar_position: 2 +title: App Sessions +description: Multi-party application channels with custom governance and state management +keywords: [app sessions, multi-party, governance, quorum, NitroRPC] +--- + +# App Sessions + +App sessions are off-chain channels built on top of the unified balance that enable multi-party applications with custom governance rules. + +**Goal**: Understand how app sessions work for building multi-party applications. + +--- + +## What is an App Session? + +An **app session** is a temporary shared account where multiple participants can: + +- Lock funds from their unified balance +- Execute application-specific logic (games, escrow, predictions) +- Redistribute funds based on outcomes +- Close and release funds back to unified balances + +Think of it as a programmable escrow with custom voting rules. + +--- + +## App Session vs Payment Channel + +| Feature | Payment Channel | App Session | +|---------|-----------------|-------------| +| **Participants** | Always 2 | 2 or more | +| **Governance** | Both must sign | Quorum-based | +| **Fund source** | On-chain deposit | Unified balance | +| **Mid-session changes** | Via resize (on-chain) | Via intent (off-chain) | +| **Use case** | Transfers | Applications | + +--- + +## App Session Definition + +Every app session starts with a **definition** that specifies the rules: + +| Field | Description | +|-------|-------------| +| `protocol` | Version (`NitroRPC/0.4` recommended) | +| `participants` | Wallet addresses (order matters for signatures) | +| `weights` | Voting power per participant | +| `quorum` | Minimum weight required for state updates | +| `challenge` | Dispute window in seconds | +| `nonce` | Unique identifier (typically timestamp) | + +The `app_session_id` is computed deterministically from the definition using `keccak256(JSON.stringify(definition))`. + +--- + +## Governance with Quorum + +The quorum system enables flexible governance patterns. + +### How It Works + +1. Each participant has a **weight** (voting power) +2. State updates require signatures with total weight ≥ **quorum** +3. Not everyone needs to sign—just enough to meet quorum + +### Common Patterns + +| Pattern | Setup | Use Case | +|---------|-------|----------| +| **Unanimous** | `weights: [50, 50]`, `quorum: 100` | Both must agree | +| **Trusted Judge** | `weights: [0, 0, 100]`, `quorum: 100` | App determines outcome | +| **2-of-3 Escrow** | `weights: [40, 40, 50]`, `quorum: 80` | Any two can proceed | +| **Weighted DAO** | `weights: [20, 25, 30, 25]`, `quorum: 51` | Majority by stake | + +--- + +## Session Lifecycle + +```mermaid +stateDiagram-v2 + [*] --> Open: create_app_session + Open --> Open: submit_app_state + Open --> Closed: close_app_session + Closed --> [*] +``` + +### 1. Creation + +- Funds locked from participants' unified balances +- All participants with non-zero allocations must sign +- Status becomes `open`, version starts at `1` + +### 2. State Updates + +- Redistribute funds with `submit_app_state` +- Version must increment by exactly 1 +- Quorum of signatures required + +### 3. Closure + +- Final allocations distributed to unified balances +- Session becomes `closed` (cannot reopen) +- Quorum of signatures required + +--- + +## Intent System (NitroRPC/0.4) + +The intent system enables dynamic fund management during active sessions: + +| Intent | Purpose | Rule | +|--------|---------|------| +| **OPERATE** | Redistribute existing funds | Sum unchanged | +| **DEPOSIT** | Add funds from unified balance | Sum increases | +| **WITHDRAW** | Remove funds to unified balance | Sum decreases | + +:::info Allocations Are Final State +Allocations always represent the **final state**, not the delta. The Clearnode computes deltas internally. +::: + +--- + +## Fund Flow + +```mermaid +graph TB + subgraph Unified["Unified Balances"] + UA["Alice: 200 USDC"] + UB["Bob: 200 USDC"] + end + + subgraph Session["App Session"] + SA["Alice: 100 USDC"] + SB["Bob: 100 USDC"] + end + + UA -->|"create (lock)"| SA + UB -->|"create (lock)"| SB + + SA -->|"close (release)"| UA + SB -->|"close (release)"| UB + + style Unified fill:#e1f5ff,stroke:#333 + style Session fill:#ffe1f5,stroke:#333 +``` + +--- + +## Protocol Versions + +| Version | Status | Key Features | +|---------|--------|--------------| +| **NitroRPC/0.2** | Legacy | Basic state updates only | +| **NitroRPC/0.4** | Current | Intent system (OPERATE, DEPOSIT, WITHDRAW) | + +Always use `NitroRPC/0.4` for new applications. Protocol version is set at creation and cannot be changed. + +--- + +## Best Practices + +1. **Set appropriate challenge periods**: 1 hour minimum, 24 hours recommended +2. **Include commission participants**: Apps often have a judge that takes a small fee +3. **Plan for disputes**: Design allocations that can be verified by third parties +4. **Version carefully**: Each state update must be exactly `current + 1` + +--- + +## Deep Dive + +For complete API specifications and implementation details: + +- **[App Session Methods](/docs/protocol/off-chain/app-sessions)** — Full API reference +- **[Communication Flows](/docs/protocol/communication-flows#app-session-lifecycle-flow)** — Sequence diagrams +- **[Implementation Checklist](/docs/protocol/implementation-checklist#state-management)** — Building app session support diff --git a/docs/learn/core-concepts/challenge-response.md b/docs/learn/core-concepts/challenge-response.md new file mode 100644 index 0000000..2f806d8 --- /dev/null +++ b/docs/learn/core-concepts/challenge-response.md @@ -0,0 +1,148 @@ +--- +sidebar_position: 4 +title: Challenge-Response & Disputes +description: How Yellow Network handles disputes and ensures fund safety +keywords: [challenge, dispute, security, settlement, fund recovery] +--- + +# Challenge-Response & Disputes + +In this guide, you will learn how Yellow Network resolves disputes and ensures your funds are always recoverable. + +**Goal**: Understand the security guarantees that make off-chain transactions safe. + +--- + +## Why Challenge-Response Matters + +In any off-chain system, a critical question arises: **What if someone tries to cheat?** + +State channels solve this with a challenge-response mechanism: + +1. Anyone can submit a state to the blockchain +2. Counterparties have time to respond with a newer state +3. The newest valid state always wins +4. Funds are distributed according to that state + +--- + +## The Trust Model + +State channels are **trustless** because: + +| Guarantee | How It's Achieved | +|-----------|-------------------| +| **Fund custody** | Smart contract holds funds, not Clearnode | +| **State validity** | Only signed states are accepted | +| **Dispute resolution** | On-chain fallback if disagreement | +| **Recovery** | You can always get your funds back | + +--- + +## Channel Dispute Flow + +### Scenario: Clearnode Becomes Unresponsive + +You have a channel with 100 USDC. The Clearnode stops responding. + +**Your options:** + +1. Wait for Clearnode to recover +2. Force settlement on-chain via challenge + +### The Process + +1. **Initiate Challenge**: Submit your latest signed state to the blockchain +2. **Challenge Period**: Contract sets a timer (e.g., 24 hours) +3. **Response Window**: Counterparty can submit a newer state +4. **Resolution**: After timeout, challenged state becomes final + +```mermaid +stateDiagram-v2 + [*] --> ACTIVE + ACTIVE --> DISPUTE: challenge() + DISPUTE --> ACTIVE: checkpoint() with newer state + DISPUTE --> FINAL: Timeout expires + FINAL --> [*] + + note right of DISPUTE: Anyone can submit
newer valid state +``` + +--- + +## Why This Works + +### States Are Ordered + +Every state has a version number. A newer (higher version) state always supersedes older states. + +### States Are Signed + +Both parties must sign every state. If someone signed a state, they can't later claim they didn't agree. + +### Challenge Period Provides Fairness + +The waiting window ensures honest parties have time to respond. Network delays don't cause losses. + +### On-Chain Contract is Neutral + +The smart contract accepts any valid signed state, picks the highest version, and distributes funds exactly as specified. + +--- + +## Challenge Period Selection + +| Duration | Trade-offs | +|----------|------------| +| **1 hour** | Fast resolution, tight response window | +| **24 hours** | Balanced (recommended) | +| **7 days** | Maximum safety, slow settlement | + +The Custody Contract enforces a minimum of 1 hour. + +--- + +## Checkpoint vs Challenge + +| Operation | Purpose | Channel Status | +|-----------|---------|----------------| +| `checkpoint()` | Record state without dispute | Stays ACTIVE | +| `challenge()` | Force dispute resolution | Changes to DISPUTE | + +Use checkpoint for safety snapshots. Use challenge when you need to force settlement. + +--- + +## What Happens If... + +| Scenario | Outcome | +|----------|---------| +| **Clearnode goes offline** | Challenge with latest state, withdraw after timeout | +| **You lose state history** | Challenge with old state; counterparty submits newer if they have it | +| **Counterparty submits wrong state** | Submit your newer state via checkpoint | +| **Block reorg occurs** | Replay events from last confirmed block | + +--- + +## Key Takeaways + +| Concept | Remember | +|---------|----------| +| **Challenge** | Force on-chain dispute resolution | +| **Response** | Submit newer state to defeat challenge | +| **Timeout** | After period, challenged state becomes final | +| **Checkpoint** | Record state without dispute | + +:::success Security Guarantee +You can **always** recover your funds according to the latest mutually signed state, regardless of counterparty behavior. +::: + +--- + +## Deep Dive + +For technical implementation details: + +- **[Channel Lifecycle](/docs/protocol/on-chain/channel-lifecycle)** — Full state machine +- **[Security Considerations](/docs/protocol/on-chain/security)** — Threat model and best practices +- **[Communication Flows](/docs/protocol/communication-flows#challenge-response-closure-flow)** — Sequence diagrams diff --git a/docs/learn/core-concepts/message-envelope.md b/docs/learn/core-concepts/message-envelope.md new file mode 100644 index 0000000..5a1c5e2 --- /dev/null +++ b/docs/learn/core-concepts/message-envelope.md @@ -0,0 +1,140 @@ +--- +sidebar_position: 5 +title: Message Envelope (RPC Protocol) +description: Overview of the Nitro RPC message format and communication protocol +keywords: [Nitro RPC, message format, WebSocket, protocol, signatures] +--- + +# Message Envelope (RPC Protocol) + +In this guide, you will learn the essentials of how messages are structured and transmitted in Yellow Network. + +**Goal**: Understand the Nitro RPC protocol at a conceptual level. + +--- + +## Protocol Overview + +**Nitro RPC** is a lightweight RPC protocol optimized for state channel communication: + +| Feature | Benefit | +|---------|---------| +| **Compact format** | ~30% smaller than traditional JSON-RPC | +| **Signature-based auth** | Every message is cryptographically verified | +| **Bidirectional** | Real-time updates via WebSocket | +| **Ordered timestamps** | Replay attack prevention | + +--- + +## Message Structure + +Every Nitro RPC message uses a compact JSON array format: + +| Component | Type | Description | +|-----------|------|-------------| +| **requestId** | uint64 | Unique identifier for correlation | +| **method** | string | RPC method name (snake_case) | +| **params/result** | object | Method-specific data | +| **timestamp** | uint64 | Unix milliseconds | + +### Request Wrapper + +``` +{ "req": [requestId, method, params, timestamp], "sig": [...] } +``` + +### Response Wrapper + +``` +{ "res": [requestId, method, result, timestamp], "sig": [...] } +``` + +### Error Response + +``` +{ "res": [requestId, "error", { "error": "description" }, timestamp], "sig": [...] } +``` + +--- + +## Signature Format + +Each signature is a 65-byte ECDSA signature (r + s + v) represented as a 0x-prefixed hex string. + +| Context | What's Signed | Who Signs | +|---------|---------------|-----------| +| **Requests** | JSON payload hash | Session key (or main wallet) | +| **Responses** | JSON payload hash | Clearnode | + +--- + +## Method Categories + +| Category | Methods | +|----------|---------| +| **Auth** | `auth_request`, `auth_verify` | +| **Channels** | `create_channel`, `close_channel`, `resize_channel` | +| **Transfers** | `transfer` | +| **App Sessions** | `create_app_session`, `submit_app_state`, `close_app_session` | +| **Queries** | `get_ledger_balances`, `get_channels`, `get_app_sessions`, etc. | + +--- + +## Notifications + +The Clearnode pushes real-time updates: + +| Notification | When Sent | +|--------------|-----------| +| `bu` (balance update) | Balance changed | +| `cu` (channel update) | Channel status changed | +| `tr` (transfer) | Incoming/outgoing transfer | +| `asu` (app session update) | App session state changed | + +--- + +## Communication Flow + +```mermaid +sequenceDiagram + participant Client + participant Clearnode + + Client->>Clearnode: Request (signed) + Clearnode->>Clearnode: Verify signature + Clearnode->>Clearnode: Process + Clearnode->>Client: Response (signed) + Client->>Client: Verify signature + + Clearnode-->>Client: Notification (async) +``` + +--- + +## Protocol Versions + +| Version | Status | Key Features | +|---------|--------|--------------| +| **NitroRPC/0.2** | Legacy | Basic state updates | +| **NitroRPC/0.4** | Current | Intent system, enhanced validation | + +Always use NitroRPC/0.4 for new implementations. + +--- + +## Key Points + +1. **Compact arrays** instead of verbose JSON objects +2. **Every message signed** for authenticity +3. **Timestamps** prevent replay attacks +4. **Bidirectional** WebSocket for real-time updates + +--- + +## Deep Dive + +For complete technical specifications: + +- **[Message Format](/docs/protocol/off-chain/message-format)** — Full format specification +- **[Off-Chain Overview](/docs/protocol/off-chain/overview)** — Protocol architecture +- **[Implementation Checklist](/docs/protocol/implementation-checklist#off-chain-rpc)** — Building RPC support diff --git a/docs/learn/core-concepts/session-keys.md b/docs/learn/core-concepts/session-keys.md new file mode 100644 index 0000000..06844ba --- /dev/null +++ b/docs/learn/core-concepts/session-keys.md @@ -0,0 +1,222 @@ +--- +sidebar_position: 3 +title: Session Keys +description: Delegated keys for secure, gasless application interactions +keywords: [session keys, authentication, signatures, allowances, security] +--- + +# Session Keys + +Session keys are delegated keys that enable applications to perform operations on behalf of a user's wallet with specified spending limits, permissions, and expiration times. They provide a secure way to grant limited access to applications without exposing the main wallet's private key. + +**Goal**: Understand how session keys enable seamless UX while maintaining security. + +--- + +## Why Session Keys Matter + +Every blockchain operation traditionally requires a wallet signature popup. For high-frequency applications like games or trading, this creates terrible UX—imagine 40+ wallet prompts during a chess game. + +Session keys solve this by allowing you to **sign once**, then operate seamlessly for the duration of the session. + +--- + +## Core Concepts + +### How Session Keys Work + +1. You generate a session keypair **locally** on your device +2. Your main wallet **authorizes** the session key (one-time EIP-712 signature) +3. The session key signs **all subsequent operations** without wallet prompts +4. The session key has **limited permissions** (spending caps, expiration) + +> **Important:** Session keys are **no longer used as on-chain channel participant addresses** for new channels created after v0.5.0. For all new channels, the wallet address is used directly as the participant address. However, session keys still function correctly for channels created before v0.5.0, ensuring backward compatibility. + +--- + +### Applications + +Each session key is associated with a specific **application name**, which identifies the application or service that will use the session key. + +This association serves several purposes: + +- **Application Isolation**: Different applications get separate session keys, preventing one application from using another's delegated access +- **Access Control**: Operations performed with a session key are validated against the application specified during registration +- **Single Active Key**: Only one session key can be active per wallet+application combination. Registering a new session key for the same application automatically invalidates any existing session key for that application + +> **Important:** Only one session key is allowed per wallet+application combination. If you register a new session key for the same application, the old one is automatically invalidated and removed. + +#### Special Application: "clearnode" + +Session keys registered with the application name `"clearnode"` receive special treatment: + +- **Root Access**: These session keys bypass spending allowance validation and application restrictions +- **Full Permissions**: They can perform any operation the wallet itself could perform +- **Backward Compatibility**: This special behavior facilitates migration from older versions +- **Expiration Still Applies**: Even with root access, the session key expires according to its `expires_at` timestamp + +> **Note:** The "clearnode" application name is primarily for backward compatibility and will be deprecated after a migration period. + +--- + +### Expiration + +All session keys must have an **expiration timestamp** (`expires_at`) that defines when the session key becomes invalid: + +- **Future Timestamp Required**: The expiration time must be set to a future date when registering +- **Automatic Invalidation**: Once the expiration time passes, the session key can no longer be used +- **No Re-registration**: It is not possible to re-register an expired session key—you must create a new one +- **Applies to All Keys**: Even "clearnode" session keys must respect the expiration timestamp + +--- + +### Allowances + +Allowances define **spending limits** for session keys, specifying which assets the session key can spend and how much. + +| Field | Description | Example | +|-------|-------------|---------| +| `asset` | Asset symbol | `"usdc"`, `"eth"` | +| `amount` | Maximum spending limit | `"100.0"` | + +#### Allowance Validation + +- **Supported Assets Only**: All assets specified in allowances must be supported by the system. Unsupported assets cause authentication to fail +- **Usage Tracking**: The system tracks spending per session key by recording which session key was used for each ledger debit operation +- **Spending Limits**: Once a session key reaches its spending cap, further operations are rejected with: `"operation denied: insufficient session key allowance"` +- **Empty Allowances**: Providing an empty `allowances` array means zero spending allowed—any operation attempting to spend funds will be rejected + +#### Allowances for "clearnode" Application + +Session keys with `application: "clearnode"` are exempt from allowance enforcement—they can spend any amount of any supported asset. + +--- + +## Session Key Lifecycle + +```mermaid +stateDiagram-v2 + [*] --> Unauthenticated + Unauthenticated --> Authenticated: auth_verify success + Authenticated --> Authenticated: Using session key + Authenticated --> Expired: expires_at reached + Authenticated --> Exhausted: Allowance depleted + Authenticated --> Revoked: Manual revocation + Expired --> Unauthenticated: Re-authenticate + Exhausted --> Unauthenticated: Re-authenticate + Revoked --> Unauthenticated: Re-authenticate +``` + +--- + +## Managing Session Keys + +### Create and Configure + +To create a session key, use the `auth_request` method during authentication. This registers the session key with its configuration. + +**Parameters:** + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `address` | Yes | The wallet address that owns this session key | +| `session_key` | Yes | The address of the session key to register | +| `application` | No | Name of the application (defaults to "clearnode") | +| `allowances` | No | Array of asset allowances specifying spending limits | +| `scope` | No | Permission scope (not yet implemented) | +| `expires_at` | Yes | Unix timestamp (seconds) when this session key expires | + +> **Important:** When authenticating with an already registered session key, you must still provide all parameters in the `auth_request`. However, the configuration values from the request will be ignored—the system uses the settings from the initial registration. + +--- + +### List Active Session Keys + +Use `get_session_keys` to retrieve all active (non-expired) session keys for the authenticated user. + +The response includes: + +| Field | Description | +|-------|-------------| +| `id` | Unique identifier for the session key record | +| `session_key` | The address of the session key | +| `application` | Application name this session key is authorized for | +| `allowances` | Array with `asset`, `allowance`, and `used` amounts | +| `scope` | Permission scope (omitted if empty) | +| `expires_at` | When this session key expires (ISO 8601 format) | +| `created_at` | When the session key was created (ISO 8601 format) | + +--- + +### Revoke a Session Key + +To immediately invalidate a session key, use the `revoke_session_key` method. + +**Permission Rules:** + +- A wallet can revoke any of its session keys +- A session key can revoke itself +- A session key with `application: "clearnode"` can revoke other session keys belonging to the same wallet +- A non-"clearnode" session key cannot revoke other session keys (only itself) + +**Important Notes:** + +- Revocation is **immediate and cannot be undone** +- After revocation, any operations attempted with the revoked session key will fail +- The revoked session key will no longer appear in `get_session_keys` response +- Revocation is useful for security purposes when a session key may have been compromised + +--- + +## Security Model + +| Approach | Risk if Compromised | UX Impact | +|----------|---------------------|-----------| +| **Main wallet always** | Full wallet access | Constant prompts | +| **Session key (limited)** | Only allowance at risk | Seamless | +| **Session key (unlimited)** | Unified balance at risk | Seamless but risky | + +:::warning Session Key Compromise +If a session key is compromised, attackers can only spend up to the configured allowance before expiration. This is why setting appropriate limits is critical. +::: + +--- + +## Best Practices + +### For Users + +1. **Set reasonable allowances**: Don't authorize more than you'll use +2. **Use short expirations**: 24 hours is usually sufficient +3. **Different keys for different apps**: Isolate risk per application +4. **Monitor spending**: Use `get_session_keys` to check usage +5. **Revoke when done**: Clean up unused sessions + +### For Developers + +1. **Secure storage**: Encrypt session keys at rest +2. **Never transmit private keys**: Session key stays on device +3. **Handle expiration gracefully**: Prompt re-authentication before expiry +4. **Verify Clearnode signatures**: Always validate response signatures +5. **Clear on logout**: Delete session keys when user logs out + +--- + +## Alternative: Main Wallet as Root Signer + +You can skip session keys entirely and sign every request with your main wallet. Use this approach for: + +- Single operations +- High-value transactions +- Maximum security required +- Non-interactive applications + +--- + +## Deep Dive + +For complete API specifications and implementation details: + +- **[Authentication Flow](/docs/protocol/off-chain/authentication)** — Full 3-step authentication protocol +- **[Communication Flows](/docs/protocol/communication-flows#authentication-flow)** — Sequence diagrams for auth +- **[Implementation Checklist](/docs/protocol/implementation-checklist#authentication)** — Building session key support diff --git a/docs/learn/core-concepts/state-channels-vs-l1-l2.md b/docs/learn/core-concepts/state-channels-vs-l1-l2.md new file mode 100644 index 0000000..868f460 --- /dev/null +++ b/docs/learn/core-concepts/state-channels-vs-l1-l2.md @@ -0,0 +1,136 @@ +--- +sidebar_position: 1 +title: State Channels vs L1/L2 +description: Compare state channels with Layer 1 and Layer 2 scaling solutions +keywords: [state channels, L1, L2, scaling, comparison, rollups, Nitrolite] +--- + +# State Channels vs L1/L2 + +In this guide, you will learn how state channels compare to Layer 1 and Layer 2 solutions, and when each approach is the right choice. + +**Goal**: Understand where state channels fit in the blockchain scaling landscape. + +--- + +## Solution Comparison + +| Solution | Throughput | Latency | Cost per Op | Best For | +|----------|------------|---------|-------------|----------| +| **Layer 1** | 15-65K TPS | 1-15 sec | $0.001-$50 | Settlement, contracts | +| **Layer 2** | 2,000-4,000 TPS | 1-10 sec | $0.01-$0.50 | General dApps | +| **State Channels** | **Unlimited** | **< 1 sec** | **$0** | High-frequency, known parties | + +--- + +## How State Channels Work + +State channels operate on a simple principle: + +1. **Lock funds** in a smart contract (on-chain) +2. **Exchange signed states** directly between participants (off-chain) +3. **Settle** when done or if there's a dispute (on-chain) + +The key insight: most interactions between parties don't need immediate on-chain settlement. + +--- + +## State Channel Advantages + +### Instant Finality + +Unlike L2 solutions that still have block times, state channels provide sub-second finality: + +| Solution | Transaction Flow | +|----------|------------------| +| L1 | Transaction → Mempool → Block → Confirmation | +| L2 | Transaction → Sequencer → L2 Block → L1 Data | +| Channels | Signature → Validation → Done | + +### Zero Operational Cost + +| Operation | L1 Cost | L2 Cost | State Channel | +|-----------|---------|---------|---------------| +| 100 transfers | $500-5000 | $10-50 | **$0** | +| 1000 transfers | $5000-50000 | $100-500 | **$0** | + +### Privacy + +Off-chain transactions are only visible to participants. Only opening and final states appear on-chain. + +--- + +## State Channel Limitations + +### Known Participants + +Channels work between specific participants. Yellow Network solves this with the Clearnode hub-and-spoke model. + +### Liquidity Requirements + +Funds must be locked upfront. You can't spend more than what's locked in the channel. + +### Liveness Requirements + +Participants must respond to challenges within the challenge period. The Clearnode provides 24/7 monitoring. + +--- + +## When to Use Each + +| Choose | When | +|--------|------| +| **L1** | Deploying contracts, one-time large transfers, final settlement | +| **L2** | General dApps, many unknown users, complex smart contracts | +| **State Channels** | Known parties, real-time speed, high frequency, zero gas needed | + +--- + +## Decision Framework + +```mermaid +flowchart TD + A[Transaction] --> B{Known counterparty?} + B -->|No| C[Use L1/L2] + B -->|Yes| D{High frequency?} + D -->|Yes| E[Use State Channel] + D -->|No| F{Large value?} + F -->|Yes| C + F -->|No| E + + style E fill:#9999ff,stroke:#333,color:#111 + style C fill:#99ff99,stroke:#333,color:#111 +``` + +--- + +## How Yellow Network Addresses Limitations + +| Limitation | Solution | +|------------|----------| +| Known participants | Hub-and-spoke via Clearnode | +| Liquidity | Unified balance across chains | +| Liveness | Always-on Clearnode monitoring | + +--- + +## Key Takeaways + +State channels shine when you have identified participants who will interact frequently—like players in a game, counterparties in a trade, or parties in a payment relationship. + +:::success State Channel Sweet Spot +- Real-time interactions between known parties +- High transaction volumes +- Zero gas costs required +- Instant finality needed +::: + +--- + +## Deep Dive + +For technical details on channel implementation: + +- **[Architecture](/docs/protocol/architecture)** — System design and fund flows +- **[Channel Lifecycle](/docs/protocol/on-chain/channel-lifecycle)** — State machine and operations +- **[Data Structures](/docs/protocol/on-chain/data-structures)** — Channel and state formats diff --git a/docs/learn/deprecated/_category_.json b/docs/learn/deprecated/_category_.json new file mode 100644 index 0000000..a3b1c2a --- /dev/null +++ b/docs/learn/deprecated/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Deprecated", + "position": 99, + "collapsible": true, + "collapsed": true, + "className": "deprecated-category" +} + diff --git a/docs/learn/deprecated/advanced/_category_.json b/docs/learn/deprecated/advanced/_category_.json new file mode 100644 index 0000000..83cb82e --- /dev/null +++ b/docs/learn/deprecated/advanced/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Advanced", + "position": 3, + "collapsible": false, + "collapsed": false +} \ No newline at end of file diff --git a/docs/learn/advanced/architecture.md b/docs/learn/deprecated/advanced/architecture.md similarity index 100% rename from docs/learn/advanced/architecture.md rename to docs/learn/deprecated/advanced/architecture.md diff --git a/docs/learn/advanced/deployment.md b/docs/learn/deprecated/advanced/deployment.md similarity index 100% rename from docs/learn/advanced/deployment.md rename to docs/learn/deprecated/advanced/deployment.md diff --git a/docs/learn/advanced/index.md b/docs/learn/deprecated/advanced/index.md similarity index 100% rename from docs/learn/advanced/index.md rename to docs/learn/deprecated/advanced/index.md diff --git a/docs/learn/advanced/multi-party.md b/docs/learn/deprecated/advanced/multi-party.md similarity index 100% rename from docs/learn/advanced/multi-party.md rename to docs/learn/deprecated/advanced/multi-party.md diff --git a/docs/learn/advanced/security.md b/docs/learn/deprecated/advanced/security.md similarity index 100% rename from docs/learn/advanced/security.md rename to docs/learn/deprecated/advanced/security.md diff --git a/docs/learn/deprecated/beginner/_category_.json b/docs/learn/deprecated/beginner/_category_.json new file mode 100644 index 0000000..0d3ad4b --- /dev/null +++ b/docs/learn/deprecated/beginner/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Beginner", + "position": 2, + "collapsible": false, + "collapsed": false +} \ No newline at end of file diff --git a/docs/learn/beginner/app-session-management.md b/docs/learn/deprecated/beginner/app-session-management.md similarity index 100% rename from docs/learn/beginner/app-session-management.md rename to docs/learn/deprecated/beginner/app-session-management.md diff --git a/docs/learn/deprecated/introduction/_category_.json b/docs/learn/deprecated/introduction/_category_.json new file mode 100644 index 0000000..5ce4da8 --- /dev/null +++ b/docs/learn/deprecated/introduction/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Introduction", + "position": 1, + "collapsible": false, + "collapsed": false +} \ No newline at end of file diff --git a/docs/learn/introduction/what-is-yellow-sdk.md b/docs/learn/deprecated/introduction/what-is-yellow-sdk.md similarity index 100% rename from docs/learn/introduction/what-is-yellow-sdk.md rename to docs/learn/deprecated/introduction/what-is-yellow-sdk.md diff --git a/docs/learn/introduction/yellow-apps.md b/docs/learn/deprecated/introduction/yellow-apps.md similarity index 100% rename from docs/learn/introduction/yellow-apps.md rename to docs/learn/deprecated/introduction/yellow-apps.md diff --git a/docs/learn/getting-started/_category_.json b/docs/learn/getting-started/_category_.json new file mode 100644 index 0000000..9d63847 --- /dev/null +++ b/docs/learn/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Getting Started", + "position": 2, + "collapsible": false, + "collapsed": false +} + diff --git a/docs/learn/getting-started/key-terms.md b/docs/learn/getting-started/key-terms.md new file mode 100644 index 0000000..ab41369 --- /dev/null +++ b/docs/learn/getting-started/key-terms.md @@ -0,0 +1,337 @@ +--- +sidebar_position: 3 +title: Key Terms & Mental Models +description: Essential vocabulary and conceptual frameworks for understanding Yellow Network +keywords: [terminology, glossary, concepts, state channels, mental models] +--- + +# Key Terms & Mental Models + +In this guide, you will learn the essential vocabulary and mental models for understanding Yellow Network and state channel technology. + +**Goal**: Build a solid conceptual foundation before diving into implementation. + +--- + +## Core Mental Model: Off-Chain Execution + +The fundamental insight behind Yellow Network is simple: + +> **Most interactions don't need immediate on-chain settlement.** + +Think of it like a bar tab: + +| Traditional (L1) | State Channels | +|------------------|----------------| +| Pay for each drink separately | Open a tab, pay once at the end | +| Wait for bartender each time | Instant service, settle later | +| Transaction per item | One transaction for the whole session | + +State channels apply this pattern to blockchain: **lock funds once**, **transact off-chain**, **settle once**. + +--- + +## Essential Vocabulary + +### State Channel + +A **state channel** is a secure pathway for exchanging cryptographically signed states between participants without touching the blockchain. + +**Key properties:** +- Funds are locked in a smart contract +- Participants exchange signed state updates off-chain +- Only opening and closing require on-chain transactions +- Either party can force on-chain settlement if needed + +**Analogy**: Like a private Venmo between two parties, backed by a bank escrow. + +--- + +### Channel + +A **Channel** is the on-chain representation of a state channel. It defines: + +```typescript +{ + participants: ['0xAlice', '0xBob'], // Who can participate + adjudicator: '0xContract', // Rules for state validation + challenge: 86400, // Dispute window (seconds) + nonce: 1699123456789 // Unique identifier +} +``` + +The **channelId** is computed deterministically from these parameters: + +``` +channelId = keccak256(participants, adjudicator, challenge, nonce, chainId) +``` + +--- + +### State + +A **State** is a snapshot of the channel at a specific moment: + +```typescript +{ + intent: 'OPERATE', // Purpose: INITIALIZE, OPERATE, RESIZE, FINALIZE + version: 5, // Incremental counter (higher = newer) + data: '0x...', // Application-specific data + allocations: [...], // How funds are distributed + sigs: ['0xSig1', '0xSig2'] // Participant signatures +} +``` + +**Key rule**: A higher version number always supersedes a lower one, regardless of allocations. + +--- + +### Allocation + +An **Allocation** specifies how funds should be distributed: + +```typescript +{ + destination: '0xAlice', // Recipient address + token: '0xUSDC_CONTRACT', // Token contract + amount: 50000000n // Amount in smallest unit (6 decimals for USDC) +} +``` + +The sum of allocations represents the total funds in the channel. + +--- + +### Clearnode + +A **Clearnode** is the off-chain service that: + +1. **Manages the Nitro RPC protocol** for state channel operations +2. **Provides unified balance** aggregated across multiple chains +3. **Coordinates channels** between users +4. **Hosts app sessions** for multi-party applications + +**Think of it as**: A game server that acts as your entry point to Yellow Network—centralized for speed, but trustless because of on-chain guarantees. + +--- + +### Unified Balance + +Your **unified balance** is the aggregation of funds across all chains where you have deposits: + +``` +Polygon: 50 USDC ┐ +Base: 30 USDC ├─→ Unified Balance: 100 USDC +Arbitrum: 20 USDC ┘ +``` + +You can: +- Transfer from unified balance instantly (off-chain) +- Withdraw to any supported chain +- Lock funds into app sessions + +--- + +### App Session + +An **App Session** is an off-chain channel built on top of the unified balance for multi-party applications: + +```typescript +{ + protocol: 'NitroRPC/0.4', + participants: ['0xAlice', '0xBob', '0xJudge'], + weights: [40, 40, 50], // Voting power + quorum: 80, // Required weight for state updates + challenge: 3600, // Dispute window + nonce: 1699123456789 +} +``` + +**Use cases**: Games, prediction markets, escrow, any multi-party coordination. + +--- + +### Session Key + +A **session key** is a temporary cryptographic key that: + +- Is generated locally on your device +- Has limited permissions and spending caps +- Expires after a specified time +- Allows gasless signing without wallet prompts + +**Flow**: +1. Generate session keypair locally +2. Main wallet authorizes the session key (one-time EIP-712 signature) +3. All subsequent operations use the session key +4. Session expires or can be revoked + +--- + +## Protocol Components + +### Nitrolite + +**Nitrolite** is the on-chain smart contract protocol: + +- Defines channel data structures +- Implements create, close, challenge, resize operations +- Provides cryptographic verification +- Currently version 0.5.0 + +--- + +### Nitro RPC + +**Nitro RPC** is the off-chain communication protocol: + +- Compact JSON array format for efficiency +- Every message is cryptographically signed +- Bidirectional real-time communication +- Currently version 0.4 + +**Message format**: +```javascript +[requestId, method, params, timestamp] + +// Example +[42, "transfer", {"destination": "0x...", "amount": "50.0"}, 1699123456789] +``` + +--- + +### Custody Contract + +The **Custody Contract** is the main on-chain entry point: + +- Locks and unlocks participant funds +- Tracks channel status (VOID → ACTIVE → FINAL) +- Validates signatures and state transitions +- Handles dispute resolution + +--- + +### Adjudicator + +An **Adjudicator** defines rules for valid state transitions: + +| Type | Rule | +|------|------| +| **SimpleConsensus** | Both participants must sign (default) | +| **Remittance** | Only sender must sign | +| **Custom** | Application-specific logic | + +--- + +## State Lifecycle + +### Channel States + +```mermaid +stateDiagram-v2 + [*] --> VOID: Channel doesn't exist + VOID --> ACTIVE: create() + ACTIVE --> ACTIVE: Off-chain updates + ACTIVE --> DISPUTE: challenge() + ACTIVE --> FINAL: close() + DISPUTE --> ACTIVE: checkpoint() + DISPUTE --> FINAL: Timeout + FINAL --> [*]: Deleted +``` + +| Status | Meaning | +|--------|---------| +| **VOID** | Channel doesn't exist on-chain | +| **INITIAL** | Created, waiting for all participants (legacy) | +| **ACTIVE** | Fully operational, off-chain updates happening | +| **DISPUTE** | Challenge period active, parties can submit newer states | +| **FINAL** | Closed, funds distributed, metadata deleted | + +--- + +### State Intents + +| Intent | When Used | Purpose | +|--------|-----------|---------| +| **INITIALIZE** | `create()` | First state when opening channel | +| **OPERATE** | Off-chain updates | Normal operation, redistribution | +| **RESIZE** | `resize()` | Add or remove funds | +| **FINALIZE** | `close()` | Final state for cooperative closure | + +--- + +## Security Concepts + +### Challenge Period + +When a dispute arises: + +1. Party A submits their latest state via `challenge()` +2. **Challenge period** starts (typically 24 hours) +3. Party B can submit a newer valid state via `checkpoint()` +4. If no newer state, Party A's state becomes final after timeout + +**Purpose**: Gives honest parties time to respond to incorrect claims. + +--- + +### Signatures + +Two contexts for signatures: + +| Context | Hash Method | Signed By | +|---------|-------------|-----------| +| **On-chain** | Raw `packedState` (no prefix) | Main wallet | +| **Off-chain RPC** | JSON payload hash | Session key | + +**On-chain packedState**: +```javascript +keccak256(abi.encode(channelId, intent, version, data, allocations)) +``` + +--- + +### Quorum + +For app sessions, **quorum** defines the minimum voting weight required for state updates: + +``` +Participants: [Alice, Bob, Judge] +Weights: [40, 40, 50] +Quorum: 80 + +Valid combinations: +- Alice + Bob = 80 ✓ +- Alice + Judge = 90 ✓ +- Bob + Judge = 90 ✓ +- Alice alone = 40 ✗ +``` + +--- + +## Quick Reference Table + +| Term | One-Line Definition | +|------|---------------------| +| **State Channel** | Off-chain execution backed by on-chain funds | +| **Clearnode** | Off-chain service coordinating state channels | +| **Unified Balance** | Aggregated funds across all chains | +| **App Session** | Multi-party application channel | +| **Session Key** | Temporary key with limited permissions | +| **Challenge Period** | Dispute resolution window | +| **Quorum** | Minimum signature weight for approval | +| **Allocation** | Fund distribution specification | +| **packedState** | Canonical payload for signing | + +--- + +## Next Steps + +Now that you understand the vocabulary, continue to: + +- **[State Channels vs L1/L2](../core-concepts/state-channels-vs-l1-l2)** — Deep comparison with other scaling solutions +- **[App Sessions](../core-concepts/app-sessions)** — Multi-party application patterns +- **[Session Keys](../core-concepts/session-keys)** — Authentication and security + +For complete definitions, see the **[Glossary](/docs/protocol/glossary)**. + diff --git a/docs/learn/getting-started/prerequisites.md b/docs/learn/getting-started/prerequisites.md new file mode 100644 index 0000000..b5b2107 --- /dev/null +++ b/docs/learn/getting-started/prerequisites.md @@ -0,0 +1,345 @@ +--- +sidebar_position: 2 +title: Prerequisites & Environment +description: Set up your development environment for building Yellow Apps +keywords: [prerequisites, setup, development, environment, Node.js, viem] +--- + +# Prerequisites & Environment + +In this guide, you will set up a complete development environment for building applications on Yellow Network. + +**Goal**: Have a working local environment ready for Yellow App development. + +--- + +## System Requirements + +| Requirement | Minimum | Recommended | +|-------------|---------|-------------| +| **Node.js** | 18.x | 20.x or later | +| **npm/yarn/pnpm** | Latest stable | Latest stable | +| **Operating System** | macOS, Linux, Windows | macOS, Linux | + +--- + +## Required Knowledge + +Before building on Yellow Network, you should be comfortable with: + +| Topic | Why It Matters | +|-------|----------------| +| **JavaScript/TypeScript** | SDK and examples are in TypeScript | +| **Async/await patterns** | All network operations are asynchronous | +| **Basic Web3 concepts** | Wallets, transactions, signatures | +| **ERC-20 tokens** | Fund management involves token operations | + +:::tip New to Web3? +If you're new to blockchain development, start with the [Ethereum Developer Documentation](https://ethereum.org/developers) to understand wallets, transactions, and smart contract basics. +::: + +--- + +## Step 1: Install Node.js + +### macOS (using Homebrew) + +```bash +# Install Homebrew if you don't have it +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + +# Install Node.js +brew install node@20 + +# Verify installation +node --version # Should show v20.x.x +npm --version # Should show 10.x.x +``` + +### Linux (Ubuntu/Debian) + +```bash +# Install Node.js via NodeSource +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt-get install -y nodejs + +# Verify installation +node --version +npm --version +``` + +### Windows + +Download and run the installer from [nodejs.org](https://nodejs.org/). + +--- + +## Step 2: Install Core Dependencies + +Create a new project and install the required packages: + +```bash +# Create project directory +mkdir yellow-app && cd yellow-app + +# Initialize project +npm init -y + +# Install core dependencies +npm install @erc7824/nitrolite viem + +# Install development dependencies +npm install -D typescript @types/node tsx +``` + +### Package Overview + +| Package | Purpose | +|---------|---------| +| `@erc7824/nitrolite` | Yellow Network SDK for state channel operations | +| `viem` | Modern Ethereum library for wallet and contract interactions | +| `typescript` | Type safety and better developer experience | +| `tsx` | Run TypeScript files directly | + +--- + +## Step 3: Configure TypeScript + +Create `tsconfig.json`: + +```json +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} +``` + +Update `package.json`: + +```json +{ + "type": "module", + "scripts": { + "dev": "tsx watch src/index.ts", + "build": "tsc", + "start": "node dist/index.js" + } +} +``` + +--- + +## Step 4: Set Up Environment Variables + +Create `.env` for sensitive configuration: + +```bash +# .env - Never commit this file! + +# Your wallet private key (for development only) +PRIVATE_KEY=0x... + +# RPC endpoints +SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY +BASE_RPC_URL=https://base-sepolia.g.alchemy.com/v2/YOUR_KEY + +# Clearnode WebSocket endpoint +CLEARNODE_WS_URL=wss://clearnode.yellow.com/ws + +# Contract addresses (get from Yellow Network docs) +CUSTODY_ADDRESS=0x... +ADJUDICATOR_ADDRESS=0x... +``` + +Add to `.gitignore`: + +```bash +# .gitignore +.env +.env.local +node_modules/ +dist/ +``` + +Install dotenv for loading environment variables: + +```bash +npm install dotenv +``` + +--- + +## Step 5: Wallet Setup + +### Development Wallet + +For development, create a dedicated wallet: + +```typescript +// scripts/create-wallet.ts +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; + +const privateKey = generatePrivateKey(); +const account = privateKeyToAccount(privateKey); + +console.log('New Development Wallet'); +console.log('----------------------'); +console.log('Address:', account.address); +console.log('Private Key:', privateKey); +console.log('\n⚠️ Save this private key securely and add to .env'); +``` + +Run it: + +```bash +npx tsx scripts/create-wallet.ts +``` + +### Get Test Tokens + +For testnet development, you need test tokens: + +| Network | Faucet | +|---------|--------| +| Sepolia | [sepoliafaucet.com](https://sepoliafaucet.com) | +| Base Sepolia | [base.org/faucet](https://www.coinbase.com/faucets/base-ethereum-goerli-faucet) | + +:::warning Development Only +Never use your main wallet or real funds for development. Always create a separate development wallet with test tokens. +::: + +--- + +## Step 6: Verify Setup + +Create `src/index.ts` to verify everything works: + +```typescript +import 'dotenv/config'; +import { createPublicClient, http } from 'viem'; +import { sepolia } from 'viem/chains'; +import { privateKeyToAccount } from 'viem/accounts'; + +async function main() { + // Verify environment variables + const privateKey = process.env.PRIVATE_KEY; + if (!privateKey) { + throw new Error('PRIVATE_KEY not set in .env'); + } + + // Create account from private key + const account = privateKeyToAccount(privateKey as `0x${string}`); + console.log('✓ Wallet loaded:', account.address); + + // Create public client + const client = createPublicClient({ + chain: sepolia, + transport: http(process.env.SEPOLIA_RPC_URL), + }); + + // Check connection + const blockNumber = await client.getBlockNumber(); + console.log('✓ Connected to Sepolia, block:', blockNumber); + + // Check balance + const balance = await client.getBalance({ address: account.address }); + console.log('✓ ETH balance:', balance.toString(), 'wei'); + + console.log('\n🎉 Environment setup complete!'); +} + +main().catch(console.error); +``` + +Run the verification: + +```bash +npm run dev +``` + +Expected output: + +``` +✓ Wallet loaded: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb +✓ Connected to Sepolia, block: 12345678 +✓ ETH balance: 100000000000000000 wei + +🎉 Environment setup complete! +``` + +--- + +## Project Structure + +Recommended folder structure for Yellow Apps: + +``` +yellow-app/ +├── src/ +│ ├── index.ts # Entry point +│ ├── config.ts # Configuration +│ ├── client.ts # Nitrolite client setup +│ ├── auth.ts # Authentication logic +│ └── channels/ +│ ├── create.ts # Channel creation +│ ├── transfer.ts # Transfer operations +│ └── close.ts # Channel closure +├── scripts/ +│ └── create-wallet.ts # Utility scripts +├── .env # Environment variables (git-ignored) +├── .gitignore +├── package.json +└── tsconfig.json +``` + +--- + +## Supported Networks + +Yellow Network currently supports these EVM-compatible chains: + +| Network | Chain ID | Status | +|---------|----------|--------| +| Ethereum Mainnet | 1 | Production | +| Polygon | 137 | Production | +| Arbitrum One | 42161 | Production | +| Optimism | 10 | Production | +| Base | 8453 | Production | +| Sepolia (testnet) | 11155111 | Testing | + +--- + +## Next Steps + +Your environment is ready! Continue to: + +- **[Key Terms & Mental Models](./key-terms)** — Understand the core concepts +- **[Quickstart](./quickstart)** — Build your first Yellow App +- **[State Channels vs L1/L2](../core-concepts/state-channels-vs-l1-l2)** — Deep dive into state channels + +--- + +## Common Issues + +### "Module not found" errors +Ensure you have `"type": "module"` in `package.json` and are using ESM imports. + +### "Cannot find module 'viem'" +Run `npm install` to ensure all dependencies are installed. + +### RPC rate limiting +Use a dedicated RPC provider (Infura, Alchemy) instead of public endpoints for production. + +### TypeScript errors with viem +Ensure your `tsconfig.json` has `"moduleResolution": "bundler"` or `"node16"`. + diff --git a/docs/learn/getting-started/quickstart.md b/docs/learn/getting-started/quickstart.md new file mode 100644 index 0000000..bc0cff8 --- /dev/null +++ b/docs/learn/getting-started/quickstart.md @@ -0,0 +1,341 @@ +--- +sidebar_position: 1 +title: "Quickstart: Your First Channel" +description: Create your first state channel and perform an off-chain transfer in minutes +keywords: [quickstart, tutorial, state channel, Nitrolite, getting started] +--- + +# Quickstart: Your First Channel + +In this guide, you will create a state channel, perform an off-chain transfer, and verify the transaction—all in under 10 minutes. + +**Goal**: Experience the full Yellow Network flow from authentication to transfer. + +--- + +## Prerequisites + +Before starting, ensure you have: + +- Node.js 18+ installed +- A Web3 wallet (MetaMask, Rabby, or similar) +- Test tokens on a supported testnet (Sepolia, Base Goerli, etc.) + +:::tip Quick Setup +If you don't have test tokens, you can use a testnet faucet. Most testnets provide free tokens for development. +::: + +--- + +## Step 1: Install the SDK + +Create a new project and install the Nitrolite SDK: + +```bash +# Create project directory +mkdir my-yellow-app && cd my-yellow-app + +# Initialize package.json +npm init -y + +# Install dependencies +npm install @erc7824/nitrolite viem +``` + +--- + +## Step 2: Initialize the Client + +Create a file `index.js` and set up the Nitrolite client: + +```javascript +import { NitroliteClient } from '@erc7824/nitrolite'; +import { createPublicClient, createWalletClient, http } from 'viem'; +import { sepolia } from 'viem/chains'; +import { privateKeyToAccount } from 'viem/accounts'; + +// Your wallet private key (use environment variables in production!) +const account = privateKeyToAccount('0xYOUR_PRIVATE_KEY'); + +// Create viem clients +const publicClient = createPublicClient({ + chain: sepolia, + transport: http(), +}); + +const walletClient = createWalletClient({ + chain: sepolia, + transport: http(), + account, +}); + +// Initialize Nitrolite client +const client = new NitroliteClient({ + publicClient, + walletClient, + // State signer function for off-chain operations + stateSigner: async (state) => { + const signature = await walletClient.signMessage({ + message: { raw: state }, + }); + return signature; + }, + // Contract addresses (get these from Yellow Network documentation) + addresses: { + custody: '0xCUSTODY_CONTRACT_ADDRESS', + adjudicator: '0xADJUDICATOR_CONTRACT_ADDRESS', + }, + chainId: sepolia.id, + challengeDuration: 3600n, // 1 hour challenge period +}); + +console.log('✓ Client initialized'); +``` + +--- + +## Step 3: Authenticate with Clearnode + +Establish a session with the Clearnode using the 3-step authentication flow: + +```javascript +// Connect to Clearnode WebSocket +const ws = new WebSocket('wss://clearnode.yellow.com/ws'); + +// Step 1: Generate session keypair locally +const sessionPrivateKey = generatePrivateKey(); // Your crypto library +const sessionAddress = privateKeyToAddress(sessionPrivateKey); + +// Step 2: Send auth_request (no signature required) +const authRequest = { + req: [ + 1, // requestId + 'auth_request', + { + address: account.address, // Your main wallet address + session_key: sessionAddress, // Session key you generated + allowances: [{ asset: 'usdc', amount: '100.0' }], // Spending limit + expires_at: Date.now() + 24 * 60 * 60 * 1000, // 24 hours + }, + Date.now(), + ], + sig: [], // No signature needed for auth_request +}; + +ws.send(JSON.stringify(authRequest)); + +// Step 3: Sign the challenge with your MAIN wallet (EIP-712) +ws.onmessage = async (event) => { + const response = JSON.parse(event.data); + + if (response.res[1] === 'auth_challenge') { + const challenge = response.res[2].challenge_message; + + // Create EIP-712 typed data signature with main wallet + const signature = await signTypedData(/* EIP-712 Policy structure */); + + // Send auth_verify + const verifyRequest = { + req: [2, 'auth_verify', { challenge }, Date.now()], + sig: [signature], + }; + ws.send(JSON.stringify(verifyRequest)); + } + + if (response.res[1] === 'auth_verify') { + console.log('✓ Authenticated successfully'); + console.log(' Session key:', response.res[2].session_key); + console.log(' JWT token received'); + } +}; +``` + +:::info Session Key Security +Your session key private key **never leaves your device**. The main wallet only signs once during authentication. All subsequent operations use the session key. +::: + +--- + +## Step 4: Create a Channel + +Request channel creation from the Clearnode: + +```javascript +// Request channel creation +const createChannelRequest = { + req: [ + 3, + 'create_channel', + { + chain_id: 11155111, // Sepolia + token: '0xUSDA_TOKEN_ADDRESS', // USDC on Sepolia + }, + Date.now(), + ], + sig: [sessionKeySignature], // Sign with session key +}; + +ws.send(JSON.stringify(createChannelRequest)); + +// Handle response +ws.onmessage = async (event) => { + const response = JSON.parse(event.data); + + if (response.res[1] === 'create_channel') { + const { channel_id, channel, state, server_signature } = response.res[2]; + + console.log('✓ Channel prepared:', channel_id); + + // Sign the state with your participant key + const userSignature = await signPackedState(channel_id, state); + + // Submit to blockchain + const txHash = await client.createChannel({ + channel, + state, + signatures: [userSignature, server_signature], + }); + + console.log('✓ Channel created on-chain:', txHash); + } +}; +``` + +--- + +## Step 5: Fund Your Channel + +Resize the channel to add funds: + +```javascript +// Request channel resize (add funds) +const resizeRequest = { + req: [ + 4, + 'resize_channel', + { + channel_id: '0xYOUR_CHANNEL_ID', + allocations: [ + { participant: account.address, asset: 'usdc', amount: '50.0' }, + { participant: clearnodeAddress, asset: 'usdc', amount: '0.0' }, + ], + }, + Date.now(), + ], + sig: [sessionKeySignature], +}; + +ws.send(JSON.stringify(resizeRequest)); + +// Complete the on-chain resize after receiving server signature +// ... (similar pattern to channel creation) + +console.log('✓ Channel funded with 50 USDC'); +``` + +--- + +## Step 6: Make an Off-Chain Transfer + +Transfer funds instantly without any blockchain transaction: + +```javascript +// Transfer 10 USDC to another user +const transferRequest = { + req: [ + 5, + 'transfer', + { + destination: '0xRECIPIENT_ADDRESS', + allocations: [{ asset: 'usdc', amount: '10.0' }], + }, + Date.now(), + ], + sig: [sessionKeySignature], +}; + +ws.send(JSON.stringify(transferRequest)); + +// Handle confirmation +ws.onmessage = (event) => { + const response = JSON.parse(event.data); + + if (response.res[1] === 'transfer') { + console.log('✓ Transfer complete!'); + console.log(' Amount: 10 USDC'); + console.log(' Time: < 1 second'); + console.log(' Gas cost: $0.00'); + } +}; +``` + +--- + +## Step 7: Verify Your Balance + +Query your updated unified balance: + +```javascript +const balanceRequest = { + req: [ + 6, + 'get_ledger_balances', + {}, + Date.now(), + ], + sig: [sessionKeySignature], +}; + +ws.send(JSON.stringify(balanceRequest)); + +// Response shows updated balance +// Original: 50 USDC +// After transfer: 40 USDC +``` + +--- + +## What You Accomplished + +You just completed the core Yellow Network workflow: + +| Step | What Happened | Gas Cost | +|------|---------------|----------| +| Authentication | Established secure session with Clearnode | None | +| Create Channel | Locked funds in on-chain contract | ~$2-5 | +| Fund Channel | Added USDC to your unified balance | ~$2-5 | +| Transfer | Sent 10 USDC instantly | **$0** | +| Query Balance | Verified updated balance | None | + +The transfer completed in under 1 second with zero gas fees. + +--- + +## Next Steps + +Now that you've completed the basics: + +- **[Prerequisites & Environment](./prerequisites)** — Set up a complete development environment +- **[Key Terms & Mental Models](./key-terms)** — Understand core concepts in depth +- **[State Channels vs L1/L2](../core-concepts/state-channels-vs-l1-l2)** — Learn why state channels are different + +For production applications, see the **[Build](/docs/build/quick-start)** section for complete implementation guides. + +--- + +## Troubleshooting + +### "Insufficient balance" error +Ensure you have deposited funds into the Custody Contract before creating a channel. + +### "Signature verification failed" +Check that you're signing with the correct key: +- `auth_verify`: Main wallet (EIP-712) +- All other requests: Session key + +### "Challenge period" errors +The minimum challenge period is 1 hour. Ensure your `challengeDuration` is at least 3600 seconds. + +### Connection issues +Verify WebSocket URL and that you're connected to the correct network (testnet vs mainnet). + diff --git a/docs/learn/index.md b/docs/learn/index.md index 044a3bc..c75b191 100644 --- a/docs/learn/index.md +++ b/docs/learn/index.md @@ -1,12 +1,74 @@ --- title: Learn -description: Comprehensive learning resources for Yellow Network and state channels +description: Master Yellow Network and state channel technology sidebar_position: 1 displayed_sidebar: learnSidebar --- # Learn -**[Introduction](/docs/learn/introduction/what-is-yellow-sdk)** - Understand the fundamentals of Yellow Network, Chain Abstraction and Yellow Apps. Explore NitroliteRPC Protocol. +Welcome to the Yellow Network learning path. This section builds your understanding from fundamentals to advanced concepts. -**[Beginner](/docs/learn/beginner/app-session-management)** - Follow the core workflows for building your first Yellow App. Learn how to set up a Yellow Account and perform basic operations. \ No newline at end of file +--- + +## Introduction + +Start here to understand what Yellow Network solves and how it works. + +**[What Yellow Solves](./introduction/what-yellow-solves)** — Understand the core problems: scaling, cost, and speed. Learn why state channels are the answer for high-frequency applications. + +**[Architecture at a Glance](./introduction/architecture-at-a-glance)** — See how the three protocol layers (on-chain, off-chain, application) work together to enable fast, secure transactions. + +--- + +## Getting Started + +Get hands-on with Yellow Network in minutes. + +**[Quickstart: Your First Channel](./getting-started/quickstart)** — Create a state channel, perform an off-chain transfer, and verify the transaction in under 10 minutes. + +**[Prerequisites & Environment](./getting-started/prerequisites)** — Set up a complete development environment with Node.js, TypeScript, and the Nitrolite SDK. + +**[Key Terms & Mental Models](./getting-started/key-terms)** — Build your vocabulary and conceptual framework for understanding state channels. + +--- + +## Core Concepts + +Deep dive into the technology powering Yellow Network. + +**[State Channels vs L1/L2](./core-concepts/state-channels-vs-l1-l2)** — Compare state channels with Layer 1 and Layer 2 solutions. Understand when each approach is the right choice. + +**[App Sessions](./core-concepts/app-sessions)** — Multi-party application channels with custom governance and state management. + +**[Session Keys](./core-concepts/session-keys)** — Delegated keys for secure, gasless interactions without repeated wallet prompts. + +**[Challenge-Response & Disputes](./core-concepts/challenge-response)** — How Yellow Network handles disputes and ensures your funds are always recoverable. + +**[Message Envelope](./core-concepts/message-envelope)** — Overview of the Nitro RPC message format and communication protocol. + +--- + +## Next Steps + +After completing the Learn section, continue to: + +- **[Build](/docs/build/quick-start)** — Implement complete Yellow Applications +- **[Protocol Reference](/docs/protocol/introduction)** — Authoritative protocol specification +- **[API Reference](/docs/api-reference)** — SDK and RPC method documentation + +--- + +## Quick Reference + +| Topic | Time | Difficulty | +|-------|------|------------| +| [What Yellow Solves](./introduction/what-yellow-solves) | 5 min | Beginner | +| [Architecture at a Glance](./introduction/architecture-at-a-glance) | 8 min | Beginner | +| [Quickstart](./getting-started/quickstart) | 10 min | Beginner | +| [Key Terms](./getting-started/key-terms) | 10 min | Beginner | +| [State Channels vs L1/L2](./core-concepts/state-channels-vs-l1-l2) | 12 min | Intermediate | +| [App Sessions](./core-concepts/app-sessions) | 8 min | Intermediate | +| [Session Keys](./core-concepts/session-keys) | 8 min | Intermediate | +| [Challenge-Response](./core-concepts/challenge-response) | 6 min | Intermediate | +| [Message Envelope](./core-concepts/message-envelope) | 5 min | Intermediate | diff --git a/docs/learn/introduction/_category_.json b/docs/learn/introduction/_category_.json index 5ce4da8..558995f 100644 --- a/docs/learn/introduction/_category_.json +++ b/docs/learn/introduction/_category_.json @@ -3,4 +3,4 @@ "position": 1, "collapsible": false, "collapsed": false -} \ No newline at end of file +} diff --git a/docs/learn/introduction/architecture-at-a-glance.md b/docs/learn/introduction/architecture-at-a-glance.md new file mode 100644 index 0000000..3ed2417 --- /dev/null +++ b/docs/learn/introduction/architecture-at-a-glance.md @@ -0,0 +1,250 @@ +--- +sidebar_position: 2 +title: Architecture at a Glance +description: High-level overview of Yellow Network's three-layer architecture +keywords: [architecture, state channels, Nitrolite, Clearnode, smart contracts] +--- + +# Architecture at a Glance + +In this guide, you will learn how Yellow Network's three protocol layers work together to enable fast, secure, off-chain transactions. + +--- + +## The Three Layers + +Yellow Network consists of three interconnected layers, each with a specific responsibility: + +```mermaid +graph TB + subgraph Application["Application Layer"] + direction TB + APP["Your Application
Games, Payments, DeFi"] + end + + subgraph OffChain["Off-Chain Layer"] + direction LR + CLIENT["Client SDK"] + BROKER["Clearnode"] + end + + subgraph OnChain["On-Chain Layer"] + direction TB + CONTRACTS["Custody & Adjudicator Contracts"] + end + + subgraph Blockchain["Blockchain Layer"] + direction TB + CHAIN["Ethereum, Polygon, Base, etc."] + end + + APP --> CLIENT + CLIENT <-->|"Nitro RPC Protocol"| BROKER + CLIENT -.->|"On-chain operations"| CONTRACTS + BROKER -.->|"Monitors events"| CONTRACTS + CONTRACTS --> CHAIN + + style Application fill:#e1f5ff,stroke:#9ad7ff,color:#111 + style OffChain fill:#fff4e1,stroke:#ffd497,color:#111 + style OnChain fill:#ffe1f5,stroke:#ffbde6,color:#111 + style Blockchain fill:#f0f0f0,stroke:#c9c9c9,color:#111 +``` + +| Layer | Purpose | Speed | Cost | +|-------|---------|-------|------| +| **Application** | Your business logic and user interface | — | — | +| **Off-Chain** | Instant state updates via Nitro RPC | < 1 second | Zero gas | +| **On-Chain** | Fund custody, disputes, final settlement | Block time | Gas fees | + +--- + +## On-Chain Layer: Security Foundation + +The on-chain layer provides cryptographic guarantees through smart contracts: + +### Custody Contract + +The **Custody Contract** is the core of Nitrolite's on-chain implementation. It handles: + +- **Channel Creation**: Lock funds and establish participant relationships +- **Dispute Resolution**: Process challenges and validate states +- **Final Settlement**: Distribute funds according to signed final state +- **Fund Management**: Deposit and withdrawal operations + +### Adjudicator Contracts + +**Adjudicators** validate state transitions according to application-specific rules: + +- **SimpleConsensus**: Both participants must sign (default for payment channels) +- **Custom Adjudicators**: Application-specific validation logic + +:::info On-Chain Operations +You only touch the blockchain for: + +1. Opening a channel (lock funds) +2. Resizing a channel (add or remove funds) +3. Closing a channel (unlock and distribute funds) +4. Disputing a state (if counterparty is uncooperative) + +::: + +--- + +## Off-Chain Layer: Speed and Efficiency + +The off-chain layer handles high-frequency operations without blockchain transactions. + +### Clearnode + +A **Clearnode** is the off-chain service that: + +- Manages the Nitro RPC protocol for state channel operations +- Provides a unified balance across multiple chains +- Coordinates payment channels between users +- Hosts app sessions for multi-party applications + +### Nitro RPC Protocol + +**Nitro RPC** is a lightweight protocol optimized for state channel communication: + +- **Compact format**: JSON array structure reduces message size by ~30% +- **Signed messages**: Every request and response is cryptographically signed +- **Real-time updates**: Bidirectional communication via WebSocket + +```javascript +// Compact Nitro RPC format +[requestId, method, params, timestamp] + +// Example: Transfer 50 USDC +[42, "transfer", {"destination": "0x...", "amount": "50.0", "asset": "usdc"}, 1699123456789] +``` + +--- + +## How Funds Flow + +This diagram shows how your tokens move through the system: + +```mermaid +graph TB + A["User Wallet
(ERC-20)"] -->|"1. deposit"| B["Available Balance
(Custody Contract)"] + B -->|"2. resize"| C["Channel-Locked
(Custody Contract)"] + C <-->|"3. resize"| D["Unified Balance
(Clearnode)"] + D -->|"4. open session"| E["App Sessions
(Applications)"] + E -->|"5. close session"| D + D -->|"6. resize/close"| B + B -->|"7. withdraw"| A + + style A fill:#90EE90,stroke:#333,color:#111 + style B fill:#87CEEB,stroke:#333,color:#111 + style C fill:#FFD700,stroke:#333,color:#111 + style D fill:#DDA0DD,stroke:#333,color:#111 + style E fill:#FFA07A,stroke:#333,color:#111 +``` + +### Fund States + +| State | Location | What It Means | +|-------|----------|---------------| +| **User Wallet** | Your EOA | Full control, on-chain | +| **Available Balance** | Custody Contract | Deposited, ready for channels | +| **Channel-Locked** | Custody Contract | Committed to a specific channel | +| **Unified Balance** | Clearnode | Available for off-chain operations | +| **App Session** | Application | Locked in a specific app session | + +--- + +## Channel Lifecycle + +A payment channel progresses through distinct states: + +```mermaid +stateDiagram-v2 + [*] --> VOID + VOID --> ACTIVE: create() with both signatures + ACTIVE --> ACTIVE: Off-chain updates (zero gas) + ACTIVE --> ACTIVE: resize() (add/remove funds) + ACTIVE --> FINAL: close() (cooperative) + ACTIVE --> DISPUTE: challenge() (if disagreement) + DISPUTE --> ACTIVE: checkpoint() (newer state) + DISPUTE --> FINAL: Timeout expires + FINAL --> [*] + + note right of ACTIVE: This is where
99% of activity happens +``` + +### Typical Flow + +1. **Create**: Both parties sign initial state → channel becomes ACTIVE +2. **Operate**: Exchange signed states off-chain (unlimited, zero gas) +3. **Close**: Both sign final state → funds distributed + +### Dispute Path (Rare) + +If your counterparty becomes unresponsive: + +1. **Challenge**: Submit your latest signed state on-chain +2. **Wait**: Challenge period (typically 24 hours) allows counterparty to respond +3. **Finalize**: If no newer state is submitted, your state becomes final + +--- + +## Communication Patterns + +### Opening a Channel + +```mermaid +sequenceDiagram + participant Client + participant Clearnode + participant Blockchain + + Client->>Clearnode: create_channel request + Clearnode->>Client: channel config + Clearnode signature + Client->>Client: Sign state + Client->>Blockchain: create() with BOTH signatures + Blockchain->>Blockchain: Verify, lock funds, emit event + Blockchain-->>Clearnode: Event detected + Clearnode->>Client: Channel now ACTIVE +``` + +### Off-Chain Transfer + +```mermaid +sequenceDiagram + participant Sender + participant Clearnode + participant Receiver + + Sender->>Clearnode: transfer(destination, amount) + Clearnode->>Clearnode: Validate, update ledger + Clearnode->>Sender: Confirmed ✓ + Clearnode->>Receiver: balance_update notification + + Note over Sender,Receiver: Complete in < 1 second, zero gas +``` + +--- + +## Key Takeaways + +| Concept | What to Remember | +|---------|------------------| +| **On-Chain** | Only for opening, closing, disputes—security layer | +| **Off-Chain** | Where all the action happens—speed layer | +| **Clearnode** | Your gateway to the network—coordination layer | +| **State Channels** | Lock once, transact unlimited times, settle once | + +:::success Security Guarantee +At every stage, funds remain cryptographically secured. You can always recover your funds according to the latest valid signed state, even if a Clearnode becomes unresponsive. +::: + +--- + +## Next Steps + +Ready to start building? Continue to: + +- **[Quickstart](../getting-started/quickstart)** — Create your first channel in minutes +- **[Prerequisites](../getting-started/prerequisites)** — Set up your development environment +- **[Core Concepts](../core-concepts/state-channels-vs-l1-l2)** — Deep dive into state channels diff --git a/docs/learn/introduction/what-yellow-solves.md b/docs/learn/introduction/what-yellow-solves.md new file mode 100644 index 0000000..1211146 --- /dev/null +++ b/docs/learn/introduction/what-yellow-solves.md @@ -0,0 +1,136 @@ +--- +sidebar_position: 1 +title: What Yellow Solves +description: Understand the core problems Yellow Network addresses - scaling, cost, and speed +keywords: [Yellow Network, state channels, blockchain scaling, off-chain, Web3] +--- + +# What Yellow Solves + +In this guide, you will learn why Yellow Network exists, what problems it addresses, and how it provides a faster, cheaper way to build Web3 applications. + +--- + +## The Blockchain Scalability Problem + +Every blockchain transaction requires global consensus. While this guarantees security and decentralization, it creates three fundamental limitations: + +| Challenge | Impact on Users | +|-----------|-----------------| +| **High Latency** | Transactions take 15 seconds to several minutes for confirmation | +| **High Costs** | Gas fees spike during network congestion, making microtransactions impractical | +| **Limited Throughput** | Networks like Ethereum process ~15-30 transactions per second | + +For applications requiring real-time interactions—gaming, trading, micropayments—these constraints make traditional blockchain unusable as a backend. + +--- + +## How Yellow Network Solves This + +Yellow Network uses **state channels** to move high-frequency operations off-chain while preserving blockchain-level security guarantees. + +### The Core Insight + +Most interactions between parties don't need immediate on-chain settlement. Consider a chess game with a 10 USDC wager: + +- **On-chain approach**: Every move requires a transaction → 40+ transactions → $100s in fees +- **State channel approach**: Lock funds once, play off-chain, settle once → 2 transactions → minimal fees + +State channels let you execute unlimited off-chain operations between on-chain checkpoints. + +### What You Get + +| Feature | Benefit | +|---------|---------| +| **Instant Transactions** | Sub-second finality (< 1 second typical) | +| **Zero Gas Costs** | Off-chain operations incur no blockchain fees | +| **Unlimited Throughput** | 100,000+ operations per second | +| **Blockchain Security** | Funds are always recoverable via on-chain contracts | + +--- + +## The Nitrolite Protocol + +Yellow Network is built on **Nitrolite**, a state channel protocol designed for EVM-compatible chains. Nitrolite provides: + +- **Fund Custody**: Smart contracts that securely lock and release assets +- **Dispute Resolution**: Challenge-response mechanism ensuring fair outcomes +- **Final Settlement**: Cryptographic guarantees that final allocations are honored + +:::tip When to Use Yellow Network +Choose Yellow Network when your application needs: + +- Real-time interactions between users +- Microtransactions or streaming payments +- High transaction volumes without gas costs +- Multi-party coordination with instant settlement + +::: + +--- + +## Chain Abstraction with Clearnode + +A **Clearnode** serves as your entry point to Yellow Network. When you connect to a Clearnode: + +1. **Deposit** tokens on any supported chain +2. **Receive** a unified balance aggregated across all chains +3. **Transact** instantly with any other user on the network +4. **Withdraw** to any supported chain + +For example, deposit 50 USDC on Polygon and 50 USDC on Base—your unified balance shows 100 USDC. You can then withdraw all 100 USDC to Arbitrum if you choose. + +```mermaid +graph LR + A["Deposit on Polygon
50 USDC"] --> C["Unified Balance
100 USDC"] + B["Deposit on Base
50 USDC"] --> C + C --> D["Withdraw to Arbitrum
100 USDC"] + + style C fill:#90EE90,stroke:#333,color:#111 +``` + +--- + +## Real-World Applications + +### Payment Applications + +- **Micropayments**: Pay-per-article, API usage billing, content monetization +- **Streaming payments**: Subscription services, hourly billing, real-time payroll +- **P2P transfers**: Instant remittances without intermediaries + +### Gaming Applications + +- **Turn-based games**: Chess, poker, strategy games with wagers +- **Real-time multiplayer**: In-game economies with instant transactions +- **Tournaments**: Prize pools and automated payouts + +### DeFi Applications + +- **High-frequency trading**: Execute trades without MEV concerns +- **Prediction markets**: Real-time betting with instant settlement +- **Escrow services**: Multi-party coordination with dispute resolution + +--- + +## Security Model + +Yellow Network maintains blockchain-level security despite operating off-chain: + +| Guarantee | How It's Achieved | +|-----------|-------------------| +| **Fund Safety** | All funds locked in audited smart contracts | +| **Dispute Resolution** | Challenge period allows contesting incorrect states | +| **Cryptographic Proof** | Every state transition is signed by participants | +| **Recovery Guarantee** | Users can always recover funds via on-chain contracts | + +If a Clearnode becomes unresponsive or malicious, you can submit your latest signed state to the blockchain and recover your funds after a challenge period. + +--- + +## Next Steps + +Now that you understand what Yellow solves, continue to: + +- **[Architecture at a Glance](./architecture-at-a-glance)** — See how the protocol layers work together +- **[Quickstart](../getting-started/quickstart)** — Create your first state channel in minutes diff --git a/sidebars.ts b/sidebars.ts index 8022ca4..7b8058f 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -24,17 +24,32 @@ const sidebars: SidebarsConfig = { type: 'category', label: 'Introduction', items: [ - 'learn/introduction/what-is-yellow-sdk', - 'learn/introduction/yellow-apps', + 'learn/introduction/what-yellow-solves', + 'learn/introduction/architecture-at-a-glance', ], collapsible: false, collapsed: false, }, { type: 'category', - label: 'Beginner', + label: 'Getting Started', items: [ - 'learn/beginner/app-session-management', + 'learn/getting-started/quickstart', + 'learn/getting-started/prerequisites', + 'learn/getting-started/key-terms', + ], + collapsible: false, + collapsed: false, + }, + { + type: 'category', + label: 'Core Concepts', + items: [ + 'learn/core-concepts/state-channels-vs-l1-l2', + 'learn/core-concepts/app-sessions', + 'learn/core-concepts/session-keys', + 'learn/core-concepts/challenge-response', + 'learn/core-concepts/message-envelope', ], collapsible: false, collapsed: false, From 1648476a830b42daf57a762ac5634eb28a9c6b4b Mon Sep 17 00:00:00 2001 From: Maharshi Mishra Date: Fri, 28 Nov 2025 17:46:16 +0530 Subject: [PATCH 2/5] Divided session keys into two docs --- docs/learn/advanced/managing-session-keys.md | 190 ++++++++++++++++++ docs/learn/core-concepts/_category_.json | 1 + .../learn/core-concepts/challenge-response.md | 6 +- docs/learn/core-concepts/session-keys.md | 136 ++++--------- .../core-concepts/state-channels-vs-l1-l2.md | 10 +- docs/learn/deprecated/_category_.json | 1 + docs/learn/getting-started/_category_.json | 1 + docs/learn/getting-started/key-terms.md | 1 + docs/learn/getting-started/prerequisites.md | 1 + docs/learn/getting-started/quickstart.md | 1 + .../introduction/architecture-at-a-glance.md | 4 + docs/learn/introduction/what-yellow-solves.md | 16 +- sidebars.ts | 9 + 13 files changed, 275 insertions(+), 102 deletions(-) create mode 100644 docs/learn/advanced/managing-session-keys.md diff --git a/docs/learn/advanced/managing-session-keys.md b/docs/learn/advanced/managing-session-keys.md new file mode 100644 index 0000000..ff18b49 --- /dev/null +++ b/docs/learn/advanced/managing-session-keys.md @@ -0,0 +1,190 @@ +--- +sidebar_position: 1 +title: Managing Session Keys +description: Create, list, and revoke session keys with complete API examples +keywords: [session keys, authentication, API, create, revoke, manage] +--- + +# Managing Session Keys + +This guide covers the operational details of creating, listing, and revoking session keys via the Clearnode API. + +:::info Prerequisites +Before diving into session key management, make sure you understand the core concepts: what session keys are, how applications and allowances work, and the expiration rules. See **[Session Keys](../core-concepts/session-keys)** for the conceptual foundation. +::: + +--- + +## How to Manage Session Keys + +### Clearnode + +#### Create and Configure + +To create a session key, use the `auth_request` method during authentication. This registers the session key with its configuration: + +**Request:** + +```json +{ + "req": [ + 1, + "auth_request", + { + "address": "0x1234567890abcdef...", + "session_key": "0x9876543210fedcba...", + "application": "Chess Game", + "allowances": [ + { + "asset": "usdc", + "amount": "100.0" + }, + { + "asset": "eth", + "amount": "0.5" + } + ], + "scope": "app.create", + "expires_at": 1762417328 + }, + 1619123456789 + ], + "sig": ["0x5432abcdef..."] +} +``` + +**Parameters:** + +- `address` (required): The wallet address that owns this session key +- `session_key` (required): The address of the session key to register +- `application` (optional): Name of the application using this session key (defaults to "clearnode" if not provided) +- `allowances` (optional): Array of asset allowances specifying spending limits +- `scope` (optional): Permission scope (e.g., "app.create", "ledger.readonly"). **Note:** This feature is not yet implemented +- `expires_at` (required): Unix timestamp (in seconds) when this session key expires + +:::note +When authenticating with an already registered session key, you must still fill in all fields in the request, at least with arbitrary values. This is required by the request itself, however, the values will be ignored as the system uses the session key configuration stored during initial registration. This behavior will be improved in future versions. +::: + +#### List Active Session Keys + +Use the `get_session_keys` method to retrieve all active (non-expired) session keys for the authenticated user: + +**Request:** + +```json +{ + "req": [1, "get_session_keys", {}, 1619123456789], + "sig": ["0x9876fedcba..."] +} +``` + +**Response:** + +```json +{ + "res": [ + 1, + "get_session_keys", + { + "session_keys": [ + { + "id": 1, + "session_key": "0xabcdef1234567890...", + "application": "Chess Game", + "allowances": [ + { + "asset": "usdc", + "allowance": "100.0", + "used": "45.0" + }, + { + "asset": "eth", + "allowance": "0.5", + "used": "0.0" + } + ], + "scope": "app.create", + "expires_at": "2024-12-31T23:59:59Z", + "created_at": "2024-01-01T00:00:00Z" + } + ] + }, + 1619123456789 + ], + "sig": ["0xabcd1234..."] +} +``` + +**Response Fields:** + +- `id`: Unique identifier for the session key record +- `session_key`: The address of the session key +- `application`: Application name this session key is authorized for +- `allowances`: Array of allowances with usage tracking: + - `asset`: Symbol of the asset (e.g., "usdc", "eth") + - `allowance`: Maximum amount the session key can spend + - `used`: Amount already spent by this session key +- `scope`: Permission scope (omitted if empty) +- `expires_at`: When this session key expires (ISO 8601 format) +- `created_at`: When the session key was created (ISO 8601 format) + +#### Revoke a Session Key + +To immediately invalidate a session key, use the `revoke_session_key` method: + +**Request:** + +```json +{ + "req": [ + 1, + "revoke_session_key", + { + "session_key": "0xabcdef1234567890..." + }, + 1619123456789 + ], + "sig": ["0x9876fedcba..."] +} +``` + +**Response:** + +```json +{ + "res": [ + 1, + "revoke_session_key", + { + "session_key": "0xabcdef1234567890..." + }, + 1619123456789 + ], + "sig": ["0xabcd1234..."] +} +``` + +**Permission Rules:** + +- A wallet can revoke any of its session keys +- A session key can revoke itself +- A session key with `application: "clearnode"` can revoke other session keys belonging to the same wallet +- A non-"clearnode" session key cannot revoke other session keys (only itself) + +**Important Notes:** + +- Revocation is **immediate and cannot be undone** +- After revocation, any operations attempted with the revoked session key will fail with a validation error +- The revoked session key will no longer appear in the `get_session_keys` response +- Revocation is useful for security purposes when a session key may have been compromised + +**Error Cases:** + +- Session key does not exist, belongs to another wallet, or is expired: `"operation denied: provided address is not an active session key of this user"` +- Non-"clearnode" session key attempting to revoke another session key: `"operation denied: insufficient permissions for the active session key"` + +### Nitrolite SDK + +The Nitrolite SDK provides a higher-level abstraction for managing session keys. For detailed information on using session keys with the Nitrolite SDK, please refer to the SDK documentation. + diff --git a/docs/learn/core-concepts/_category_.json b/docs/learn/core-concepts/_category_.json index 53585cb..e2a77fe 100644 --- a/docs/learn/core-concepts/_category_.json +++ b/docs/learn/core-concepts/_category_.json @@ -5,3 +5,4 @@ "collapsed": false } + diff --git a/docs/learn/core-concepts/challenge-response.md b/docs/learn/core-concepts/challenge-response.md index 2f806d8..68dcbf1 100644 --- a/docs/learn/core-concepts/challenge-response.md +++ b/docs/learn/core-concepts/challenge-response.md @@ -78,7 +78,11 @@ Every state has a version number. A newer (higher version) state always supersed ### States Are Signed -Both parties must sign every state. If someone signed a state, they can't later claim they didn't agree. +With the default SimpleConsensus adjudicator, both parties must sign every state. If someone signed a state, they can't later claim they didn't agree. + +:::note Other Adjudicators +Different adjudicators may have different signing requirements. For example, a Remittance adjudicator may only require the sender's signature. The signing rules are defined by the channel's adjudicator contract. +::: ### Challenge Period Provides Fairness diff --git a/docs/learn/core-concepts/session-keys.md b/docs/learn/core-concepts/session-keys.md index 06844ba..18b176a 100644 --- a/docs/learn/core-concepts/session-keys.md +++ b/docs/learn/core-concepts/session-keys.md @@ -9,6 +9,10 @@ keywords: [session keys, authentication, signatures, allowances, security] Session keys are delegated keys that enable applications to perform operations on behalf of a user's wallet with specified spending limits, permissions, and expiration times. They provide a secure way to grant limited access to applications without exposing the main wallet's private key. +:::important +Session keys are **no longer used as on-chain channel participant addresses** for new channels created after the v0.5.0 release. For all new channels, the wallet address is used directly as the participant address. However, session keys still function correctly for channels that were created before v0.5.0, ensuring backward compatibility. +::: + **Goal**: Understand how session keys enable seamless UX while maintaining security. --- @@ -23,20 +27,15 @@ Session keys solve this by allowing you to **sign once**, then operate seamlessl ## Core Concepts -### How Session Keys Work - -1. You generate a session keypair **locally** on your device -2. Your main wallet **authorizes** the session key (one-time EIP-712 signature) -3. The session key signs **all subsequent operations** without wallet prompts -4. The session key has **limited permissions** (spending caps, expiration) +### General Rules -> **Important:** Session keys are **no longer used as on-chain channel participant addresses** for new channels created after v0.5.0. For all new channels, the wallet address is used directly as the participant address. However, session keys still function correctly for channels created before v0.5.0, ensuring backward compatibility. - ---- +:::important +When authenticating with an already registered session key, you must still provide all parameters in the `auth_request`. However, the configuration values (`application`, `allowances`, `scope`, and `expires_at`) from the request will be ignored, as the system uses the settings from the initial registration. You may provide arbitrary values for these fields, as they are required by the request format but will not be used. +::: ### Applications -Each session key is associated with a specific **application name**, which identifies the application or service that will use the session key. +Each session key is associated with a specific **application name**, which identifies the application or service that will use the session key. The application name is also used to identify **app sessions** that are created using that session key. This association serves several purposes: @@ -44,7 +43,9 @@ This association serves several purposes: - **Access Control**: Operations performed with a session key are validated against the application specified during registration - **Single Active Key**: Only one session key can be active per wallet+application combination. Registering a new session key for the same application automatically invalidates any existing session key for that application -> **Important:** Only one session key is allowed per wallet+application combination. If you register a new session key for the same application, the old one is automatically invalidated and removed. +:::important +Only one session key is allowed per wallet+application combination. If you register a new session key for the same application, the old one is automatically invalidated and removed from the database. +::: #### Special Application: "clearnode" @@ -55,40 +56,52 @@ Session keys registered with the application name `"clearnode"` receive special - **Backward Compatibility**: This special behavior facilitates migration from older versions - **Expiration Still Applies**: Even with root access, the session key expires according to its `expires_at` timestamp -> **Note:** The "clearnode" application name is primarily for backward compatibility and will be deprecated after a migration period. - ---- +:::note +The "clearnode" application name is primarily for backward compatibility and will be deprecated after a migration period for developers. +::: ### Expiration All session keys must have an **expiration timestamp** (`expires_at`) that defines when the session key becomes invalid: -- **Future Timestamp Required**: The expiration time must be set to a future date when registering -- **Automatic Invalidation**: Once the expiration time passes, the session key can no longer be used -- **No Re-registration**: It is not possible to re-register an expired session key—you must create a new one -- **Applies to All Keys**: Even "clearnode" session keys must respect the expiration timestamp - ---- +- **Future Timestamp Required**: The expiration time must be set to a future date when registering a session key +- **Automatic Invalidation**: Once the expiration time passes, the session key can no longer be used for any operations +- **No Re-registration**: It is not possible to re-register an expired session key. You must create a new session key instead +- **Applies to All Keys**: Even "clearnode" application session keys must respect the expiration timestamp ### Allowances -Allowances define **spending limits** for session keys, specifying which assets the session key can spend and how much. - -| Field | Description | Example | -|-------|-------------|---------| -| `asset` | Asset symbol | `"usdc"`, `"eth"` | -| `amount` | Maximum spending limit | `"100.0"` | +Allowances define **spending limits** for session keys, specifying which assets the session key can spend and how much: + +```json +{ + "allowances": [ + { + "asset": "usdc", + "amount": "100.0" + }, + { + "asset": "eth", + "amount": "0.5" + } + ] +} +``` #### Allowance Validation - **Supported Assets Only**: All assets specified in allowances must be supported by the system. Unsupported assets cause authentication to fail - **Usage Tracking**: The system tracks spending per session key by recording which session key was used for each ledger debit operation -- **Spending Limits**: Once a session key reaches its spending cap, further operations are rejected with: `"operation denied: insufficient session key allowance"` -- **Empty Allowances**: Providing an empty `allowances` array means zero spending allowed—any operation attempting to spend funds will be rejected +- **Spending Limits**: Once a session key reaches its spending cap for an asset, further operations requiring that asset are rejected with: `"operation denied: insufficient session key allowance: X required, Y available"` +- **Empty Allowances**: Providing an empty `allowances` array (`[]`) means zero spending allowed for all assets—any operation attempting to spend funds will be rejected #### Allowances for "clearnode" Application -Session keys with `application: "clearnode"` are exempt from allowance enforcement—they can spend any amount of any supported asset. +Session keys with `application: "clearnode"` are exempt from allowance enforcement: + +- **No Spending Limits**: Allowance checks are bypassed entirely +- **Full Financial Access**: These keys can spend any amount of any supported asset +- **Expiration Still Matters**: Even without allowance restrictions, the session key still expires according to its `expires_at` timestamp --- @@ -109,65 +122,6 @@ stateDiagram-v2 --- -## Managing Session Keys - -### Create and Configure - -To create a session key, use the `auth_request` method during authentication. This registers the session key with its configuration. - -**Parameters:** - -| Parameter | Required | Description | -|-----------|----------|-------------| -| `address` | Yes | The wallet address that owns this session key | -| `session_key` | Yes | The address of the session key to register | -| `application` | No | Name of the application (defaults to "clearnode") | -| `allowances` | No | Array of asset allowances specifying spending limits | -| `scope` | No | Permission scope (not yet implemented) | -| `expires_at` | Yes | Unix timestamp (seconds) when this session key expires | - -> **Important:** When authenticating with an already registered session key, you must still provide all parameters in the `auth_request`. However, the configuration values from the request will be ignored—the system uses the settings from the initial registration. - ---- - -### List Active Session Keys - -Use `get_session_keys` to retrieve all active (non-expired) session keys for the authenticated user. - -The response includes: - -| Field | Description | -|-------|-------------| -| `id` | Unique identifier for the session key record | -| `session_key` | The address of the session key | -| `application` | Application name this session key is authorized for | -| `allowances` | Array with `asset`, `allowance`, and `used` amounts | -| `scope` | Permission scope (omitted if empty) | -| `expires_at` | When this session key expires (ISO 8601 format) | -| `created_at` | When the session key was created (ISO 8601 format) | - ---- - -### Revoke a Session Key - -To immediately invalidate a session key, use the `revoke_session_key` method. - -**Permission Rules:** - -- A wallet can revoke any of its session keys -- A session key can revoke itself -- A session key with `application: "clearnode"` can revoke other session keys belonging to the same wallet -- A non-"clearnode" session key cannot revoke other session keys (only itself) - -**Important Notes:** - -- Revocation is **immediate and cannot be undone** -- After revocation, any operations attempted with the revoked session key will fail -- The revoked session key will no longer appear in `get_session_keys` response -- Revocation is useful for security purposes when a session key may have been compromised - ---- - ## Security Model | Approach | Risk if Compromised | UX Impact | @@ -213,10 +167,8 @@ You can skip session keys entirely and sign every request with your main wallet. --- -## Deep Dive - -For complete API specifications and implementation details: +## Next Steps +- **[Managing Session Keys](../advanced/managing-session-keys)** — Create, list, and revoke session keys with full API examples - **[Authentication Flow](/docs/protocol/off-chain/authentication)** — Full 3-step authentication protocol - **[Communication Flows](/docs/protocol/communication-flows#authentication-flow)** — Sequence diagrams for auth -- **[Implementation Checklist](/docs/protocol/implementation-checklist#authentication)** — Building session key support diff --git a/docs/learn/core-concepts/state-channels-vs-l1-l2.md b/docs/learn/core-concepts/state-channels-vs-l1-l2.md index 868f460..625710e 100644 --- a/docs/learn/core-concepts/state-channels-vs-l1-l2.md +++ b/docs/learn/core-concepts/state-channels-vs-l1-l2.md @@ -19,7 +19,9 @@ In this guide, you will learn how state channels compare to Layer 1 and Layer 2 |----------|------------|---------|-------------|----------| | **Layer 1** | 15-65K TPS | 1-15 sec | $0.001-$50 | Settlement, contracts | | **Layer 2** | 2,000-4,000 TPS | 1-10 sec | $0.01-$0.50 | General dApps | -| **State Channels** | **Unlimited** | **< 1 sec** | **$0** | High-frequency, known parties | +| **State Channels** | **Unlimited*** | **< 1 sec** | **$0** | High-frequency, known parties | + +*\*Theoretically unlimited—no consensus bottleneck. Real-world throughput depends on signature generation, network latency, and application logic. Benchmarking documentation coming soon.* --- @@ -64,7 +66,7 @@ Off-chain transactions are only visible to participants. Only opening and final ### Known Participants -Channels work between specific participants. Yellow Network solves this with the Clearnode hub-and-spoke model. +Channels work between specific participants. Yellow Network addresses this through Clearnodes—off-chain service providers that coordinate channels and provide a unified balance across multiple users and chains. ### Liquidity Requirements @@ -72,7 +74,7 @@ Funds must be locked upfront. You can't spend more than what's locked in the cha ### Liveness Requirements -Participants must respond to challenges within the challenge period. The Clearnode provides 24/7 monitoring. +Participants must respond to challenges within the challenge period. Users should ensure they can monitor for challenges or use services that provide this functionality. --- @@ -108,7 +110,7 @@ flowchart TD | Limitation | Solution | |------------|----------| -| Known participants | Hub-and-spoke via Clearnode | +| Known participants | Clearnode coordination layer | | Liquidity | Unified balance across chains | | Liveness | Always-on Clearnode monitoring | diff --git a/docs/learn/deprecated/_category_.json b/docs/learn/deprecated/_category_.json index a3b1c2a..9cb1b34 100644 --- a/docs/learn/deprecated/_category_.json +++ b/docs/learn/deprecated/_category_.json @@ -6,3 +6,4 @@ "className": "deprecated-category" } + diff --git a/docs/learn/getting-started/_category_.json b/docs/learn/getting-started/_category_.json index 9d63847..c9b64d7 100644 --- a/docs/learn/getting-started/_category_.json +++ b/docs/learn/getting-started/_category_.json @@ -5,3 +5,4 @@ "collapsed": false } + diff --git a/docs/learn/getting-started/key-terms.md b/docs/learn/getting-started/key-terms.md index ab41369..ddecdd5 100644 --- a/docs/learn/getting-started/key-terms.md +++ b/docs/learn/getting-started/key-terms.md @@ -335,3 +335,4 @@ Now that you understand the vocabulary, continue to: For complete definitions, see the **[Glossary](/docs/protocol/glossary)**. + diff --git a/docs/learn/getting-started/prerequisites.md b/docs/learn/getting-started/prerequisites.md index b5b2107..e5eeee5 100644 --- a/docs/learn/getting-started/prerequisites.md +++ b/docs/learn/getting-started/prerequisites.md @@ -343,3 +343,4 @@ Use a dedicated RPC provider (Infura, Alchemy) instead of public endpoints for p ### TypeScript errors with viem Ensure your `tsconfig.json` has `"moduleResolution": "bundler"` or `"node16"`. + diff --git a/docs/learn/getting-started/quickstart.md b/docs/learn/getting-started/quickstart.md index bc0cff8..9fcdf85 100644 --- a/docs/learn/getting-started/quickstart.md +++ b/docs/learn/getting-started/quickstart.md @@ -339,3 +339,4 @@ The minimum challenge period is 1 hour. Ensure your `challengeDuration` is at le ### Connection issues Verify WebSocket URL and that you're connected to the correct network (testnet vs mainnet). + diff --git a/docs/learn/introduction/architecture-at-a-glance.md b/docs/learn/introduction/architecture-at-a-glance.md index 3ed2417..8b99361 100644 --- a/docs/learn/introduction/architecture-at-a-glance.md +++ b/docs/learn/introduction/architecture-at-a-glance.md @@ -173,6 +173,10 @@ stateDiagram-v2 note right of ACTIVE: This is where
99% of activity happens ``` +:::info Legacy Flow +The diagram above shows the recommended flow where both participants sign the initial state, creating the channel directly in ACTIVE status. A legacy flow also exists where only the creator signs initially (status becomes INITIAL), and other participants call `join()` separately. See [Channel Lifecycle](/docs/protocol/on-chain/channel-lifecycle) for details. +::: + ### Typical Flow 1. **Create**: Both parties sign initial state → channel becomes ACTIVE diff --git a/docs/learn/introduction/what-yellow-solves.md b/docs/learn/introduction/what-yellow-solves.md index 1211146..6ab90d0 100644 --- a/docs/learn/introduction/what-yellow-solves.md +++ b/docs/learn/introduction/what-yellow-solves.md @@ -44,9 +44,11 @@ State channels let you execute unlimited off-chain operations between on-chain c |---------|---------| | **Instant Transactions** | Sub-second finality (< 1 second typical) | | **Zero Gas Costs** | Off-chain operations incur no blockchain fees | -| **Unlimited Throughput** | 100,000+ operations per second | +| **Unlimited Throughput*** | No consensus bottleneck limiting operations | | **Blockchain Security** | Funds are always recoverable via on-chain contracts | +*\*Theoretically unlimited—state channels have no blockchain consensus overhead. Real-world performance depends on signature generation speed, network latency between participants, and application complexity. We'll be publishing detailed benchmarks soon.* + --- ## The Nitrolite Protocol @@ -73,12 +75,16 @@ Choose Yellow Network when your application needs: A **Clearnode** serves as your entry point to Yellow Network. When you connect to a Clearnode: -1. **Deposit** tokens on any supported chain -2. **Receive** a unified balance aggregated across all chains +1. **Deposit** tokens into the Custody Contract on any supported chain +2. **Resize** your channel to move funds to your unified balance 3. **Transact** instantly with any other user on the network -4. **Withdraw** to any supported chain +4. **Withdraw** back through the Custody Contract to any supported chain + +:::note Fund Flow +Funds flow through the Custody Contract (on-chain) before reaching your unified balance (off-chain). The `resize` operation moves funds between your on-chain available balance and your off-chain unified balance. See [Architecture](./architecture-at-a-glance#how-funds-flow) for the complete flow. +::: -For example, deposit 50 USDC on Polygon and 50 USDC on Base—your unified balance shows 100 USDC. You can then withdraw all 100 USDC to Arbitrum if you choose. +For example, deposit 50 USDC on Polygon and 50 USDC on Base—after resizing, your unified balance shows 100 USDC. You can then withdraw all 100 USDC to Arbitrum if you choose. ```mermaid graph LR diff --git a/sidebars.ts b/sidebars.ts index b017c9e..644ab70 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -54,6 +54,15 @@ const sidebars: SidebarsConfig = { collapsible: false, collapsed: false, }, + { + type: 'category', + label: 'Advanced', + items: [ + 'learn/advanced/managing-session-keys', + ], + collapsible: false, + collapsed: false, + }, ], // Build section sidebar From 7300f6a3997972918936ab4338f63b03da13cc2d Mon Sep 17 00:00:00 2001 From: Maharshi Mishra Date: Tue, 2 Dec 2025 21:16:24 +0530 Subject: [PATCH 3/5] Addressed PR comments --- docs/api-reference/index.md | 6 +-- docs/build/quick-start/index.md | 15 ++++-- docs/learn/core-concepts/app-sessions.md | 4 +- docs/learn/getting-started/key-terms.md | 8 +-- docs/learn/getting-started/prerequisites.md | 60 +++++++++++++++------ docs/learn/getting-started/quickstart.md | 25 ++++++--- docs/learn/index.md | 1 - 7 files changed, 83 insertions(+), 36 deletions(-) diff --git a/docs/api-reference/index.md b/docs/api-reference/index.md index 8378e90..2b535a7 100644 --- a/docs/api-reference/index.md +++ b/docs/api-reference/index.md @@ -134,7 +134,7 @@ interface ClearNodeConfig { } const config = { - endpoint: 'wss://clearnet.yellow.com/ws', + endpoint: 'wss://clearnet-sandbox.yellow.com/ws', // or wss://clearnet.yellow.com/ws for production timeout: 30000, retryAttempts: 3 }; @@ -224,8 +224,8 @@ try { ```typescript const CLEARNODE_ENDPOINTS = { - MAINNET: 'wss://clearnet.yellow.com/ws', - TESTNET: 'wss://testnet.clearnet.yellow.com/ws', + PRODUCTION: 'wss://clearnet.yellow.com/ws', + SANDBOX: 'wss://clearnet-sandbox.yellow.com/ws', LOCAL: 'ws://localhost:8080/ws' }; diff --git a/docs/build/quick-start/index.md b/docs/build/quick-start/index.md index d846148..3cab60d 100644 --- a/docs/build/quick-start/index.md +++ b/docs/build/quick-start/index.md @@ -68,13 +68,18 @@ pnpm add @erc7824/nitrolite ## Step 2: Connect to ClearNode -Create a file `app.js` and connect to the Yellow Network: +Create a file `app.js` and connect to the Yellow Network. + +:::tip Clearnode Endpoints +- **Production**: `wss://clearnet.yellow.com/ws` +- **Sandbox**: `wss://clearnet-sandbox.yellow.com/ws` (recommended for testing) +::: ```javascript title="app.js" showLineNumbers import { createAppSessionMessage, parseRPCResponse } from '@erc7824/nitrolite'; -// Connect to Yellow Network -const ws = new WebSocket('wss://clearnet.yellow.com/ws'); +// Connect to Yellow Network (using sandbox for testing) +const ws = new WebSocket('wss://clearnet-sandbox.yellow.com/ws'); ws.onopen = () => { console.log('✅ Connected to Yellow Network!'); @@ -245,8 +250,8 @@ class SimplePaymentApp { this.userAddress = userAddress; this.messageSigner = messageSigner; - // Step 2: Connect to ClearNode - this.ws = new WebSocket('wss://clearnet.yellow.com/ws'); + // Step 2: Connect to ClearNode (sandbox for testing) + this.ws = new WebSocket('wss://clearnet-sandbox.yellow.com/ws'); this.ws.onopen = () => { console.log('🟢 Connected to Yellow Network!'); diff --git a/docs/learn/core-concepts/app-sessions.md b/docs/learn/core-concepts/app-sessions.md index 95eeae9..18c31d9 100644 --- a/docs/learn/core-concepts/app-sessions.md +++ b/docs/learn/core-concepts/app-sessions.md @@ -170,8 +170,8 @@ Always use `NitroRPC/0.4` for new applications. Protocol version is set at creat ## Deep Dive -For complete API specifications and implementation details: +For complete method specifications and implementation details: -- **[App Session Methods](/docs/protocol/off-chain/app-sessions)** — Full API reference +- **[App Session Methods](/docs/protocol/off-chain/app-sessions)** — Complete method specifications - **[Communication Flows](/docs/protocol/communication-flows#app-session-lifecycle-flow)** — Sequence diagrams - **[Implementation Checklist](/docs/protocol/implementation-checklist#state-management)** — Building app session support diff --git a/docs/learn/getting-started/key-terms.md b/docs/learn/getting-started/key-terms.md index ddecdd5..82a5dfb 100644 --- a/docs/learn/getting-started/key-terms.md +++ b/docs/learn/getting-started/key-terms.md @@ -53,8 +53,8 @@ A **Channel** is the on-chain representation of a state channel. It defines: ```typescript { - participants: ['0xAlice', '0xBob'], // Who can participate - adjudicator: '0xContract', // Rules for state validation + participants: ['0xAlice', '0xBob'], // Who can participate + adjudicator: '0xContract', // Rules for state validation challenge: 86400, // Dispute window (seconds) nonce: 1699123456789 // Unique identifier } @@ -93,7 +93,7 @@ An **Allocation** specifies how funds should be distributed: ```typescript { destination: '0xAlice', // Recipient address - token: '0xUSDC_CONTRACT', // Token contract + token: '0xUSDC_CONTRACT', // Token contract amount: 50000000n // Amount in smallest unit (6 decimals for USDC) } ``` @@ -140,7 +140,7 @@ An **App Session** is an off-chain channel built on top of the unified balance f { protocol: 'NitroRPC/0.4', participants: ['0xAlice', '0xBob', '0xJudge'], - weights: [40, 40, 50], // Voting power + weights: [40, 40, 50], // Voting power quorum: 80, // Required weight for state updates challenge: 3600, // Dispute window nonce: 1699123456789 diff --git a/docs/learn/getting-started/prerequisites.md b/docs/learn/getting-started/prerequisites.md index e5eeee5..94c9d8b 100644 --- a/docs/learn/getting-started/prerequisites.md +++ b/docs/learn/getting-started/prerequisites.md @@ -154,11 +154,9 @@ SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY BASE_RPC_URL=https://base-sepolia.g.alchemy.com/v2/YOUR_KEY # Clearnode WebSocket endpoint -CLEARNODE_WS_URL=wss://clearnode.yellow.com/ws - -# Contract addresses (get from Yellow Network docs) -CUSTODY_ADDRESS=0x... -ADJUDICATOR_ADDRESS=0x... +# Production: wss://clearnet.yellow.com/ws +# Sandbox: wss://clearnet-sandbox.yellow.com/ws +CLEARNODE_WS_URL=wss://clearnet-sandbox.yellow.com/ws ``` Add to `.gitignore`: @@ -207,7 +205,25 @@ npx tsx scripts/create-wallet.ts ### Get Test Tokens -For testnet development, you need test tokens: +#### Yellow Network Sandbox Faucet (Recommended) + +For testing on the Yellow Network Sandbox, you can request test tokens directly to your unified balance: + +```bash +curl -XPOST https://clearnet-sandbox.yellow.com/faucet/requestTokens \ + -H "Content-Type: application/json" \ + -d '{"userAddress":""}' +``` + +Replace `` with your actual wallet address. + +:::tip No On-Chain Operations Needed +Test tokens (ytest.USD) are credited directly to your unified balance on the Sandbox Clearnode. No deposit or channel operations are required—you can start transacting immediately! +::: + +#### Testnet Faucets (For On-Chain Testing) + +If you need on-chain test tokens for Sepolia or Base Sepolia: | Network | Faucet | |---------|--------| @@ -306,16 +322,30 @@ yellow-app/ ## Supported Networks -Yellow Network currently supports these EVM-compatible chains: +To get the current list of supported chains and contract addresses, query the Clearnode's `get_config` endpoint: + +```javascript +// Example: Fetch supported chains and contract addresses +const ws = new WebSocket('wss://clearnet-sandbox.yellow.com/ws'); + +ws.onopen = () => { + const request = { + req: [1, 'get_config', {}, Date.now()], + sig: [] // get_config is a public endpoint, no signature required + }; + ws.send(JSON.stringify(request)); +}; + +ws.onmessage = (event) => { + const response = JSON.parse(event.data); + console.log('Supported chains:', response.res[2].chains); + console.log('Contract addresses:', response.res[2].contracts); +}; +``` -| Network | Chain ID | Status | -|---------|----------|--------| -| Ethereum Mainnet | 1 | Production | -| Polygon | 137 | Production | -| Arbitrum One | 42161 | Production | -| Optimism | 10 | Production | -| Base | 8453 | Production | -| Sepolia (testnet) | 11155111 | Testing | +:::tip Dynamic Configuration +The `get_config` method returns real-time information about supported chains, contract addresses, and Clearnode capabilities. This ensures you always have the most up-to-date network information. +::: --- diff --git a/docs/learn/getting-started/quickstart.md b/docs/learn/getting-started/quickstart.md index 9fcdf85..e53ce56 100644 --- a/docs/learn/getting-started/quickstart.md +++ b/docs/learn/getting-started/quickstart.md @@ -19,10 +19,18 @@ Before starting, ensure you have: - Node.js 18+ installed - A Web3 wallet (MetaMask, Rabby, or similar) -- Test tokens on a supported testnet (Sepolia, Base Goerli, etc.) +- Test tokens from the Yellow Network Sandbox faucet -:::tip Quick Setup -If you don't have test tokens, you can use a testnet faucet. Most testnets provide free tokens for development. +:::tip Get Test Tokens +Request test tokens directly to your unified balance: + +```bash +curl -XPOST https://clearnet-sandbox.yellow.com/faucet/requestTokens \ + -H "Content-Type: application/json" \ + -d '{"userAddress":""}' +``` + +Tokens are credited immediately—no on-chain operations needed! For complete setup instructions, see [Prerequisites](./prerequisites#get-test-tokens). ::: --- @@ -96,11 +104,16 @@ console.log('✓ Client initialized'); ## Step 3: Authenticate with Clearnode -Establish a session with the Clearnode using the 3-step authentication flow: +Establish a session with the Clearnode using the 3-step authentication flow. + +:::tip Clearnode Endpoints +- **Production**: `wss://clearnet.yellow.com/ws` +- **Sandbox**: `wss://clearnet-sandbox.yellow.com/ws` (recommended for testing) +::: ```javascript -// Connect to Clearnode WebSocket -const ws = new WebSocket('wss://clearnode.yellow.com/ws'); +// Connect to Clearnode WebSocket (using sandbox for testing) +const ws = new WebSocket('wss://clearnet-sandbox.yellow.com/ws'); // Step 1: Generate session keypair locally const sessionPrivateKey = generatePrivateKey(); // Your crypto library diff --git a/docs/learn/index.md b/docs/learn/index.md index c75b191..be600d3 100644 --- a/docs/learn/index.md +++ b/docs/learn/index.md @@ -55,7 +55,6 @@ After completing the Learn section, continue to: - **[Build](/docs/build/quick-start)** — Implement complete Yellow Applications - **[Protocol Reference](/docs/protocol/introduction)** — Authoritative protocol specification -- **[API Reference](/docs/api-reference)** — SDK and RPC method documentation --- From b0a3b5f8c35edf048e0efb8ea0a0aafe0f32fa29 Mon Sep 17 00:00:00 2001 From: Maharshi Mishra Date: Tue, 2 Dec 2025 22:32:08 +0530 Subject: [PATCH 4/5] switched to mdx + tooltips usage --- ...sion-keys.md => managing-session-keys.mdx} | 5 +- docs/learn/beginner/_category_.json | 6 - docs/learn/beginner/session-keys.md | 248 ------ .../{app-sessions.md => app-sessions.mdx} | 15 +- ...nge-response.md => challenge-response.mdx} | 15 +- ...ssage-envelope.md => message-envelope.mdx} | 9 +- .../{session-keys.md => session-keys.mdx} | 13 +- ...s-l1-l2.md => state-channels-vs-l1-l2.mdx} | 13 +- docs/learn/deprecated/_category_.json | 9 - .../learn/deprecated/advanced/_category_.json | 6 - .../learn/deprecated/advanced/architecture.md | 293 ------- docs/learn/deprecated/advanced/deployment.md | 757 ------------------ docs/learn/deprecated/advanced/index.md | 28 - docs/learn/deprecated/advanced/multi-party.md | 719 ----------------- docs/learn/deprecated/advanced/security.md | 408 ---------- .../learn/deprecated/beginner/_category_.json | 6 - .../beginner/app-session-management.md | 418 ---------- .../deprecated/introduction/_category_.json | 6 - .../introduction/what-is-yellow-sdk.md | 133 --- .../deprecated/introduction/yellow-apps.md | 46 -- .../{key-terms.md => key-terms.mdx} | 13 +- .../{prerequisites.md => prerequisites.mdx} | 9 +- .../{quickstart.md => quickstart.mdx} | 11 +- docs/learn/index.md | 73 -- docs/learn/index.mdx | 76 ++ ...glance.md => architecture-at-a-glance.mdx} | 25 +- ...ellow-solves.md => what-yellow-solves.mdx} | 15 +- 27 files changed, 163 insertions(+), 3212 deletions(-) rename docs/learn/advanced/{managing-session-keys.md => managing-session-keys.mdx} (96%) delete mode 100644 docs/learn/beginner/_category_.json delete mode 100644 docs/learn/beginner/session-keys.md rename docs/learn/core-concepts/{app-sessions.md => app-sessions.mdx} (84%) rename docs/learn/core-concepts/{challenge-response.md => challenge-response.mdx} (84%) rename docs/learn/core-concepts/{message-envelope.md => message-envelope.mdx} (90%) rename docs/learn/core-concepts/{session-keys.md => session-keys.mdx} (88%) rename docs/learn/core-concepts/{state-channels-vs-l1-l2.md => state-channels-vs-l1-l2.mdx} (80%) delete mode 100644 docs/learn/deprecated/_category_.json delete mode 100644 docs/learn/deprecated/advanced/_category_.json delete mode 100644 docs/learn/deprecated/advanced/architecture.md delete mode 100644 docs/learn/deprecated/advanced/deployment.md delete mode 100644 docs/learn/deprecated/advanced/index.md delete mode 100644 docs/learn/deprecated/advanced/multi-party.md delete mode 100644 docs/learn/deprecated/advanced/security.md delete mode 100644 docs/learn/deprecated/beginner/_category_.json delete mode 100644 docs/learn/deprecated/beginner/app-session-management.md delete mode 100644 docs/learn/deprecated/introduction/_category_.json delete mode 100644 docs/learn/deprecated/introduction/what-is-yellow-sdk.md delete mode 100644 docs/learn/deprecated/introduction/yellow-apps.md rename docs/learn/getting-started/{key-terms.md => key-terms.mdx} (95%) rename docs/learn/getting-started/{prerequisites.md => prerequisites.mdx} (96%) rename docs/learn/getting-started/{quickstart.md => quickstart.mdx} (95%) delete mode 100644 docs/learn/index.md create mode 100644 docs/learn/index.mdx rename docs/learn/introduction/{architecture-at-a-glance.md => architecture-at-a-glance.mdx} (84%) rename docs/learn/introduction/{what-yellow-solves.md => what-yellow-solves.mdx} (84%) diff --git a/docs/learn/advanced/managing-session-keys.md b/docs/learn/advanced/managing-session-keys.mdx similarity index 96% rename from docs/learn/advanced/managing-session-keys.md rename to docs/learn/advanced/managing-session-keys.mdx index ff18b49..ef0f2ad 100644 --- a/docs/learn/advanced/managing-session-keys.md +++ b/docs/learn/advanced/managing-session-keys.mdx @@ -5,12 +5,15 @@ description: Create, list, and revoke session keys with complete API examples keywords: [session keys, authentication, API, create, revoke, manage] --- +import Tooltip from '@site/src/components/Tooltip'; +import { tooltipDefinitions } from '@site/src/constants/tooltipDefinitions'; + # Managing Session Keys This guide covers the operational details of creating, listing, and revoking session keys via the Clearnode API. :::info Prerequisites -Before diving into session key management, make sure you understand the core concepts: what session keys are, how applications and allowances work, and the expiration rules. See **[Session Keys](../core-concepts/session-keys)** for the conceptual foundation. +Before diving into session key management, make sure you understand the core concepts: what session keys are, how applications and allowances work, and the expiration rules. See **[Session Keys](../core-concepts/session-keys.mdx)** for the conceptual foundation. ::: --- diff --git a/docs/learn/beginner/_category_.json b/docs/learn/beginner/_category_.json deleted file mode 100644 index 0d3ad4b..0000000 --- a/docs/learn/beginner/_category_.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "label": "Beginner", - "position": 2, - "collapsible": false, - "collapsed": false -} \ No newline at end of file diff --git a/docs/learn/beginner/session-keys.md b/docs/learn/beginner/session-keys.md deleted file mode 100644 index e66a6eb..0000000 --- a/docs/learn/beginner/session-keys.md +++ /dev/null @@ -1,248 +0,0 @@ -# Session Keys - -Session keys are delegated keys that enable applications to perform operations on behalf of a user's wallet with specified spending limits, permissions, and expiration times. They provide a secure way to grant limited access to applications without exposing the main wallet's private key. - -> **Important:** Session keys are **no longer used as on-chain channel participant addresses** for new channels created after the v0.5.0 release. For all new channels, the wallet address is used directly as the participant address. However, session keys still function correctly for channels that were created before v0.5.0, ensuring backward compatibility. - -## Core Concepts - -### General Rules - -> **Important:** When authenticating with an already registered session key, you must still provide all parameters in the `auth_request`. However, the configuration values (`application`, `allowances`, `scope`, and `expires_at`) from the request will be ignored, as the system uses the settings from the initial registration. You may provide arbitrary values for these fields, as they are required by the request format but will not be used. - -### Applications - -Each session key is associated with a specific **application name**, which identifies the application or service that will use the session key. The application name is also used to identify **app sessions** that are created using that session key. - -This association serves several purposes: - -- **Application Isolation**: Different applications get separate session keys, preventing one application from using another's delegated access -- **Access Control**: Operations performed with a session key are validated against the application specified during registration -- **Single Active Key**: Only one session key can be active per wallet+application combination. Registering a new session key for the same application automatically invalidates any existing session key for that application - -> **Important:** Only one session key is allowed per wallet+application combination. If you register a new session key for the same application, the old one is automatically invalidated and removed from the database. - -#### Special Application: "clearnode" - -Session keys registered with the application name `"clearnode"` receive special treatment: - -- **Root Access**: These session keys bypass spending allowance validation and application restrictions -- **Full Permissions**: They can perform any operation the wallet itself could perform -- **Backward Compatibility**: This special behavior facilitates migration from older versions -- **Expiration Still Applies**: Even with root access, the session key expires according to its `expires_at` timestamp - -> **Note:** The "clearnode" application name is primarily for backward compatibility and will be deprecated after a migration period for developers. - -### Expiration - -All session keys must have an **expiration timestamp** (`expires_at`) that defines when the session key becomes invalid: - -- **Future Timestamp Required**: The expiration time must be set to a future date when registering a session key -- **Automatic Invalidation**: Once the expiration time passes, the session key can no longer be used for any operations -- **No Re-registration**: It is not possible to re-register an expired session key. You must create a new session key instead -- **Applies to All Keys**: Even "clearnode" application session keys must respect the expiration timestamp - -### Allowances - -Allowances define **spending limits** for session keys, specifying which assets the session key can spend and how much: - -```json -{ - "allowances": [ - { - "asset": "usdc", - "amount": "100.0" - }, - { - "asset": "eth", - "amount": "0.5" - } - ] -} -``` - -#### Allowance Validation - -- **Supported Assets Only**: All assets specified in allowances must be supported by the system. Unsupported assets cause authentication to fail -- **Usage Tracking**: The system tracks spending per session key by recording which session key was used for each ledger debit operation -- **Spending Limits**: Once a session key reaches its spending cap for an asset, further operations requiring that asset are rejected with: `"operation denied: insufficient session key allowance: X required, Y available"` -- **Empty Allowances**: Providing an empty `allowances` array (`[]`) means zero spending allowed for all assets—any operation attempting to spend funds will be rejected - -#### Allowances for "clearnode" Application - -Session keys with `application: "clearnode"` are exempt from allowance enforcement: - -- **No Spending Limits**: Allowance checks are bypassed entirely -- **Full Financial Access**: These keys can spend any amount of any supported asset -- **Expiration Still Matters**: Even without allowance restrictions, the session key still expires according to its `expires_at` timestamp - -## How to Manage Session Keys - -### Clearnode - -#### Create and Configure - -To create a session key, use the `auth_request` method during authentication. This registers the session key with its configuration: - -**Request:** - -```json -{ - "req": [ - 1, - "auth_request", - { - "address": "0x1234567890abcdef...", - "session_key": "0x9876543210fedcba...", - "application": "Chess Game", - "allowances": [ - { - "asset": "usdc", - "amount": "100.0" - }, - { - "asset": "eth", - "amount": "0.5" - } - ], - "scope": "app.create", - "expires_at": 1762417328 - }, - 1619123456789 - ], - "sig": ["0x5432abcdef..."] -} -``` - -**Parameters:** - -- `address` (required): The wallet address that owns this session key -- `session_key` (required): The address of the session key to register -- `application` (optional): Name of the application using this session key (defaults to "clearnode" if not provided) -- `allowances` (optional): Array of asset allowances specifying spending limits -- `scope` (optional): Permission scope (e.g., "app.create", "ledger.readonly"). **Note:** This feature is not yet implemented -- `expires_at` (required): Unix timestamp (in seconds) when this session key expires - -> **Note:** When authenticating with an already registered session key, you must still fill in all fields in the request, at least with arbitrary values. This is required by the request itself, however, the values will be ignored as the system uses the session key configuration stored during initial registration. This behavior will be improved in future versions. - -#### List Active Session Keys - -Use the `get_session_keys` method to retrieve all active (non-expired) session keys for the authenticated user: - -**Request:** - -```json -{ - "req": [1, "get_session_keys", {}, 1619123456789], - "sig": ["0x9876fedcba..."] -} -``` - -**Response:** - -```json -{ - "res": [ - 1, - "get_session_keys", - { - "session_keys": [ - { - "id": 1, - "session_key": "0xabcdef1234567890...", - "application": "Chess Game", - "allowances": [ - { - "asset": "usdc", - "allowance": "100.0", - "used": "45.0" - }, - { - "asset": "eth", - "allowance": "0.5", - "used": "0.0" - } - ], - "scope": "app.create", - "expires_at": "2024-12-31T23:59:59Z", - "created_at": "2024-01-01T00:00:00Z" - } - ] - }, - 1619123456789 - ], - "sig": ["0xabcd1234..."] -} -``` - -**Response Fields:** - -- `id`: Unique identifier for the session key record -- `session_key`: The address of the session key -- `application`: Application name this session key is authorized for -- `allowances`: Array of allowances with usage tracking: - - `asset`: Symbol of the asset (e.g., "usdc", "eth") - - `allowance`: Maximum amount the session key can spend - - `used`: Amount already spent by this session key -- `scope`: Permission scope (omitted if empty) -- `expires_at`: When this session key expires (ISO 8601 format) -- `created_at`: When the session key was created (ISO 8601 format) - -#### Revoke a Session Key - -To immediately invalidate a session key, use the `revoke_session_key` method: - -**Request:** - -```json -{ - "req": [ - 1, - "revoke_session_key", - { - "session_key": "0xabcdef1234567890..." - }, - 1619123456789 - ], - "sig": ["0x9876fedcba..."] -} -``` - -**Response:** - -```json -{ - "res": [ - 1, - "revoke_session_key", - { - "session_key": "0xabcdef1234567890..." - }, - 1619123456789 - ], - "sig": ["0xabcd1234..."] -} -``` - -**Permission Rules:** - -- A wallet can revoke any of its session keys -- A session key can revoke itself -- A session key with `application: "clearnode"` can revoke other session keys belonging to the same wallet -- A non-"clearnode" session key cannot revoke other session keys (only itself) - -**Important Notes:** - -- Revocation is **immediate and cannot be undone** -- After revocation, any operations attempted with the revoked session key will fail with a validation error -- The revoked session key will no longer appear in the `get_session_keys` response -- Revocation is useful for security purposes when a session key may have been compromised - -**Error Cases:** - -- Session key does not exist, belongs to another wallet, or is expired: `"operation denied: provided address is not an active session key of this user"` -- Non-"clearnode" session key attempting to revoke another session key: `"operation denied: insufficient permissions for the active session key"` - -### Nitrolite SDK - -The Nitrolite SDK provides a higher-level abstraction for managing session keys. For detailed information on using session keys with the Nitrolite SDK, please refer to the SDK documentation. \ No newline at end of file diff --git a/docs/learn/core-concepts/app-sessions.md b/docs/learn/core-concepts/app-sessions.mdx similarity index 84% rename from docs/learn/core-concepts/app-sessions.md rename to docs/learn/core-concepts/app-sessions.mdx index 18c31d9..f6b9694 100644 --- a/docs/learn/core-concepts/app-sessions.md +++ b/docs/learn/core-concepts/app-sessions.mdx @@ -5,9 +5,12 @@ description: Multi-party application channels with custom governance and state m keywords: [app sessions, multi-party, governance, quorum, NitroRPC] --- +import Tooltip from '@site/src/components/Tooltip'; +import { tooltipDefinitions } from '@site/src/constants/tooltipDefinitions'; + # App Sessions -App sessions are off-chain channels built on top of the unified balance that enable multi-party applications with custom governance rules. +App sessions are off-chain channels built on top of the unified balance that enable multi-party applications with custom governance rules. **Goal**: Understand how app sessions work for building multi-party applications. @@ -15,9 +18,9 @@ App sessions are off-chain channels built on top of the unified balance that ena ## What is an App Session? -An **app session** is a temporary shared account where multiple participants can: +An **app session** is a temporary shared account where multiple participants can: -- Lock funds from their unified balance +- Lock funds from their unified balance - Execute application-specific logic (games, escrow, predictions) - Redistribute funds based on outcomes - Close and release funds back to unified balances @@ -172,6 +175,6 @@ Always use `NitroRPC/0.4` for new applications. Protocol version is set at creat For complete method specifications and implementation details: -- **[App Session Methods](/docs/protocol/off-chain/app-sessions)** — Complete method specifications -- **[Communication Flows](/docs/protocol/communication-flows#app-session-lifecycle-flow)** — Sequence diagrams -- **[Implementation Checklist](/docs/protocol/implementation-checklist#state-management)** — Building app session support +- **[App Session Methods](/docs/protocol/off-chain/app-sessions.mdx)** — Complete method specifications +- **[Communication Flows](/docs/protocol/communication-flows.mdx#app-session-lifecycle-flow)** — Sequence diagrams +- **[Implementation Checklist](/docs/protocol/implementation-checklist.mdx#state-management)** — Building app session support diff --git a/docs/learn/core-concepts/challenge-response.md b/docs/learn/core-concepts/challenge-response.mdx similarity index 84% rename from docs/learn/core-concepts/challenge-response.md rename to docs/learn/core-concepts/challenge-response.mdx index 68dcbf1..44000bf 100644 --- a/docs/learn/core-concepts/challenge-response.md +++ b/docs/learn/core-concepts/challenge-response.mdx @@ -5,6 +5,9 @@ description: How Yellow Network handles disputes and ensures fund safety keywords: [challenge, dispute, security, settlement, fund recovery] --- +import Tooltip from '@site/src/components/Tooltip'; +import { tooltipDefinitions } from '@site/src/constants/tooltipDefinitions'; + # Challenge-Response & Disputes In this guide, you will learn how Yellow Network resolves disputes and ensures your funds are always recoverable. @@ -17,9 +20,9 @@ In this guide, you will learn how Yellow Network resolves disputes and ensures y In any off-chain system, a critical question arises: **What if someone tries to cheat?** -State channels solve this with a challenge-response mechanism: +State channels solve this with a challenge-response mechanism: -1. Anyone can submit a state to the blockchain +1. Anyone can submit a state to the blockchain 2. Counterparties have time to respond with a newer state 3. The newest valid state always wins 4. Funds are distributed according to that state @@ -43,7 +46,7 @@ State channels are **trustless** because: ### Scenario: Clearnode Becomes Unresponsive -You have a channel with 100 USDC. The Clearnode stops responding. +You have a channel with 100 USDC. The Clearnode stops responding. **Your options:** @@ -147,6 +150,6 @@ You can **always** recover your funds according to the latest mutually signed st For technical implementation details: -- **[Channel Lifecycle](/docs/protocol/on-chain/channel-lifecycle)** — Full state machine -- **[Security Considerations](/docs/protocol/on-chain/security)** — Threat model and best practices -- **[Communication Flows](/docs/protocol/communication-flows#challenge-response-closure-flow)** — Sequence diagrams +- **[Channel Lifecycle](/docs/protocol/on-chain/channel-lifecycle.mdx)** — Full state machine +- **[Security Considerations](/docs/protocol/on-chain/security.mdx)** — Threat model and best practices +- **[Communication Flows](/docs/protocol/communication-flows.mdx#challenge-response-closure-flow)** — Sequence diagrams diff --git a/docs/learn/core-concepts/message-envelope.md b/docs/learn/core-concepts/message-envelope.mdx similarity index 90% rename from docs/learn/core-concepts/message-envelope.md rename to docs/learn/core-concepts/message-envelope.mdx index 5a1c5e2..c973ce3 100644 --- a/docs/learn/core-concepts/message-envelope.md +++ b/docs/learn/core-concepts/message-envelope.mdx @@ -5,6 +5,9 @@ description: Overview of the Nitro RPC message format and communication protocol keywords: [Nitro RPC, message format, WebSocket, protocol, signatures] --- +import Tooltip from '@site/src/components/Tooltip'; +import { tooltipDefinitions } from '@site/src/constants/tooltipDefinitions'; + # Message Envelope (RPC Protocol) In this guide, you will learn the essentials of how messages are structured and transmitted in Yellow Network. @@ -135,6 +138,6 @@ Always use NitroRPC/0.4 for new implementations. For complete technical specifications: -- **[Message Format](/docs/protocol/off-chain/message-format)** — Full format specification -- **[Off-Chain Overview](/docs/protocol/off-chain/overview)** — Protocol architecture -- **[Implementation Checklist](/docs/protocol/implementation-checklist#off-chain-rpc)** — Building RPC support +- **[Message Format](/docs/protocol/off-chain/message-format.mdx)** — Full format specification +- **[Off-Chain Overview](/docs/protocol/off-chain/overview.mdx)** — Protocol architecture +- **[Implementation Checklist](/docs/protocol/implementation-checklist.mdx#off-chain-rpc)** — Building RPC support diff --git a/docs/learn/core-concepts/session-keys.md b/docs/learn/core-concepts/session-keys.mdx similarity index 88% rename from docs/learn/core-concepts/session-keys.md rename to docs/learn/core-concepts/session-keys.mdx index 18b176a..c52b4cd 100644 --- a/docs/learn/core-concepts/session-keys.md +++ b/docs/learn/core-concepts/session-keys.mdx @@ -5,9 +5,12 @@ description: Delegated keys for secure, gasless application interactions keywords: [session keys, authentication, signatures, allowances, security] --- +import Tooltip from '@site/src/components/Tooltip'; +import { tooltipDefinitions } from '@site/src/constants/tooltipDefinitions'; + # Session Keys -Session keys are delegated keys that enable applications to perform operations on behalf of a user's wallet with specified spending limits, permissions, and expiration times. They provide a secure way to grant limited access to applications without exposing the main wallet's private key. +Session keys are delegated keys that enable applications to perform operations on behalf of a user's wallet with specified spending limits, permissions, and expiration times. They provide a secure way to grant limited access to applications without exposing the main wallet's private key. :::important Session keys are **no longer used as on-chain channel participant addresses** for new channels created after the v0.5.0 release. For all new channels, the wallet address is used directly as the participant address. However, session keys still function correctly for channels that were created before v0.5.0, ensuring backward compatibility. @@ -35,7 +38,7 @@ When authenticating with an already registered session key, you must still provi ### Applications -Each session key is associated with a specific **application name**, which identifies the application or service that will use the session key. The application name is also used to identify **app sessions** that are created using that session key. +Each session key is associated with a specific **application name**, which identifies the application or service that will use the session key. The application name is also used to identify **app sessions** that are created using that session key. This association serves several purposes: @@ -169,6 +172,6 @@ You can skip session keys entirely and sign every request with your main wallet. ## Next Steps -- **[Managing Session Keys](../advanced/managing-session-keys)** — Create, list, and revoke session keys with full API examples -- **[Authentication Flow](/docs/protocol/off-chain/authentication)** — Full 3-step authentication protocol -- **[Communication Flows](/docs/protocol/communication-flows#authentication-flow)** — Sequence diagrams for auth +- **[Managing Session Keys](../advanced/managing-session-keys.mdx)** — Create, list, and revoke session keys with full API examples +- **[Authentication Flow](/docs/protocol/off-chain/authentication.mdx)** — Full 3-step authentication protocol +- **[Communication Flows](/docs/protocol/communication-flows.mdx#authentication-flow)** — Sequence diagrams for auth diff --git a/docs/learn/core-concepts/state-channels-vs-l1-l2.md b/docs/learn/core-concepts/state-channels-vs-l1-l2.mdx similarity index 80% rename from docs/learn/core-concepts/state-channels-vs-l1-l2.md rename to docs/learn/core-concepts/state-channels-vs-l1-l2.mdx index 625710e..94ae9cc 100644 --- a/docs/learn/core-concepts/state-channels-vs-l1-l2.md +++ b/docs/learn/core-concepts/state-channels-vs-l1-l2.mdx @@ -5,6 +5,9 @@ description: Compare state channels with Layer 1 and Layer 2 scaling solutions keywords: [state channels, L1, L2, scaling, comparison, rollups, Nitrolite] --- +import Tooltip from '@site/src/components/Tooltip'; +import { tooltipDefinitions } from '@site/src/constants/tooltipDefinitions'; + # State Channels vs L1/L2 In this guide, you will learn how state channels compare to Layer 1 and Layer 2 solutions, and when each approach is the right choice. @@ -30,7 +33,7 @@ In this guide, you will learn how state channels compare to Layer 1 and Layer 2 State channels operate on a simple principle: 1. **Lock funds** in a smart contract (on-chain) -2. **Exchange signed states** directly between participants (off-chain) +2. **Exchange signed states** directly between participants (off-chain) 3. **Settle** when done or if there's a dispute (on-chain) The key insight: most interactions between parties don't need immediate on-chain settlement. @@ -66,7 +69,7 @@ Off-chain transactions are only visible to participants. Only opening and final ### Known Participants -Channels work between specific participants. Yellow Network addresses this through Clearnodes—off-chain service providers that coordinate channels and provide a unified balance across multiple users and chains. +Channels work between specific participants. Yellow Network addresses this through Clearnodes—off-chain service providers that coordinate channels and provide a unified balance across multiple users and chains. ### Liquidity Requirements @@ -133,6 +136,6 @@ State channels shine when you have identified participants who will interact fre For technical details on channel implementation: -- **[Architecture](/docs/protocol/architecture)** — System design and fund flows -- **[Channel Lifecycle](/docs/protocol/on-chain/channel-lifecycle)** — State machine and operations -- **[Data Structures](/docs/protocol/on-chain/data-structures)** — Channel and state formats +- **[Architecture](/docs/protocol/architecture.mdx)** — System design and fund flows +- **[Channel Lifecycle](/docs/protocol/on-chain/channel-lifecycle.mdx)** — State machine and operations +- **[Data Structures](/docs/protocol/on-chain/data-structures.mdx)** — Channel and state formats diff --git a/docs/learn/deprecated/_category_.json b/docs/learn/deprecated/_category_.json deleted file mode 100644 index 9cb1b34..0000000 --- a/docs/learn/deprecated/_category_.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "label": "Deprecated", - "position": 99, - "collapsible": true, - "collapsed": true, - "className": "deprecated-category" -} - - diff --git a/docs/learn/deprecated/advanced/_category_.json b/docs/learn/deprecated/advanced/_category_.json deleted file mode 100644 index 83cb82e..0000000 --- a/docs/learn/deprecated/advanced/_category_.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "label": "Advanced", - "position": 3, - "collapsible": false, - "collapsed": false -} \ No newline at end of file diff --git a/docs/learn/deprecated/advanced/architecture.md b/docs/learn/deprecated/advanced/architecture.md deleted file mode 100644 index ebb729c..0000000 --- a/docs/learn/deprecated/advanced/architecture.md +++ /dev/null @@ -1,293 +0,0 @@ ---- -sidebar_position: 2 -title: Architecture Deep Dive -description: Understanding state channel fundamentals and SDK architecture -keywords: [state channels, architecture, nitrolite, sdk, blockchain scaling] -displayed_sidebar: learnSidebar ---- - -# Architecture Deep Dive - -## State Channel Fundamentals - -State channels are the foundation of Yellow Apps. Understanding their mechanics is crucial for building robust applications: - -```mermaid -graph TD - A[Deposit Funds] --> B[Create Channel] - B --> C[Connect to ClearNode] - C --> D[Create App Session] - D --> E[Off-Chain Transactions] - E --> F[Close Session] - F --> G[Settle & Withdraw] -``` - -### How State Channels Work - -1. **Setup**: Lock funds in a smart contract between participants -2. **Operate**: Exchange signed state updates instantly off-chain -3. **Settle**: Submit final state to blockchain for fund distribution - -This enables applications to achieve: -- **Instant finality** - no waiting for block confirmations -- **Minimal gas costs** - pay only for setup and settlement -- **Unlimited throughput** - thousands of transactions per second - -### Core Data Structures - -```typescript title="types.ts" showLineNumbers -interface Channel { - participants: Address[]; // Channel participants - adjudicator: Address; // Contract that validates state transitions - challenge: bigint; // Dispute resolution period - nonce: bigint; // Unique channel identifier -} - -interface State { - intent: StateIntent; // Purpose of the state - version: bigint; // Incremental version number - data: Hex; // Application-specific data - allocations: Allocation[]; // Fund distribution - sigs: Hex[]; // Participant signatures -} - -enum StateIntent { - OPERATE = 0, // Normal operation - INITIALIZE = 1, // Channel funding - RESIZE = 2, // Allocation adjustment - FINALIZE = 3 // Channel closure -} -``` - -## SDK Architecture - -### NitroliteRPC - -The core communication protocol for real-time interaction with ClearNode infrastructure: - -```javascript title="nitro-client.js" showLineNumbers -import { createAppSessionMessage, parseRPCResponse } from '@erc7824/nitrolite'; - -// Connect to ClearNode -const ws = new WebSocket('wss://clearnet.yellow.com/ws'); - -// Create application session -const sessionMessage = await createAppSessionMessage(messageSigner, [{ - definition: appDefinition, - allocations: initialAllocations -}]); - -// Send to ClearNode -ws.send(sessionMessage); - -// Parse responses -ws.onmessage = (event) => { - const message = parseRPCResponse(event.data); - console.log('Received:', message); -}; -``` - -### Message Signing - -Secure message authentication using wallet signatures: - -```javascript title="message-signing.js" showLineNumbers -// Set up message signer with your wallet -const messageSigner = async (message) => { - return await window.ethereum.request({ - method: 'personal_sign', - params: [message, userAddress] - }); -}; - -// Use signer for session creation -const sessionMessage = await createAppSessionMessage(messageSigner, sessionData); -``` - -### ClearNode Infrastructure - -Network infrastructure providing: -- **Message routing**: Secure communication between participants -- **Session management**: Application session lifecycle -- **State coordination**: Off-chain state synchronization -- **Network resilience**: Redundancy and failover support - -## Application Session Management - -### Session Lifecycle - -```javascript title="SessionManager.js" showLineNumbers -class SessionManager { - constructor() { - this.activeSessions = new Map(); - this.ws = null; - this.messageSigner = null; - } - - async createSession(participants, protocol, allocations) { - const appDefinition = { - protocol, - participants, - weights: participants.map(() => 100 / participants.length), - quorum: 51, // Majority consensus - challenge: 0, - nonce: Date.now() - }; - - const sessionMessage = await createAppSessionMessage( - this.messageSigner, - [{ definition: appDefinition, allocations }] - ); - - // Send session creation request to ClearNode - this.ws.send(sessionMessage); - - return this.waitForSessionConfirmation(); - } - - async sendSessionMessage(sessionId, messageType, data) { - const message = { - sessionId, - type: messageType, - data, - timestamp: Date.now() - }; - - // Sign message - const signature = await this.messageSigner(JSON.stringify(message)); - - this.ws.send(JSON.stringify({ - ...message, - signature - })); - } - - handleSessionMessage(message) { - const parsedMessage = parseRPCResponse(message); - const { sessionId, type, data } = parsedMessage; - - switch (type) { - case 'state_update': - this.handleStateUpdate(sessionId, data); - break; - case 'participant_joined': - this.handleParticipantJoined(sessionId, data); - break; - case 'session_closed': - this.handleSessionClosed(sessionId, data); - break; - } - } -} -``` - -## State Management Patterns - -### Client-Side State Tracking - -```javascript title="StateTracker.js" showLineNumbers -class StateTracker { - constructor() { - this.channelStates = new Map(); - this.stateHistory = new Map(); - } - - updateChannelState(channelId, newState) { - // Validate state progression - const currentState = this.channelStates.get(channelId); - if (currentState && newState.version <= currentState.version) { - throw new Error('Invalid state version'); - } - - // Store state - this.channelStates.set(channelId, newState); - - // Maintain history for dispute resolution - if (!this.stateHistory.has(channelId)) { - this.stateHistory.set(channelId, []); - } - this.stateHistory.get(channelId).push(newState); - - // Emit event for UI updates - this.emit('stateUpdated', { channelId, state: newState }); - } - - getStateHistory(channelId) { - return this.stateHistory.get(channelId) || []; - } - - getLatestState(channelId) { - return this.channelStates.get(channelId); - } -} -``` - -### Reactive Updates - -```javascript title="ReactiveChannelManager.js" showLineNumbers -class ReactiveChannelManager { - constructor() { - this.stateSubjects = new Map(); - } - - getChannelObservable(channelId) { - if (!this.stateSubjects.has(channelId)) { - this.stateSubjects.set(channelId, new BehaviorSubject(null)); - } - return this.stateSubjects.get(channelId); - } - - updateChannelState(channelId, newState) { - const subject = this.getChannelObservable(channelId); - subject.next(newState); - } - - subscribeToChannel(channelId, callback) { - return this.getChannelObservable(channelId).subscribe(callback); - } -} -``` - -## Integration Patterns - -### Event-Driven Architecture - -```javascript title="EventDrivenApp.js" showLineNumbers -class EventDrivenApp extends EventEmitter { - constructor(config) { - super(); - this.client = new NitroliteClient(config); - this.setupEventHandlers(); - } - - setupEventHandlers() { - this.on('channel:created', this.onChannelCreated.bind(this)); - this.on('message:received', this.onMessageReceived.bind(this)); - this.on('session:closed', this.onSessionClosed.bind(this)); - } - - async onChannelCreated(channelId) { - // Automatically connect to ClearNode - await this.connectToClearNode(channelId); - - // Set up session - await this.createApplicationSession(channelId); - - this.emit('app:ready', channelId); - } - - onMessageReceived(channelId, message) { - // Route message based on type - switch (message.type) { - case 'payment': - this.handlePayment(channelId, message); - break; - case 'game_move': - this.handleGameMove(channelId, message); - break; - } - } -} -``` - -Understanding these SDK patterns is essential for building robust, scalable Yellow Apps focused on application development rather than protocol implementation. \ No newline at end of file diff --git a/docs/learn/deprecated/advanced/deployment.md b/docs/learn/deprecated/advanced/deployment.md deleted file mode 100644 index eb43ecc..0000000 --- a/docs/learn/deprecated/advanced/deployment.md +++ /dev/null @@ -1,757 +0,0 @@ ---- -sidebar_position: 5 -title: Production Deployment -description: Deploy Yellow Apps to production with confidence - configuration, optimization, and best practices -keywords: [production, deployment, configuration, optimization, mainnet, scaling] -displayed_sidebar: learnSidebar ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -# Production Deployment - -Deploy your Yellow App to production with confidence using battle-tested configurations and optimization strategies. - -## Environment Configuration - - - - -```javascript title="production-config.js" showLineNumbers -// Production configuration for Polygon mainnet -const productionConfig = { - chainId: 137, - addresses: { - custody: '0x...', // Production custody contract - adjudicator: '0x...', // Your deployed adjudicator - tokenAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174' // USDC on Polygon - }, - clearNodeUrl: 'wss://clearnet.yellow.com/ws', - challengeDuration: 7200n, // 2 hours for mainnet - reconnectConfig: { - maxAttempts: 10, - backoffMultiplier: 1.5, - initialDelay: 1000 - } -}; -``` - - - - -```javascript title="testnet-config.js" showLineNumbers -// Testnet configuration for development -const testnetConfig = { - chainId: 80001, // Mumbai testnet - addresses: { - custody: '0x...', // Testnet custody contract - adjudicator: '0x...', // Your test adjudicator - tokenAddress: '0x...' // Test USDC - }, - clearNodeUrl: 'wss://testnet.clearnet.yellow.com/ws', - challengeDuration: 100n, // Shorter for testing - reconnectConfig: { - maxAttempts: 3, - backoffMultiplier: 2, - initialDelay: 500 - } -}; -``` - - - - -## Error Handling & Recovery - -### Robust Initialization - -```javascript title="RobustYellowApp.js" showLineNumbers -class RobustYellowApp { - constructor(config) { - this.client = new NitroliteClient(config); - this.reconnectAttempts = 0; - this.maxReconnectAttempts = config.reconnectConfig.maxAttempts; - this.backoffMultiplier = config.reconnectConfig.backoffMultiplier; - } - - async initializeWithRetry() { - try { - await this.client.deposit(this.config.initialDeposit); - const channel = await this.client.createChannel(this.config.channelParams); - await this.connectToClearNode(); - return channel; - } catch (error) { - return this.handleInitializationError(error); - } - } - - async handleInitializationError(error) { - switch (error.code) { - case 'INSUFFICIENT_FUNDS': - throw new UserError('Please add more funds to your wallet'); - - case 'NETWORK_ERROR': - if (this.reconnectAttempts < this.maxReconnectAttempts) { - const delay = this.config.reconnectConfig.initialDelay * - Math.pow(this.backoffMultiplier, this.reconnectAttempts); - this.reconnectAttempts++; - await this.delay(delay); - return this.initializeWithRetry(); - } - throw new NetworkError('Unable to connect after maximum attempts'); - - case 'CONTRACT_ERROR': - throw new ContractError('Smart contract interaction failed: ' + error.message); - - default: - throw error; - } - } - - async connectToClearNode() { - return new Promise((resolve, reject) => { - const ws = new WebSocket(this.config.clearNodeUrl); - - const connectionTimeout = setTimeout(() => { - reject(new Error('ClearNode connection timeout')); - }, 10000); - - ws.onopen = () => { - clearTimeout(connectionTimeout); - this.setupHeartbeat(ws); - this.setupReconnectLogic(ws); - resolve(ws); - }; - - ws.onerror = (error) => { - clearTimeout(connectionTimeout); - reject(error); - }; - }); - } - - setupHeartbeat(ws) { - const heartbeatInterval = setInterval(() => { - if (ws.readyState === WebSocket.OPEN) { - ws.send(JSON.stringify({ type: 'ping', timestamp: Date.now() })); - } else { - clearInterval(heartbeatInterval); - } - }, 30000); - - // Clear interval when WebSocket closes - ws.addEventListener('close', () => { - clearInterval(heartbeatInterval); - }); - } - - setupReconnectLogic(ws) { - ws.addEventListener('close', async (event) => { - if (event.code !== 1000) { // Not a normal closure - console.log('Connection lost, attempting to reconnect...'); - await this.delay(5000); - await this.connectToClearNode(); - } - }); - } - - delay(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } -} -``` - -## Performance Optimization - -### Batch Operations - -```javascript title="OptimizedYellowApp.js" showLineNumbers -class OptimizedYellowApp { - async batchDepositsAndChannels(operations) { - // Prepare all transactions in parallel - const preparationPromises = operations.map(async (op) => ({ - deposit: await this.client.prepareDeposit(op.amount), - channel: await this.client.prepareCreateChannel(op.channelParams) - })); - - const prepared = await Promise.all(preparationPromises); - - // Execute in optimized batches - const batchSize = 5; // Adjust based on gas limits - const results = []; - - for (let i = 0; i < prepared.length; i += batchSize) { - const batch = prepared.slice(i, i + batchSize); - - const batchResults = await Promise.all( - batch.map(async ({ deposit, channel }) => { - const depositTx = await this.client.executeTransaction(deposit); - const channelTx = await this.client.executeTransaction(channel); - return { deposit: depositTx, channel: channelTx }; - }) - ); - - results.push(...batchResults); - } - - return results; - } - - async optimizeGasUsage() { - // Estimate gas for common operations - const gasEstimates = await Promise.all([ - this.client.estimateDeposit(1000000n), - this.client.estimateCreateChannel(this.defaultChannelParams), - this.client.estimateCloseChannel(this.defaultCloseParams) - ]); - - // Adjust gas limits based on network conditions - const gasMultiplier = await this.getNetworkCongestionMultiplier(); - - return { - deposit: gasEstimates[0] * gasMultiplier, - createChannel: gasEstimates[1] * gasMultiplier, - closeChannel: gasEstimates[2] * gasMultiplier - }; - } -} -``` - -### Memory-Efficient State Storage - -```javascript title="CompactStateStorage.js" showLineNumbers -class CompactStateStorage { - constructor() { - this.stateHashes = new Map(); // Store only hashes - this.criticalStates = new Map(); // Store full critical states - this.compressionLevel = 9; // High compression for storage - } - - storeState(channelId, state) { - const stateHash = keccak256(JSON.stringify(state)); - - // Always store hash for validation - this.stateHashes.set(`${channelId}-${state.version}`, stateHash); - - // Store full state only for checkpoints and final states - if (this.isCriticalState(state)) { - const compressed = this.compressState(state); - this.criticalStates.set(`${channelId}-${state.version}`, compressed); - } - } - - isCriticalState(state) { - return state.intent === StateIntent.INITIALIZE || - state.intent === StateIntent.FINALIZE || - state.version % 100 === 0; // Every 100th state - } - - compressState(state) { - // Implement compression logic for storage efficiency - return JSON.stringify(state); // Placeholder - } -} -``` - -## Infrastructure Setup - -### Load Balancing - -```javascript title="LoadBalancedConnection.js" showLineNumbers -class LoadBalancedConnection { - constructor(clearNodeUrls) { - this.clearNodeUrls = clearNodeUrls; - this.connectionPool = new Map(); - this.currentIndex = 0; - } - - async getConnection() { - const url = this.getNextUrl(); - - if (!this.connectionPool.has(url)) { - const ws = await this.createConnection(url); - this.connectionPool.set(url, ws); - } - - return this.connectionPool.get(url); - } - - getNextUrl() { - const url = this.clearNodeUrls[this.currentIndex]; - this.currentIndex = (this.currentIndex + 1) % this.clearNodeUrls.length; - return url; - } - - async healthCheck() { - const healthPromises = this.clearNodeUrls.map(async (url) => { - try { - const ws = await this.createConnection(url); - ws.close(); - return { url, healthy: true, latency: Date.now() }; - } catch (error) { - return { url, healthy: false, error: error.message }; - } - }); - - return Promise.all(healthPromises); - } -} -``` - -### Caching Strategy - -```javascript title="IntelligentCache.js" showLineNumbers -class IntelligentCache { - constructor() { - this.stateCache = new LRUCache(1000); // Most recent states - this.channelCache = new LRUCache(100); // Channel info - this.accountCache = new LRUCache(50); // Account data - } - - async getAccountInfo(address, maxAge = 30000) { - const cacheKey = `account:${address}`; - const cached = this.accountCache.get(cacheKey); - - if (cached && Date.now() - cached.timestamp < maxAge) { - return cached.data; - } - - const fresh = await this.client.getAccountInfo(); - this.accountCache.set(cacheKey, { - data: fresh, - timestamp: Date.now() - }); - - return fresh; - } - - invalidateChannel(channelId) { - // Remove all related cache entries - this.channelCache.delete(`channel:${channelId}`); - this.stateCache.delete(`latest:${channelId}`); - } -} -``` - -## Deployment Pipeline - -### Automated Deployment - -```yaml title="deploy.yml" showLineNumbers -# .github/workflows/deploy.yml -name: Deploy Yellow App - -on: - push: - branches: [main] - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '18' - - - name: Install dependencies - run: npm ci - - - name: Run tests - run: npm test - - - name: Deploy contracts - run: | - npx hardhat deploy --network polygon - npx hardhat verify --network polygon - env: - PRIVATE_KEY: ${{ secrets.DEPLOYER_PRIVATE_KEY }} - POLYGONSCAN_API_KEY: ${{ secrets.POLYGONSCAN_API_KEY }} - - - name: Deploy frontend - run: | - npm run build - aws s3 sync ./build s3://${{ secrets.S3_BUCKET }} - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} -``` - -### Environment Management - -```javascript title="production.js" showLineNumbers -// config/production.js -export const productionConfig = { - contracts: { - custody: process.env.CUSTODY_CONTRACT_ADDRESS, - adjudicator: process.env.ADJUDICATOR_CONTRACT_ADDRESS, - tokenAddress: process.env.TOKEN_CONTRACT_ADDRESS - }, - network: { - chainId: parseInt(process.env.CHAIN_ID), - rpcUrl: process.env.RPC_URL, - clearNodeUrls: process.env.CLEARNODE_URLS.split(',') - }, - monitoring: { - sentryDsn: process.env.SENTRY_DSN, - logLevel: process.env.LOG_LEVEL || 'info' - } -}; -``` - -## Monitoring Setup - -### Health Checks - -```javascript title="ProductionHealthCheck.js" showLineNumbers -class ProductionHealthCheck { - constructor(client) { - this.client = client; - this.healthMetrics = { - lastSuccessfulDeposit: null, - lastSuccessfulChannel: null, - connectionUptime: 0, - errorRate: 0 - }; - } - - async runHealthCheck() { - const checks = [ - this.checkContractConnectivity(), - this.checkClearNodeConnectivity(), - this.checkAccountAccess(), - this.checkGasEstimation() - ]; - - const results = await Promise.allSettled(checks); - - return { - healthy: results.every(r => r.status === 'fulfilled'), - checks: results.map((r, i) => ({ - name: this.getCheckName(i), - status: r.status, - error: r.reason?.message - })), - timestamp: Date.now() - }; - } - - async checkContractConnectivity() { - const balance = await this.client.getTokenBalance(); - return balance !== null; - } - - async checkClearNodeConnectivity() { - return new Promise((resolve, reject) => { - const ws = new WebSocket(this.config.clearNodeUrl); - const timeout = setTimeout(() => reject(new Error('Timeout')), 5000); - - ws.onopen = () => { - clearTimeout(timeout); - ws.close(); - resolve(true); - }; - - ws.onerror = () => { - clearTimeout(timeout); - reject(new Error('Connection failed')); - }; - }); - } -} -``` - -### Logging and Alerting - -```javascript title="ProductionLogger.js" showLineNumbers -class ProductionLogger { - constructor(config) { - this.logger = winston.createLogger({ - level: config.logLevel, - format: winston.format.combine( - winston.format.timestamp(), - winston.format.errors({ stack: true }), - winston.format.json() - ), - transports: [ - new winston.transports.File({ filename: 'error.log', level: 'error' }), - new winston.transports.File({ filename: 'combined.log' }), - new winston.transports.Console({ - format: winston.format.simple() - }) - ] - }); - } - - logChannelEvent(event, channelId, data) { - this.logger.info('Channel event', { - event, - channelId, - data, - timestamp: Date.now() - }); - } - - logError(error, context) { - this.logger.error('Application error', { - error: error.message, - stack: error.stack, - context, - timestamp: Date.now() - }); - - // Send to alerting system - this.sendAlert('ERROR', error.message, context); - } - - async sendAlert(level, message, context) { - // Integration with alerting services (PagerDuty, Slack, etc.) - if (level === 'ERROR' || level === 'CRITICAL') { - await this.notifyOnCall(message, context); - } - } -} -``` - -## Scaling Strategies - -### Horizontal Scaling - -```javascript title="HorizontalScaler.js" showLineNumbers -class HorizontalScaler { - constructor() { - this.instances = new Map(); - this.loadBalancer = new LoadBalancer(); - } - - async scaleUp(requiredCapacity) { - const currentCapacity = this.getCurrentCapacity(); - - if (requiredCapacity > currentCapacity) { - const additionalInstances = Math.ceil( - (requiredCapacity - currentCapacity) / this.instanceCapacity - ); - - await this.deployInstances(additionalInstances); - } - } - - async deployInstances(count) { - const deploymentPromises = Array(count).fill().map(() => - this.deployInstance() - ); - - const newInstances = await Promise.all(deploymentPromises); - - newInstances.forEach(instance => { - this.instances.set(instance.id, instance); - this.loadBalancer.addInstance(instance); - }); - } - - async deployInstance() { - // Deploy new application instance - return { - id: generateInstanceId(), - client: new NitroliteClient(this.config), - capacity: this.instanceCapacity, - status: 'healthy' - }; - } -} -``` - -### Database Optimization - -```javascript title="OptimizedStateStorage.js" showLineNumbers -class OptimizedStateStorage { - constructor(dbConfig) { - this.db = new Database(dbConfig); - this.setupIndexes(); - } - - async setupIndexes() { - // Optimize queries for common patterns - await this.db.createIndex('states', ['channelId', 'version']); - await this.db.createIndex('states', ['channelId', 'intent']); - await this.db.createIndex('channels', ['participants']); - await this.db.createIndex('transactions', ['timestamp', 'status']); - } - - async storeStateOptimized(channelId, state) { - const compressed = await this.compressState(state); - - // Store with proper indexing - await this.db.transaction(async (tx) => { - await tx.states.insert({ - channelId, - version: state.version, - intent: state.intent, - data: compressed, - timestamp: Date.now() - }); - - // Update latest state cache - await tx.channels.update( - { id: channelId }, - { latestVersion: state.version, lastActivity: Date.now() } - ); - }); - } -} -``` - -## Security in Production - -### Key Management - -```javascript title="ProductionKeyManager.js" showLineNumbers -class ProductionKeyManager { - constructor() { - this.keyVault = new AzureKeyVault(); // or AWS KMS, HashiCorp Vault - this.localCache = new Map(); - } - - async getSigningKey(channelId) { - // Check local cache first - if (this.localCache.has(channelId)) { - return this.localCache.get(channelId); - } - - // Fetch from secure vault - const key = await this.keyVault.getSecret(`channel-${channelId}`); - - // Cache for limited time - this.localCache.set(channelId, key); - setTimeout(() => { - this.localCache.delete(channelId); - }, 300000); // 5 minutes - - return key; - } - - async rotateKeys(channelId) { - const newKey = await this.generateKey(); - await this.keyVault.setSecret(`channel-${channelId}`, newKey); - this.localCache.delete(channelId); // Clear cache - return newKey; - } -} -``` - -### Rate Limiting - -```javascript title="RateLimiter.js" showLineNumbers -class RateLimiter { - constructor() { - this.limits = new Map(); - this.windowSize = 60000; // 1 minute windows - } - - async checkLimit(identifier, limit) { - const now = Date.now(); - const windowStart = now - this.windowSize; - - if (!this.limits.has(identifier)) { - this.limits.set(identifier, []); - } - - const requests = this.limits.get(identifier); - - // Remove old requests - const recentRequests = requests.filter(time => time > windowStart); - this.limits.set(identifier, recentRequests); - - if (recentRequests.length >= limit) { - throw new Error('Rate limit exceeded'); - } - - // Add current request - recentRequests.push(now); - return true; - } -} -``` - -## Deployment Checklist - -### Pre-Production - -- [ ] **Contracts Audited**: Security audit completed by reputable firm -- [ ] **Gas Optimization**: All transactions optimized for cost -- [ ] **Error Handling**: Comprehensive error recovery implemented -- [ ] **State Validation**: All state transitions validated -- [ ] **Key Management**: Secure key storage and rotation -- [ ] **Monitoring**: Health checks and alerting configured -- [ ] **Testing**: Full integration test suite passing -- [ ] **Load Testing**: Performance validated under expected load -- [ ] **Documentation**: User guides and API docs complete - -### Production - -- [ ] **Mainnet Contracts**: Deployed and verified on block explorers -- [ ] **ClearNode Connection**: Production endpoints configured -- [ ] **Backup Systems**: Redundancy and failover implemented -- [ ] **User Support**: Documentation and support channels ready -- [ ] **Incident Response**: Monitoring and response procedures documented -- [ ] **Upgrade Path**: Contract upgrade strategy defined -- [ ] **Compliance**: Regulatory requirements addressed -- [ ] **Insurance**: Consider smart contract insurance -- [ ] **Legal Review**: Terms of service and liability reviewed - -### Post-Deployment - -- [ ] **Monitoring Active**: All systems being monitored 24/7 -- [ ] **Alerts Configured**: Team notified of critical issues -- [ ] **Backup Verified**: Disaster recovery tested -- [ ] **Performance Baseline**: Metrics baseline established -- [ ] **User Feedback**: Feedback collection system active -- [ ] **Update Process**: Smooth update and rollback procedures -- [ ] **Security Monitoring**: Anomaly detection active -- [ ] **Capacity Planning**: Growth projections and scaling plans - -## Disaster Recovery - -### Backup Strategies - -```javascript title="DisasterRecovery.js" showLineNumbers -class DisasterRecovery { - constructor() { - this.backupSchedule = new CronJob('0 */6 * * *', this.performBackup.bind(this)); - this.recoveryPlan = new RecoveryPlan(); - } - - async performBackup() { - // Backup critical state data - const criticalStates = await this.getCriticalStates(); - await this.uploadToSecureStorage(criticalStates); - - // Backup channel configurations - const channelConfigs = await this.getChannelConfigurations(); - await this.uploadToSecureStorage(channelConfigs); - - // Verify backup integrity - await this.verifyBackupIntegrity(); - } - - async emergencyRecovery(backupTimestamp) { - // 1. Stop all active operations - await this.gracefulShutdown(); - - // 2. Restore from backup - const backup = await this.downloadBackup(backupTimestamp); - await this.restoreState(backup); - - // 3. Validate restored state - await this.validateRestoredState(); - - // 4. Resume operations - await this.resumeOperations(); - } -} -``` - -Following these production deployment practices ensures your Yellow App can handle real-world usage with confidence, security, and reliability. \ No newline at end of file diff --git a/docs/learn/deprecated/advanced/index.md b/docs/learn/deprecated/advanced/index.md deleted file mode 100644 index f32bcaa..0000000 --- a/docs/learn/deprecated/advanced/index.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -sidebar_position: 1 -title: Advanced Guide -description: Advanced topics for experienced developers -displayed_sidebar: learnSidebar ---- - -# Advanced Guide - -This section covers advanced topics for working with the Yellow SDK. These are intended for developers who need deeper control over the state channel operations or want to integrate with specialized systems. - -**Consider using the advanced features when:** - -- Building custom workflows that require more control than the high-level NitroliteClient API provides -- Integrating with smart contract wallets or other account abstraction systems -- Implementing specialized monitoring or management systems for state channels -- Developing cross-chain applications that require custom handling of state channel operations -- Optimizing gas usage through transaction batching and other techniques - -## Advanced Topics - -**[Architecture](./architecture)** - Deep dive into the Yellow Network architecture, understanding the core components, data flow, and system design principles that power decentralized clearing. - -**[Multi-Party State Channels](./multi-party)** - Learn about implementing complex multi-party state channel operations, handling multiple participants, and managing advanced channel lifecycle events. - -**[Deployment Strategies](./deployment)** - Master production deployment patterns, scaling considerations, monitoring setup, and operational best practices for Yellow Apps. - -**[Security Considerations](./security)** - Understand security best practices, threat models, secure key management, and how to build robust, attack-resistant applications. \ No newline at end of file diff --git a/docs/learn/deprecated/advanced/multi-party.md b/docs/learn/deprecated/advanced/multi-party.md deleted file mode 100644 index b52f1bf..0000000 --- a/docs/learn/deprecated/advanced/multi-party.md +++ /dev/null @@ -1,719 +0,0 @@ ---- -sidebar_position: 3 -title: Multi-Party Applications -description: Complex scenarios with multiple participants and application patterns -keywords: [multi-party, applications, consensus, state channels, patterns] -displayed_sidebar: learnSidebar ---- - -# Multi-Party Applications - -Build sophisticated applications with multiple participants using Yellow SDK's flexible channel architecture. - -## Three-Party Applications - -### Escrow Pattern - -Perfect for marketplace transactions with buyer, seller, and mediator: - -### Escrow Application Session - -```javascript title="createEscrowSession.js" showLineNumbers -import { createAppSessionMessage } from '@erc7824/nitrolite'; - -async function createEscrowSession(buyer, seller, mediator, amount) { - const appDefinition = { - protocol: 'escrow-v1', - participants: [buyer, seller, mediator], - weights: [33, 33, 34], // Equal voting with mediator tiebreaker - quorum: 67, // Requires 2 of 3 consensus - challenge: 0, - nonce: Date.now() - }; - - const allocations = [ - { participant: buyer, asset: 'usdc', amount: amount.toString() }, - { participant: seller, asset: 'usdc', amount: '0' }, - { participant: mediator, asset: 'usdc', amount: '0' } - ]; - - return createAppSessionMessage(messageSigner, [{ - definition: appDefinition, - allocations - }]); -} -``` - -## Tournament Structure - -Multi-player competitive applications with prize distribution: - -```javascript title="createTournament.js" showLineNumbers -async function createTournament(players, entryFee, messageSigner) { - // Create application session for tournament logic - const appDefinition = { - protocol: 'tournament-v1', - participants: [...players, houseAddress], - weights: [...players.map(() => 0), 100], // House controls tournament - quorum: 100, - challenge: 0, - nonce: Date.now() - }; - - const allocations = players.map(player => ({ - participant: player, - asset: 'usdc', - amount: entryFee.toString() - })).concat([{ - participant: houseAddress, - asset: 'usdc', - amount: '0' - }]); - - const tournamentMessage = await createAppSessionMessage(messageSigner, [{ - definition: appDefinition, - allocations - }]); - - // Send to ClearNode - ws.send(tournamentMessage); - console.log('🎮 Tournament session created!'); - - return appDefinition; -} -``` - -## Consensus Mechanisms - -### Weighted Voting - -Different participants can have different voting power: - -```javascript title="governanceSession.js" showLineNumbers -const governanceSession = { - protocol: 'governance-v1', - participants: [admin, moderator1, moderator2, user1, user2], - weights: [40, 20, 20, 10, 10], // Admin has 40% vote - quorum: 60, // Requires 60% consensus - challenge: 0, - nonce: Date.now() -}; -``` - -### Multi-Signature Requirements - -```javascript title="multiSigSession.js" showLineNumbers -const multiSigSession = { - protocol: 'multisig-v1', - participants: [signer1, signer2, signer3, beneficiary], - weights: [33, 33, 34, 0], // 3 signers, 1 beneficiary - quorum: 67, // Requires 2 of 3 signatures - challenge: 0, - nonce: Date.now() -}; -``` - -## Application Patterns - -### Payment Routing - -Route payments through multiple sessions for optimal liquidity: - -```javascript title="PaymentRouter.js" showLineNumbers -class PaymentRouter { - constructor() { - this.sessions = new Map(); // route -> sessionId - this.liquidity = new Map(); // sessionId -> available amounts - this.ws = null; - this.messageSigner = null; - } - - async routePayment(amount, recipient) { - // Find optimal path considering liquidity and fees - const path = await this.findOptimalPath(this.userAddress, recipient, amount); - - if (path.length === 1) { - // Direct session exists - return this.sendDirectPayment(path[0], amount, recipient); - } else { - // Multi-hop payment required - return this.executeMultiHopPayment(path, amount, recipient); - } - } - - async sendDirectPayment(sessionId, amount, recipient) { - const paymentMessage = { - sessionId, - type: 'payment', - amount: amount.toString(), - recipient, - timestamp: Date.now() - }; - - const signature = await this.messageSigner(JSON.stringify(paymentMessage)); - - this.ws.send(JSON.stringify({ - ...paymentMessage, - signature - })); - - return paymentMessage; - } -} -``` - -### State Synchronization - -Keep multiple channels synchronized for complex applications: - -```javascript title="ChannelSynchronizer.js" showLineNumbers -class ChannelSynchronizer { - constructor() { - this.channels = new Map(); - this.syncGroups = new Map(); - } - - addToSyncGroup(groupId, channelId) { - if (!this.syncGroups.has(groupId)) { - this.syncGroups.set(groupId, new Set()); - } - this.syncGroups.get(groupId).add(channelId); - } - - async syncStateUpdate(groupId, stateUpdate) { - const channels = this.syncGroups.get(groupId); - - // Apply update to all channels in sync group - const updatePromises = Array.from(channels).map(channelId => - this.applyStateUpdate(channelId, stateUpdate) - ); - - const results = await Promise.allSettled(updatePromises); - - // Handle any failures - const failures = results.filter(r => r.status === 'rejected'); - if (failures.length > 0) { - await this.handleSyncFailures(groupId, failures); - } - - return results; - } -} -``` - -## ClearNode Integration - -### Multi-Session Management - -```javascript title="MultiSessionManager.js" showLineNumbers -class MultiSessionManager { - constructor() { - this.connections = new Map(); // sessionId -> WebSocket - this.sessions = new Map(); // sessionId -> sessionData - this.messageSigner = null; - } - - async connectToSession(sessionConfig) { - const ws = new WebSocket('wss://clearnet.yellow.com/ws'); - - return new Promise((resolve, reject) => { - ws.onopen = async () => { - // Create application session - const sessionMessage = await createAppSessionMessage( - this.messageSigner, - [sessionConfig] - ); - - ws.send(sessionMessage); - - const sessionId = this.generateSessionId(); - this.connections.set(sessionId, ws); - this.sessions.set(sessionId, sessionConfig); - - resolve({ ws, sessionId }); - }; - - ws.onerror = reject; - - ws.onmessage = (event) => { - this.handleSessionMessage(sessionId, parseRPCResponse(event.data)); - }; - }); - } - - async broadcastToAllSessions(message) { - const broadcasts = Array.from(this.connections.entries()).map(([sessionId, ws]) => { - if (ws.readyState === WebSocket.OPEN) { - const signature = await this.messageSigner(JSON.stringify(message)); - return ws.send(JSON.stringify({ ...message, signature })); - } - }); - - return Promise.allSettled(broadcasts); - } - - handleSessionMessage(sessionId, message) { - // Route messages based on session and message type - switch (message.type) { - case 'session_created': - this.handleSessionCreated(sessionId, message.data); - break; - case 'participant_message': - this.handleParticipantMessage(sessionId, message.data); - break; - case 'error': - this.handleSessionError(sessionId, message.error); - break; - } - } -} -``` - -### Session Management - -```javascript title="SessionManager.js" showLineNumbers -class SessionManager { - constructor() { - this.activeSessions = new Map(); - this.sessionParticipants = new Map(); - } - - async createMultiPartySession(participants, sessionConfig) { - const appDefinition = { - protocol: sessionConfig.protocol, - participants, - weights: sessionConfig.weights || participants.map(() => 100 / participants.length), - quorum: sessionConfig.quorum || 51, - challenge: 0, - nonce: Date.now() - }; - - const allocations = participants.map((participant, index) => ({ - participant, - asset: sessionConfig.asset || 'usdc', - amount: sessionConfig.initialAmounts?.[index]?.toString() || '0' - })); - - const sessionMessage = await createAppSessionMessage( - this.messageSigner, - [{ definition: appDefinition, allocations }] - ); - - // Send to all participants' connections - await this.broadcastSessionCreation(participants, sessionMessage); - - return this.waitForSessionConfirmation(); - } - - async coordinateStateUpdate(sessionId, updateData) { - const session = this.activeSessions.get(sessionId); - const participants = this.sessionParticipants.get(sessionId); - - // Create coordinated update message - const updateMessage = { - type: 'coordinate_update', - sessionId, - data: updateData, - requiredSignatures: this.calculateRequiredSignatures(session), - timestamp: Date.now() - }; - - // Send to all participants - await this.broadcastToParticipants(participants, updateMessage); - - // Wait for consensus - return this.waitForConsensus(sessionId, updateMessage.timestamp); - } -} -``` - -## Advanced Patterns - -### Channel Hierarchies - -Create parent-child relationships between channels: - -```javascript title="HierarchicalChannels.js" showLineNumbers -class HierarchicalChannels { - constructor(client) { - this.client = client; - this.parentChannels = new Map(); - this.childChannels = new Map(); - } - - async createParentChannel(participants, totalCapacity) { - const parentChannel = await this.client.createChannel({ - participants: [...participants, this.coordinatorAddress], - initialAllocationAmounts: [...totalCapacity, 0n], - stateData: '0x' - }); - - this.parentChannels.set(parentChannel.channelId, { - participants, - totalCapacity, - childChannels: new Set() - }); - - return parentChannel; - } - - async createChildChannel(parentChannelId, subset, allocation) { - const parent = this.parentChannels.get(parentChannelId); - - // Validate subset is from parent participants - if (!subset.every(addr => parent.participants.includes(addr))) { - throw new Error('Child participants must be subset of parent'); - } - - const childChannel = await this.client.createChannel({ - participants: subset, - initialAllocationAmounts: allocation, - stateData: this.encodeParentReference(parentChannelId) - }); - - // Link to parent - parent.childChannels.add(childChannel.channelId); - this.childChannels.set(childChannel.channelId, parentChannelId); - - return childChannel; - } -} -``` - -### Cross-Channel Coordination - -Coordinate state updates across multiple related channels: - -```javascript title="CrossChannelCoordinator.js" showLineNumbers -class CrossChannelCoordinator { - constructor() { - this.channelGroups = new Map(); - this.pendingUpdates = new Map(); - } - - async coordinateAcrossChannels(groupId, operation) { - const channels = this.channelGroups.get(groupId); - - // Prepare updates for all channels - const updatePromises = channels.map(channelId => - this.prepareChannelUpdate(channelId, operation) - ); - - const preparedUpdates = await Promise.all(updatePromises); - - // Execute all updates atomically - try { - const results = await this.executeAtomicUpdates(preparedUpdates); - return results; - } catch (error) { - // Rollback all updates on failure - await this.rollbackUpdates(preparedUpdates); - throw error; - } - } - - async executeAtomicUpdates(updates) { - // Use two-phase commit protocol - - // Phase 1: Prepare all updates - const preparePromises = updates.map(update => - this.prepareUpdate(update) - ); - - const prepared = await Promise.all(preparePromises); - - // Phase 2: Commit all updates - const commitPromises = prepared.map(prep => - this.commitUpdate(prep) - ); - - return Promise.all(commitPromises); - } -} -``` - -## Real-World Applications - -### Gaming Lobby System - -```javascript title="GamingLobby.js" showLineNumbers -class GamingLobby { - constructor() { - this.gameRooms = new Map(); - this.playerQueues = new Map(); - this.ws = null; - this.messageSigner = null; - } - - async createGameRoom(gameType, maxPlayers, buyIn) { - const roomId = this.generateRoomId(); - - this.gameRooms.set(roomId, { - gameType, - maxPlayers, - buyIn, - players: [], - status: 'WAITING' - }); - - // Broadcast room creation - const roomMessage = { - type: 'room_created', - roomId, - gameType, - maxPlayers, - buyIn, - timestamp: Date.now() - }; - - const signature = await this.messageSigner(JSON.stringify(roomMessage)); - this.ws.send(JSON.stringify({ ...roomMessage, signature })); - - return roomId; - } - - async joinGameRoom(roomId, playerAddress) { - const room = this.gameRooms.get(roomId); - - if (room.players.length >= room.maxPlayers) { - throw new Error('Room is full'); - } - - room.players.push(playerAddress); - - // Start game when room is full - if (room.players.length === room.maxPlayers) { - await this.startGame(roomId); - } - - return room; - } - - async startGame(roomId) { - const room = this.gameRooms.get(roomId); - - // Create game application session - const appDefinition = { - protocol: `${room.gameType}-v1`, - participants: [...room.players, this.serverAddress], - weights: [...room.players.map(() => 0), 100], // Server controls game - quorum: 100, - challenge: 0, - nonce: Date.now() - }; - - const allocations = room.players.map(player => ({ - participant: player, - asset: 'usdc', - amount: room.buyIn.toString() - })).concat([{ - participant: this.serverAddress, - asset: 'usdc', - amount: '0' - }]); - - const gameSession = await createAppSessionMessage(this.messageSigner, [{ - definition: appDefinition, - allocations - }]); - - this.ws.send(gameSession); - - room.status = 'ACTIVE'; - room.sessionId = this.generateSessionId(); - - return room; - } -} -``` - -### Subscription Service - -```javascript title="SubscriptionService.js" showLineNumbers -class SubscriptionService { - constructor() { - this.subscriptions = new Map(); - this.ws = null; - this.messageSigner = null; - } - - async createSubscription(subscriber, provider, monthlyFee) { - const appDefinition = { - protocol: 'subscription-v1', - participants: [subscriber, provider, this.serviceAddress], - weights: [0, 100, 0], // Provider controls service delivery - quorum: 100, - challenge: 0, - nonce: Date.now() - }; - - const allocations = [ - { participant: subscriber, asset: 'usdc', amount: (monthlyFee * 12).toString() }, - { participant: provider, asset: 'usdc', amount: '0' }, - { participant: this.serviceAddress, asset: 'usdc', amount: '0' } - ]; - - const sessionMessage = await createAppSessionMessage(this.messageSigner, [{ - definition: appDefinition, - allocations - }]); - - // Send to ClearNode - this.ws.send(sessionMessage); - - const subscriptionId = this.generateSubscriptionId(); - this.subscriptions.set(subscriptionId, { - subscriber, - provider, - monthlyFee, - createdAt: Date.now() - }); - - return subscriptionId; - } - - async processMonthlyPayment(subscriptionId) { - const subscription = this.subscriptions.get(subscriptionId); - - // Create payment message for this month - const paymentMessage = { - type: 'monthly_payment', - subscriptionId, - amount: subscription.monthlyFee, - month: this.getCurrentMonth(), - timestamp: Date.now() - }; - - const signature = await this.messageSigner(JSON.stringify(paymentMessage)); - - this.ws.send(JSON.stringify({ - ...paymentMessage, - signature - })); - - return this.waitForPaymentConfirmation(subscriptionId); - } -} -``` - -## Best Practices - -### Participant Management - -```javascript title="ParticipantManager.js" showLineNumbers -class ParticipantManager { - constructor() { - this.participants = new Map(); - this.roles = new Map(); - } - - addParticipant(address, role, permissions) { - this.participants.set(address, { - role, - permissions: new Set(permissions), - joinedAt: Date.now(), - status: 'ACTIVE' - }); - } - - validateParticipantAction(address, action) { - const participant = this.participants.get(address); - if (!participant) { - throw new Error('Unknown participant'); - } - - if (!participant.permissions.has(action)) { - throw new Error(`Insufficient permissions for action: ${action}`); - } - - return true; - } - - async rotateParticipant(oldAddress, newAddress) { - const participant = this.participants.get(oldAddress); - - // Transfer permissions to new address - this.participants.set(newAddress, { - ...participant, - previousAddress: oldAddress, - rotatedAt: Date.now() - }); - - // Mark old address as rotated - participant.status = 'ROTATED'; - participant.rotatedTo = newAddress; - } -} -``` - -### Message Broadcasting - -```javascript title="MessageBroadcaster.js" showLineNumbers -class MessageBroadcaster { - constructor() { - this.connections = new Map(); - this.messageQueue = new Map(); - } - - async broadcastToParticipants(participants, message) { - const deliveryPromises = participants.map(async (participant) => { - const connection = this.connections.get(participant); - - if (!connection || connection.readyState !== WebSocket.OPEN) { - // Queue message for later delivery - this.queueMessage(participant, message); - return { participant, status: 'QUEUED' }; - } - - try { - connection.send(JSON.stringify(message)); - return { participant, status: 'DELIVERED' }; - } catch (error) { - this.queueMessage(participant, message); - return { participant, status: 'FAILED', error: error.message }; - } - }); - - return Promise.all(deliveryPromises); - } - - queueMessage(participant, message) { - if (!this.messageQueue.has(participant)) { - this.messageQueue.set(participant, []); - } - - this.messageQueue.get(participant).push({ - message, - timestamp: Date.now(), - retries: 0 - }); - } - - async deliverQueuedMessages(participant) { - const queue = this.messageQueue.get(participant); - if (!queue || queue.length === 0) return; - - const connection = this.connections.get(participant); - if (!connection || connection.readyState !== WebSocket.OPEN) return; - - // Deliver all queued messages - for (const queued of queue) { - try { - connection.send(JSON.stringify(queued.message)); - } catch (error) { - queued.retries++; - if (queued.retries < 3) { - continue; // Keep in queue for retry - } - } - } - - // Clear delivered messages - this.messageQueue.set(participant, - queue.filter(msg => msg.retries >= 3) - ); - } -} -``` - -Multi-party applications enable sophisticated logic while maintaining the performance benefits of state channels. Focus on application logic and participant coordination rather than low-level protocol details. \ No newline at end of file diff --git a/docs/learn/deprecated/advanced/security.md b/docs/learn/deprecated/advanced/security.md deleted file mode 100644 index 5752325..0000000 --- a/docs/learn/deprecated/advanced/security.md +++ /dev/null @@ -1,408 +0,0 @@ ---- -sidebar_position: 6 -title: Security Best Practices -description: Secure your Yellow Apps with proper authentication, key management, and monitoring -keywords: [security, authentication, key management, best practices, yellow apps] ---- - -# Security Best Practices - -Secure your Yellow Apps with proper authentication, robust key management, and proactive monitoring. - -## Authentication & Authorization - -### Wallet Integration Security - -```javascript title="WalletSecurity.js" showLineNumbers -class WalletSecurity { - constructor() { - this.authorizedSessions = new Map(); - this.sessionTimeout = 30 * 60 * 1000; // 30 minutes - } - - async authenticateUser(walletAddress) { - // Verify wallet connection - if (!window.ethereum) { - throw new Error('No wallet provider found'); - } - - // Request account access - const accounts = await window.ethereum.request({ - method: 'eth_requestAccounts' - }); - - if (!accounts.includes(walletAddress)) { - throw new SecurityError('Wallet not authorized'); - } - - // Create session - const sessionId = this.generateSessionId(); - this.authorizedSessions.set(sessionId, { - address: walletAddress, - createdAt: Date.now(), - lastActivity: Date.now() - }); - - // Auto-expire session - setTimeout(() => { - this.authorizedSessions.delete(sessionId); - }, this.sessionTimeout); - - return sessionId; - } - - validateSession(sessionId) { - const session = this.authorizedSessions.get(sessionId); - if (!session) { - throw new SecurityError('Invalid or expired session'); - } - - // Update last activity - session.lastActivity = Date.now(); - return session; - } -} -``` - -### Environment Configuration - -```javascript title="SecureConfig.js" showLineNumbers -class SecureConfig { - constructor() { - this.requiredVars = [ - 'CLEARNODE_ENDPOINT', - 'CUSTODY_ADDRESS', - 'ADJUDICATOR_ADDRESS' - ]; - } - - validateEnvironment() { - // Check required environment variables - for (const varName of this.requiredVars) { - if (!process.env[varName]) { - throw new ConfigError(`Missing required environment variable: ${varName}`); - } - } - - // Validate addresses - if (!this.isValidAddress(process.env.CUSTODY_ADDRESS)) { - throw new ConfigError('Invalid custody contract address'); - } - - return { - clearNodeEndpoint: process.env.CLEARNODE_ENDPOINT, - custodyAddress: process.env.CUSTODY_ADDRESS, - adjudicatorAddress: process.env.ADJUDICATOR_ADDRESS, - environment: process.env.NODE_ENV || 'development' - }; - } - - isValidAddress(address) { - return /^0x[a-fA-F0-9]{40}$/.test(address); - } -} -``` - -## Input Validation & Sanitization - -### User Input Security - -```javascript title="InputValidator.js" showLineNumbers -class InputValidator { - validateChannelParams(params) { - return { - participants: this.validateAddresses(params.participants), - amount: this.validateAmount(params.amount), - sessionData: this.sanitizeSessionData(params.sessionData) - }; - } - - validateAddresses(addresses) { - if (!Array.isArray(addresses) || addresses.length < 2) { - throw new ValidationError('Invalid participants array'); - } - - return addresses.map(addr => { - if (!/^0x[a-fA-F0-9]{40}$/.test(addr)) { - throw new ValidationError(`Invalid address: ${addr}`); - } - return addr.toLowerCase(); - }); - } - - validateAmount(amount) { - const bigIntValue = BigInt(amount); - - if (bigIntValue <= 0n) { - throw new ValidationError('Amount must be positive'); - } - - if (bigIntValue > BigInt('1000000000000000000000')) { // 1000 tokens max - throw new ValidationError('Amount exceeds maximum limit'); - } - - return bigIntValue; - } - - sanitizeSessionData(data) { - if (!data) return ''; - - // Remove potentially malicious content - const sanitized = data.replace(/)<[^<]*)*<\/script>/gi, ''); - - // Validate size limits - if (sanitized.length > 64 * 1024) { // 64KB limit - throw new ValidationError('Session data too large'); - } - - return sanitized; - } -} -``` - -## Error Handling - -### Secure Error Responses - -```javascript title="SecureErrorHandler.js" showLineNumbers -class SecureErrorHandler { - constructor() { - this.errorLogs = new Map(); - } - - handleError(error, context) { - // Log detailed error internally - this.logError(error, context); - - // Return sanitized error to user - return this.sanitizeError(error); - } - - sanitizeError(error) { - // Remove sensitive information from error messages - const safeErrors = { - 'ValidationError': 'Invalid input parameters', - 'SecurityError': 'Authentication failed', - 'NetworkError': 'Connection issue', - 'TimeoutError': 'Request timed out' - }; - - return { - message: safeErrors[error.constructor.name] || 'An error occurred', - code: this.getErrorCode(error), - timestamp: Date.now() - }; - } - - logError(error, context) { - const errorEntry = { - message: error.message, - stack: error.stack, - context, - timestamp: Date.now(), - severity: this.getErrorSeverity(error) - }; - - // Store securely (never expose to client) - this.errorLogs.set(this.generateErrorId(), errorEntry); - } -} -``` - -## Rate Limiting & Protection - -### DDoS Protection - -```javascript title="RateLimiter.js" showLineNumbers -class RateLimiter { - constructor() { - this.requestCounts = new Map(); - this.limits = { - perMinute: 100, - perHour: 1000, - perDay: 10000 - }; - } - - async checkRateLimit(userAddress, action) { - const key = `${userAddress}:${action}`; - const now = Date.now(); - - // Clean old entries - this.cleanupOldEntries(now); - - const userRequests = this.requestCounts.get(key) || []; - - // Check minute limit - const minuteCount = userRequests.filter(t => now - t < 60000).length; - if (minuteCount >= this.limits.perMinute) { - throw new SecurityError('Rate limit exceeded'); - } - - // Record request - userRequests.push(now); - this.requestCounts.set(key, userRequests); - - return true; - } - - cleanupOldEntries(now) { - const dayAgo = now - 24 * 60 * 60 * 1000; - - for (const [key, requests] of this.requestCounts) { - const filtered = requests.filter(t => t > dayAgo); - if (filtered.length === 0) { - this.requestCounts.delete(key); - } else { - this.requestCounts.set(key, filtered); - } - } - } -} -``` - -## Monitoring & Logging - -### Application Monitoring - -```javascript title="SecurityMonitor.js" showLineNumbers -class SecurityMonitor { - constructor() { - this.metrics = new Map(); - this.alerts = new Set(); - } - - trackUserActivity(userAddress, action, details) { - const key = `${userAddress}:${action}`; - const activity = { - timestamp: Date.now(), - action, - details, - userAgent: details.userAgent, - ipAddress: details.ipAddress - }; - - if (!this.metrics.has(key)) { - this.metrics.set(key, []); - } - - this.metrics.get(key).push(activity); - - // Check for suspicious patterns - this.detectSuspiciousActivity(userAddress, action); - } - - detectSuspiciousActivity(userAddress, action) { - const activities = this.metrics.get(`${userAddress}:${action}`) || []; - const recentActivities = activities.filter(a => - Date.now() - a.timestamp < 5 * 60 * 1000 // Last 5 minutes - ); - - // Flag rapid consecutive actions - if (recentActivities.length > 50) { - this.alerts.add({ - type: 'RAPID_ACTIVITY', - userAddress, - action, - count: recentActivities.length, - timestamp: Date.now() - }); - } - } - - getSecurityMetrics() { - return { - totalUsers: this.metrics.size, - activeAlerts: this.alerts.size, - recentActivity: this.getRecentActivityCount(), - timestamp: Date.now() - }; - } -} -``` - -## Security Testing - -### Application Security Tests - -```javascript title="security.test.js" showLineNumbers -describe('Yellow App Security', () => { - describe('Authentication', () => { - it('should reject unauthorized wallet connections', async () => { - const unauthorizedWallet = '0x1234567890123456789012345678901234567890'; - - await expect( - app.authenticateUser(unauthorizedWallet) - ).rejects.toThrow('Wallet not authorized'); - }); - - it('should expire sessions after timeout', async () => { - const session = await app.createSession(validWallet); - - // Fast-forward time - jest.advanceTimersByTime(31 * 60 * 1000); // 31 minutes - - expect(app.validateSession(session.id)).toThrow('Invalid or expired session'); - }); - }); - - describe('Input Validation', () => { - it('should reject invalid amounts', async () => { - await expect( - app.createPayment(-100n, recipient) - ).rejects.toThrow('Amount must be positive'); - }); - - it('should sanitize malicious session data', async () => { - const maliciousData = 'normal content'; - const sanitized = app.sanitizeSessionData(maliciousData); - - expect(sanitized).toBe('normal content'); - expect(sanitized).not.toContain('