Skip to main content
Version: 1.x

Home Channel Withdraw on Create Flow

This document provides a comprehensive breakdown of the Home Channel Withdraw On Create From State flow as defined in the Nitrolite v1.0 protocol. This is a special case flow that handles users who have received off-chain funds (have a pending state) but don't yet have an on-chain channel.

This scenario commonly occurs when a user receives a transfer before ever depositing -- they need to create an on-chain channel to withdraw their received funds.


Actors in the Flow

ActorRole
UserThe human user initiating the withdrawal
ClientSDK/Application managing states on behalf of the user
NodeThe Clearnode that contains the user's pending state
HomeChainThe blockchain where the channel will be created

Prerequisites

Before this flow begins:

  1. Client is connected to the Node via WebSocket.
  2. Node contains a state with no channel -- user has an off-chain state (e.g., from receiving transfers) but no on-chain home channel.
  3. User wants to withdraw funds from their off-chain balance.
Key Scenario

This flow is critical for users who receive funds before ever depositing. For example, if Alice sends funds to Bob, but Bob has never created a channel, Bob's state exists off-chain in the Node. When Bob wants to withdraw, this flow creates his channel and withdraws in one operation.


Key Concepts

State Without Channel

Unlike a new user (who has no state at all), this user has an off-chain state but no on-chain channel:

AspectNew UserThis User
Has off-chain stateNoYes
Has on-chain channelNoNo
Has balanceNoYes (from receives)
Node returnschannel_not_found errorState with no home chain

Why This Flow Exists

The Nitrolite protocol allows users to receive off-chain transfers without having a channel. The Node tracks these states and signs them. However, to withdraw, the user must:

  1. Create an on-chain channel (to have a settlement destination).
  2. Submit the withdrawal state via channel creation.

This flow combines both operations.


Phase 1: Withdrawal Initiation

The User calls the withdraw function on the Client SDK:

ParameterDescriptionExample
blockchainIdThe blockchain ID to create channel and withdraw on137 (Polygon)
assetThe asset symbol to withdrawusdc
amountThe amount to withdraw50.0

Phase 2: Fetching Current State (No Home Chain)

  1. Client requests the latest state from the Node.
  2. Node finds the user's state (from receiving transfers).
  3. Node returns a state with no home chain -- indicating off-chain balance exists but no channel.

The State Returned

FieldValue
version>= 1 (from receive transitions)
home_channel_idnull/empty
home_ledgerContains balance from receives
transitionsContains transfer_receive entries

Unlike "creation from scratch" (which returns an error), this returns an actual state -- but without a home channel ID.


Phase 3: Building the Withdrawal State with Channel Definition

3.1 Create Channel Definition

newChannelDefinition() -> channelDef

Since no channel exists, the Client needs to create one:

FieldValue
nonceUnique number (can be random, derived from timestamp, or an increment from the previous nonce)
challengeDurationDefault challenge period
userUser wallet address
nodeNode wallet address
metadataApplication-specific metadata (bytes32)

3.2 Create Next State

createNextState(currentState) -> state

Creates a new state based on the existing pending state (not a new empty state).

3.3 Apply Channel Creation

state.ApplyChannelCreation(channelDef, blockchainId, tokenAddress, nodeAddress)

Sets up the state with the channel definition, token information, and node address. This also computes and sets the State ID internally.

3.4 Apply Withdrawal Transition

state.ApplyHomeWithdrawalTransition(amount)

Creates and applies the withdrawal transition internally:

FieldValue
typehome_withdrawal
tx_hashState ID reference
account_idUser wallet address
amountWithdrawal amount

3.5 Sign

The user signs the state.


Phase 4: Requesting Channel Creation with Withdrawal

Key Difference from Regular Creation

AspectRegular CreationThis Flow
Previous statenil (no state)pendingState (has balance)
ValidationValidateStateTransition(nil, state)ValidateStateTransition(pendingState, state)
Initial transitionhome_deposithome_withdrawal

Node Validation Steps

StepOperationPurpose
1GetLastState(...)Get the pending state (with balance)
2ValidateChannelDefinition(...)Ensure valid nonce and challenge
3ValidateStateTransition(...)Validate from pending to withdrawal state
4StoreChannel(channel)Create channel record
5StoreState(state)Store the withdrawal state

Validation Rules

The Node validates:

  • Version continuity from pending state
  • Sufficient balance for withdrawal (from received funds)
  • Valid signatures
  • No overdraft beyond received balance

Phase 5: On-Chain Channel Creation

What Happens On-Chain

The createChannel call does both operations atomically:

  1. Creates the channel on the blockchain (emits ChannelCreated).
  2. Processes the withdrawal state with negative net flow (emits ChannelWithdrawn).
  3. Releases funds to the user's wallet.

On-Chain State After Creation

FieldValue
channel_idHash of definition
statusOPERATING
state_versionCurrent version
locked_fundsBalance minus withdrawal

Where Do Funds Come From?

Since this is a withdrawal without deposit:

  • Node must provide liquidity -- the Node covers the withdrawal from its own funds.
  • Net effect: User receives tokens, Node's locked funds increase.
  • Security: Node trusts the off-chain state it already signed.

Phase 6: Event Handling and Completion

The Client returns success to the User, confirming:

  • Home channel created successfully
  • Withdrawal processed
  • Funds received in their wallet

Complete Flow Diagram


Key Concepts Summary

State Lifecycle in This Flow

Comparison: Three Channel Creation Scenarios

ScenarioUser Has State?Initial TransitionAPI Method
From ScratchNo (channel_not_found error)home_depositrequest_creation
Withdraw on CreateYes (pending state)home_withdrawalrequest_creation
Regular WithdrawalYes + Channel existshome_withdrawalsubmit_state

Who Provides Withdrawal Funds?

The Node trusts the off-chain state because it already co-signed all receive transitions.


Security Considerations

Why Is This Safe?

  1. Node already signed receives -- All transfer_receive transitions were co-signed by Node.
  2. Version continuity -- Withdrawal state must increment from pending state.
  3. Balance enforcement -- Cannot withdraw more than received balance.
  4. On-chain verification -- Smart contract validates both signatures.

Invariants Preserved

InvariantHow It Applies
Version monotonicityWithdrawal version > pending state version
Signature authorizationBoth User and Node sign the withdrawal state
No overdraftWithdrawal amount must not exceed received balance

Error Scenarios

ScenarioCauseResolution
No pending stateUser has never received fundsUse regular "from scratch" flow
Insufficient balanceWithdrawal exceeds received amountReduce withdrawal amount
Channel already existsUser already has a home channelUse regular withdrawal flow