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 Nitronode 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.

:::info 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: Confirmation 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