Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 151 additions & 37 deletions content/docs/concept/channels/unidirectional-channel.mdx
Original file line number Diff line number Diff line change
@@ -1,94 +1,208 @@
---
title: Unidirectional Channel
description: Open a one-way payment channel where funds can only flow from initiator to acceptor
date: 2026-05-25
description: Open a one-way payment channel where funds can only flow from initiator to acceptor — ideal for streaming payments and merchant receiving
date: 2026-06-15
---

import { Callout } from 'fumadocs-ui/components/callout';

<Callout type="info">
This page is a work in progress. Detailed operational guides and examples will be added soon.
</Callout>
## TL;DR

Set `one_way: true` when opening a channel to restrict payment flow to one direction: from initiator to acceptor. One-way channels are always private and cannot route third-party payments. When the channel closes, any unspent funds are returned to the initiator.

A **unidirectional channel** (also called a one-way channel) is a payment channel where funds can only flow in a single direction: from the channel initiator to the acceptor. Unlike a standard bidirectional channel, the acceptor cannot send payments back through the channel.
```bash
fnn-cli channel open_channel --pubkey <peer_pubkey> --funding-amount 49900000000 --one-way
```

## When to Use a Unidirectional Channel
## What Is a Unidirectional Channel

Unidirectional channels are useful in scenarios where:
A **unidirectional channel** (also called a **one-way channel**) is a payment channel where funds can only flow in a single direction — from the channel initiator to the acceptor. Unlike a standard bidirectional channel, the acceptor cannot send payments back through the same channel.

- **One-way streaming payments**: A subscriber pays a content provider continuously, but never expects refunds or payments back
- **Merchant-only receiving**: A merchant opens a channel solely to receive customer payments
- **Simplified channel management**: No need to worry about balanced liquidity in both directions
Think of it like a prepaid card: you load money onto it, and the merchant can only receive from it, never push money back. If you don't spend everything, you get the remainder back when you close the channel.

Under the hood, the channel's TLC (Time-Locked Contract) logic restricts the initiator to be the only sender and the acceptor to be the only receiver.

## How It Works

In a unidirectional channel:

1. The **initiator** opens the channel and provides all the funding
2. The **acceptor** does not contribute any funds to the channel
3. The initiator can send payments to the acceptor through off-chain TLC updates
4. The acceptor **cannot** send payments back to the initiator through this channel
2. The **acceptor** does not contribute any funds
3. The initiator sends payments to the acceptor through off-chain TLC updates
4. The acceptor **cannot** send payments back — any attempt to do so will fail at the routing level with a "Failed to build route" error
5. When the channel closes, the final balance is settled on-chain

The direction restriction is enforced at the routing level. The node will never find a valid path for a reverse payment, so such payments are rejected before they even leave the sender.

<Callout type="warning">
Unidirectional channels **cannot be public**. They will not be broadcast to the network graph, so they cannot be used for routing payments from other nodes.
One-way channels **cannot be public**. If you set both `public: true` and `one_way: true`, the node will reject the request with `"An one-way channel cannot be public"`. This also means one-way channels cannot participate in routing payments for other nodes.
</Callout>

## Comparison with Bidirectional Channels

| Property | Unidirectional | Bidirectional |
|---|---|---|
| Funding | Only initiator funds | Both parties can fund |
| Payment direction | Initiator → Acceptor only | Both directions |
| Public visibility | Always private | Can be public or private |
| Routing for others | Cannot route third-party payments | Can route payments if public |
| Channel rebalancing | Not applicable | Supported via circular payments |
| Typical use case | Streaming, merchant receiving | General P2P payments |
| Channel reserve | ≥99 CKB (initiator side, default) | ≥99 CKB per side (default) |

## Use Cases and Trade-offs

### Good Fit

**Streaming payments.** A subscriber pays a content provider continuously — for example, paying per second of video watched or per API call made. The subscriber (initiator) funds the channel and streams payments to the provider (acceptor). Since payments only go one way, a unidirectional channel is a natural fit and avoids the complexity of managing liquidity in both directions.

**Merchant receiving.** A merchant opens a channel with a specific customer or partner so the customer can make repeated purchases without on-chain transactions each time. The customer is the initiator; the merchant is the acceptor.

**IoT and machine-to-machine payments.** A device that continuously pays for a service (compute, data, bandwidth) benefits from the simplified model — the device opens a one-way channel and drips payments as the service is consumed.

### When to Use Bidirectional Instead

If you expect payments to flow in both directions — for example, two peers who may trade roles as payer and payee — use a standard bidirectional channel. A one-way channel cannot be "upgraded" to bidirectional after creation; you would need to close it and open a new one.

### Limitations

- **No reverse payments.** If the acceptor needs to pay the initiator, they must open a separate channel.
- **No routing participation.** One-way channels are invisible to the network graph, so they cannot earn routing fees or help relay payments for others.
- **No rebalancing.** Since only one side holds funds, there is no liquidity rebalancing to manage.

## Opening a Unidirectional Channel

Set `one_way: true` when calling `open_channel`:
Set `one_way: true` when calling `open_channel`. The parameter is optional and defaults to `false`.

### Using fnn-cli

```bash
fnn-cli channel open_channel --pubkey <acceptor_pubkey> --funding-amount 49900000000 --one-way
```

### Using JSON-RPC

```json
{
"jsonrpc": "2.0",
"method": "open_channel",
"params": [
{
"peer_id": "QmbLM...",
"funding_amount": "0x77359400",
"pubkey": "02abc...",
"funding_amount": "0xb9e459300",
"one_way": true
}
],
"id": 1
}
```

Or using `fnn-cli`:
<Callout>
The `funding_amount` is in **shannons** (1 CKB = 10⁸ shannons). By default, 99 CKB is reserved for the channel reserve (98 CKB minimum cell capacity + 1 CKB default shutdown fee), so the available balance for payments is `funding_amount - 99_00000000` shannons. This default can be adjusted via the `FIBER_AUTO_ACCEPT_CHANNEL_CKB_FUNDING_AMOUNT` environment variable.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FIBER_AUTO_ACCEPT_CHANNEL_CKB_FUNDING_AMOUNT env var controls the auto-accept funding contribution, not the channel reserve itself.

</Callout>

## Sending Payments

Once the channel is in `ChannelReady` state, the initiator can send payments to the acceptor using `send_payment` as usual. No special parameters are needed — the routing engine automatically knows the channel is one-way and only allows forward-direction payments.

```json
{
"jsonrpc": "2.0",
"method": "send_payment",
"params": [
{
"target_pubkey": "<acceptor_pubkey>",
"amount": "0x5f5e100",
"keysend": true
}
],
"id": 1
}
```

If the acceptor tries to send a payment back through the same channel, the routing algorithm will fail because it cannot find a valid path:

```
Error: Failed to build route
```

## Closing and Fund Recovery

<Callout type="info">
Although funds flow in only one direction during the channel's lifetime, closing a one-way channel works exactly the same as closing a bidirectional channel. Any unspent balance is returned to the initiator.
</Callout>

This is an important point that often causes confusion. A one-way channel restricts the **payment direction** during the channel's lifetime, but it does **not** mean the initiator forfeits unspent funds. When the channel closes — whether cooperatively or by force — the on-chain settlement distributes funds according to the current balance:

- **Initiator's remaining balance** goes back to the initiator's CKB address
- **Acceptor's received balance** goes to the acceptor's CKB address
- The channel reserve (99 CKB by default) is released back to the initiator

For example, if you open a one-way channel with 499 CKB and send 120 CKB worth of payments before closing:

- You (initiator) receive back: 499 - 120 - fees = **~379 CKB** (minus transaction fees)
- The acceptor receives: **120 CKB**

Either party can initiate the close:

```bash
fnn-cli channel open_channel --peer-id QmbLM... --funding-amount 49900000000 --one-way
fnn-cli channel shutdown_channel --channel-id <channel_id>
```

## Channel Properties
Or via JSON-RPC:

| Property | Unidirectional Channel | Bidirectional Channel |
|----------|----------------------|----------------------|
| Funding | Only initiator funds | Both parties fund |
| Payment direction | Initiator → Acceptor only | Both directions |
| Public visibility | Cannot be public | Can be public |
| Routing capability | Cannot route third-party payments | Can route payments |
| Use case | Streaming, receiving | General P2P payments |
```json
{
"jsonrpc": "2.0",
"method": "shutdown_channel",
"params": [
{
"channel_id": "0x..."
}
],
"id": 1
}
```

For details on the cooperative and force-close flows, see [Channel Lifecycle](/docs/concept/channels/channel-lifecycle).

## Monitoring
## Monitoring One-Way Channels

When listing channels, check `is_one_way` to verify the channel type:
When listing channels, the `is_one_way` field indicates whether a channel is unidirectional:

```bash
fnn-cli channel list_channels
```

The response will include:
Response:

```json
{
"channel_id": "0x...",
"is_one_way": true,
"state": { "state_name": "ChannelReady" }
"channels": [
{
"channel_id": "0x...",
"pubkey": "02abc...",
"is_public": false,
"is_one_way": true,
"is_acceptor": false,
"state": { "state_name": "CHANNEL_READY" },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"state": { "state_name": "CHANNEL_READY" },
"state": { "state_name": "ChannelReady" },

"local_balance": "0x9c16f4300",
"remote_balance": "0x1dcd65000"
}
]
}
```

Combine `is_one_way` with `is_acceptor` to determine your role in the channel:

| `is_one_way` | `is_acceptor` | Your role |
|---|---|---|
| `true` | `false` | You are the payer (TLC sender) |
| `true` | `true` | You are the payee (TLC receiver) |
| `false` | either | Standard bidirectional channel |

## Related Topics

- [Channel Lifecycle](/docs/guide/channels/channel-lifecycle) — full channel state transitions
- [Channel Rebalancing](/docs/guide/channels/channel-rebalancing) — adjust liquidity in bidirectional channels
- [Payment Lifecycle](/docs/guide/payments/payment-lifecycle) — how payments are processed
- [Channel Lifecycle](/docs/concept/channels/channel-lifecycle) — full channel state transitions and closing flows
- [Channel Rebalancing](/docs/concept/channels/channel-rebalancing) — liquidity management in bidirectional channels
- [Payment Lifecycle](/docs/concept/payments/payment-lifecycle) — how TLC payments are processed
Loading