Skip to main content

Cross-Layer Communication Flows

This section illustrates how the on-chain and off-chain layers interact during typical operations. Each flow shows the sequence of method calls and data exchange between Client, Clearnode, and Smart Contracts.

Flow Navigation

Jump to a specific flow:


Authentication Flow

Purpose

Establish authenticated session with session key delegation.

Actors

  • Client: User application or SDK
  • Clearnode: Off-chain service provider

Sequence Diagram

Steps

Step 1: Client Generates Session Keypair

The session key is generated entirely off-chain and the private key never leaves the client:

session_private_key = random()
session_public_key = derive(session_private_key)
session_address = address(session_public_key)

Step 2: Client → Clearnode: auth_request (public, no signature)

The client sends a public registration request (no signature required):

Request:
{
address: user_wallet_address
session_key: session_address
allowances: [{"asset": "usdc", "amount": "100.0"}]
scope: "transfer,app.create"
expires_at: 1762417328123 // Unix ms
}

Step 3: Clearnode Validates and Generates Challenge

The clearnode performs validation:

  • Validate address/session_key format, optional allowances/scope, expires_at
  • Generate challenge UUID

Step 4: Clearnode → Client: auth_challenge

The clearnode responds with a challenge:

Response:
{
challenge_message: "550e8400-e29b-41d4-a716-446655440000"
}
Signature: signed by Clearnode

Step 5: Client Signs Challenge (MAIN wallet, EIP-712)

The client signs the challenge using the main wallet over the Policy typed data (includes challenge, wallet, session_key, expires_at, scope, allowances):

challenge_signature = signTypedData(policyTypedData, main_wallet_private_key)

Step 6: Client → Clearnode: auth_verify

The client submits the signed challenge (or a previously issued JWT):

Request:
{
challenge: "550e8400-e29b-41d4-a716-446655440000",
// alternatively:
// jwt: "<existing_jwt>"
}
Signature: EIP-712 signature by main wallet (required if jwt is absent)

Step 7: Clearnode Validates Challenge

The clearnode validates:

  • Signature recovers the wallet used in auth_request
  • Challenge matches pending authentication
  • Challenge not expired or reused

Step 8: Clearnode → Client: auth_verify Response

The clearnode confirms authentication:

Response:
{
address: user_wallet_address
session_key: session_address
jwt_token: "<jwt>"
success: true
}

Step 9: Session Established

  • All subsequent requests signed with session_private_key
  • The clearnode enforces allowances and expiration
  • No main wallet interaction required until session expires

Key Points

Session Security
  • Session private key NEVER leaves the client
  • Main wallet only signs once (auth_request)
  • All subsequent operations use session key
  • Allowances prevent unlimited spending
  • Challenge-response prevents replay attacks

Related Methods: auth_request, auth_challenge, auth_verify


Channel Creation Flow

Purpose

Open a payment channel with zero initial balance; fund it later via resize_channel.

Actors

  • Client: User application or SDK
  • Clearnode: Off-chain service provider
  • Smart Contract: Custody Contract
  • Blockchain: Ethereum-compatible network

Sequence Diagram

Steps

Step 1: Client → Clearnode: create_channel

Client requests channel creation:

Request:
{
chain_id: 137 // Polygon
token: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174" // USDC
}
Signature: session key signature

Step 2: Clearnode Processes Request

The clearnode:

  • Validates token is supported on chain
  • Generates unique nonce
  • Selects adjudicator (SimpleConsensus for payment channels)
  • Creates Channel struct
  • Computes channelId = keccak256(abi.encode(Channel))
  • Creates initial State with intent: INITIALIZE, version: 0, state_data: "0x", zero allocations
  • Packs state (abi.encode(channelId, intent, version, data, allocations) in Solidity terms)
  • Signs packed state with clearnode's participant key

Step 3: Clearnode → Client: Response

Response:
{
channel: {
participants: [user_address, clearnode_address]
adjudicator: 0xSimpleConsensusAddress
challenge: 86400
nonce: 1699123456789
}
state: {
intent: INITIALIZE
version: 0
data: "0x"
allocations: [
{destination: user_address, token: usdc, amount: 0},
{destination: clearnode_address, token: usdc, amount: 0}
]
}
server_signature: "0xClearnodeSig..."
channel_id: "0xChannelId..."
}
Clearnode Signs First

The clearnode provides its signature BEFORE the user commits funds on-chain. This ensures both parties have committed before any on-chain transaction occurs.

Steps 4-5: Client Validates and Signs

Client:

  • Recomputes channelId and verifies it matches
  • Recomputes packed state and verifies clearnode signature
  • Signs packed state with user's participant key

Step 6: Client → Blockchain: Custody.create()

Client submits transaction:

Custody.create(channel, state, userSig, serverSig)

Step 7: Blockchain Validates and Creates Channel

Contract:

  • Verifies user's signature is valid
  • Verifies clearnode's signature is valid
  • Stores channel parameters and funding state (zero balances)
  • Sets channel status to OPEN
  • Emits Opened event

Step 8: Event Listener Detects Creation

The clearnode's event listener:

  • Detects Opened event
  • Validates channel parameters

Steps 9-10: Notifications

The clearnode:

  • Updates internal database: channel status = open (zero balance)
  • Sends channel_update notification to client

Step 11: Channel Active

  • Channel active with zero balance
  • Use resize_channel to fund the channel

Key Points

Two-Phase Process
  • Off-chain preparation: Clearnode prepares and signs channel configuration
  • On-chain execution: User submits transaction to lock funds
  • This ensures clearnode is ready to join before user risks funds

Related Methods: create_channel


Off-Chain Transfer Flow

Purpose

Transfer funds between users instantly without blockchain transaction.

Actors

  • Sender (Client A): Initiating user
  • Clearnode: Off-chain service provider
  • Receiver (Client B): Receiving user

Sequence Diagram

Steps

Step 1: Client A → Clearnode: transfer

Sender initiates transfer:

Request:
{
destination: "0xClientB_Address", // or destination_user_tag: "UX123D"
allocations: [{"asset": "usdc", "amount": "50.0"}]
}
Signature: Client A's session key

Step 2: Clearnode Validates

The clearnode validates:

  • Client A is authenticated
  • Client A has >= 50 USDC available balance
  • Destination address/tag is valid (account is created if new)
  • Asset "usdc" is supported

Step 3: Clearnode Creates Ledger Entries

Double-entry bookkeeping:

Entry 1 (Debit from Client A unified account):

{
account_id: Client A address
asset: "usdc"
credit: "0.0"
debit: "50.0"
}

Entry 2 (Credit to Client B unified account):

{
account_id: Client B address
asset: "usdc"
credit: "50.0"
debit: "0.0"
}

Step 4: Clearnode Creates Transaction Record

{
id: 1,
tx_type: "transfer",
from_account: Client A address,
from_account_tag: "NQKO7C",
to_account: Client B address,
to_account_tag: "UX123D",
asset: "usdc",
amount: "50.0",
created_at: "2023-05-01T12:00:00Z"
}

Step 5: Clearnode → Client A: Response

Response:
{
transactions: [
{
id: 1,
tx_type: "transfer",
from_account: "0xA...",
from_account_tag: "NQKO7C",
to_account: "0xB...",
to_account_tag: "UX123D",
asset: "usdc",
amount: "50.0",
created_at: "2023-05-01T12:00:00Z"
}
]
}

Step 6-7: Clearnode → Clients: Notifications

  • tr (transfer) notification to sender/receiver with transactions array
  • bu (balance update) notification reflecting new balances

Step 9: Transfer Complete

  • Instant (< 1 second)
  • No blockchain transaction
  • Zero gas fees
  • Both parties notified

Key Points

Instant Settlement
  • Purely off-chain: Database transaction, no blockchain
  • Instant settlement: < 1 second typical
  • Zero gas fees: No on-chain transaction required
  • Double-entry bookkeeping: Accounting accuracy guaranteed
  • Receiver account auto-created: Destination tag/address need not have a prior balance

Related Methods: transfer


App Session Lifecycle Flow

Purpose

Create, update, and close a collaborative app session with multiple participants.

Actors

  • Client A: Participant 1
  • Client B: Participant 2
  • Clearnode: Off-chain service provider

Scenario

Two-player chess game with 100 USDC stake each.

Sequence Diagram

Sequence (Create → Update → Close)

  1. Create (off-chain): create_app_session

    • Client signs request (all participants with non-zero allocations must sign).
    • Clearnode validates protocol version (0.2/0.4), quorum, balances, allowances/session keys.
    • Funds are locked from each signer’s unified balance into the app session account.
    • Response (minimal): app_session_id, status: "open", version: 1. Full metadata is not echoed; use get_app_sessions to read it.

    Example Request:

    {
    "req": [1,"create_app_session",{
    "definition": {
    "protocol": "NitroRPC/0.4",
    "participants": ["0xA","0xB"],
    "weights": [100,100],
    "quorum": 200,
    "challenge": 86400,
    "nonce": 1699123
    },
    "allocations": [
    {"participant": "0xA","asset": "usdc","amount": "100.0"},
    {"participant": "0xB","asset": "usdc","amount": "100.0"}
    ],
    "session_data": "{\"game\":\"chess\"}"
    },1699123456789],
    "sig": ["0xUserSig","0xCoSig"]
    }
  2. State Updates (off-chain): submit_app_state

    • v0.4 requires version = current+1; v0.2 rejects intent/version and only allows a single update.
    • Intents:
      • operate: redistribute, sum must stay equal.
      • deposit: sum must increase; depositor must sign and have available unified balance.
      • withdraw: sum must decrease; session must have funds.
    • Quorum required; session-key allowances enforced.
    • Response (minimal): app_session_id, status: "open", version (new). No metadata echoed.
    • Notifications: asu (app session update) + bu (balance update for deposit/withdraw).

    Example Request (deposit v0.4):

    {
    "req": [2,"submit_app_state",{
    "app_session_id": "0xSession",
    "intent": "deposit",
    "version": 2,
    "allocations": [
    {"participant": "0xA","asset": "usdc","amount": "150.0"},
    {"participant": "0xB","asset": "usdc","amount": "100.0"}
    ]
    },1699123456790],
    "sig": ["0xUserSig","0xCoSig"]
    }
  3. Close (off-chain): close_app_session

    • Requires quorum signatures; final allocations must match total balances.
    • Response (minimal): app_session_id, status: "closed", version (incremented). No metadata echoed.
    • Funds are released to participants’ unified balances; notifications asu and bu are sent.

    Example Request:

    {
    "req": [3,"close_app_session",{
    "app_session_id": "0xSession",
    "allocations": [
    {"participant": "0xA","asset": "usdc","amount": "180.0"},
    {"participant": "0xB","asset": "usdc","amount": "20.0"}
    ]
    },1699123456795],
    "sig": ["0xUserSig","0xCoSig"]
    }

Key Points

App Sessions

App sessions enable multi-party applications with custom governance rules. Funds are locked from unified balance for the duration of the session.

Related Methods: create_app_session, submit_app_state, close_app_session


Cooperative Closure Flow

Purpose

Close channel when all parties agree on final state.

Actors

  • Client: User application
  • Clearnode: Off-chain service provider
  • Smart Contract: Custody Contract
  • Blockchain: Ethereum-compatible network

Key Points

Preferred Method

Cooperative closure is fast (1 transaction), cheap (low gas), and immediate (no waiting period). Always use this when possible.

Sequence Diagram

Sequence

  1. Client → Clearnode: close_channel(channel_id, funds_destination)

    • Authenticated request signed by the user (session key or wallet).

    Example Request:

    {
    "req": [10,"close_channel",{
    "channel_id": "0xChannel",
    "funds_destination": "0xUser"
    },1699123457000],
    "sig": ["0xUserSig"]
    }
  2. Clearnode: validates channel exists and is open/resizing, checks challenged-channel guard, builds FINALIZE state:

    • intent: FINALIZE, version = current+1, state_data: "0x", allocations split between user and broker based on channel balance.
    • Signs packed state (keccak256(abi.encode(channelId, intent, version, data, allocations))).
  3. Clearnode → Client: response with channel_id, state, server_signature.

  4. Client: verifies server signature, signs the same packed state.

  5. Client → Blockchain: Custody.close(channel_id, state, userSig, serverSig) (one tx).

  6. Blockchain: verifies both signatures, closes channel, emits Closed/Opened-equivalent event (implementation-specific), releases funds.

  7. Clearnode: observes event, updates DB, sends cu (channel update) and bu (balance update) notifications.

Related Methods: close_channel


Challenge-Response Closure Flow

Purpose

Close channel when other party is unresponsive or disputes final state.

Actors

  • Client: User application
  • Clearnode: Off-chain service provider (may be unresponsive)
  • Smart Contract: Custody Contract
  • Blockchain: Ethereum-compatible network

Key Points

Challenge Period

This method requires waiting for the challenge period (typically 24 hours) to elapse. Use only when cooperative closure fails.

Sequence Diagram

Sequence (User-initiated, clearnode unresponsive)

  1. Prerequisite: User holds the latest mutually signed state (or clearnode-signed latest) for the channel.
  2. Client → Blockchain: Custody.challenge(channelId, state, sigs...)
    • Submits the latest signed state to start the challenge.
  3. Challenge Window: Other party can respond with a newer valid state before timeout.
  4. If no newer state is posted: After the challenge period, user calls Custody.close(channelId, state, sigs...) to finalize.
  5. Blockchain: finalizes channel, releases funds per challenged state, emits closure event.
  6. Clearnode (when responsive again): observes event, updates DB, sends cu/bu notifications to participants.

Related Methods: On-chain Custody.challenge() and Custody.close()


Next Steps

Now that you understand how all protocol layers work together:

  1. Review Method Details: Visit Part 2 (Off-Chain RPC Protocol) for complete method specifications
  2. Explore Reference: See Protocol Reference for constants and standards
  3. Implementation Guide: Check Implementation Checklist for best practices
  4. Quick Start: Follow the Quick Start Guide to begin building
Complete Flows

These flows represent the most common operations. For edge cases and error handling, consult the specific method documentation in Part 2.