Menu
Lightning Intermediate 8 min read

Payment Channels

How Lightning payment channels work. Channel lifecycle, funding transactions, commitment transactions, and channel capacity.

channels funding commitment capacity

Payment Channels

A payment channel is a two-party financial relationship that allows unlimited payments without touching the blockchain. Only two on-chain transactions are needed: one to open the channel, one to close it.

Why Channels Matter for Agents

BenefitDescription
SpeedPayments settle in milliseconds
CostNo on-chain fees for channel payments
VolumeUnlimited payments per channel
PrivacyIntermediate states aren’t broadcast

Channel Lifecycle

1. Channel Opening

Two parties create a funding transaction that locks Bitcoin into a 2-of-2 multisig address.

Alice: 0.1 BTC ─┐
                ├─ Funding TX ─→ 2-of-2 Multisig
Bob:   0.0 BTC ─┘

On-chain cost: One transaction (~140 vbytes)

2. Channel Usage

Parties exchange commitment transactions off-chain. Each commitment represents the current balance split.

State 0: Alice=0.1, Bob=0.0
State 1: Alice=0.09, Bob=0.01  (Alice pays Bob 0.01)
State 2: Alice=0.08, Bob=0.02  (Alice pays Bob 0.01)
State 3: Alice=0.085, Bob=0.015 (Bob pays Alice 0.005)

On-chain cost: Zero

3. Channel Closing

When parties are done, they broadcast a closing transaction that splits funds according to the final state.

Cooperative close: Both parties sign, immediate settlement Unilateral close: One party broadcasts, requires timelock

Commitment Transactions

Each party holds their own commitment transaction that they can broadcast at any time.

┌─────────────────────────────────────┐
│         Commitment TX (Alice's)      │
├─────────────────────────────────────┤
│ Input: Funding TX output            │
│                                     │
│ Output 1: Alice (immediate)         │
│ Output 2: Bob (with revocation key) │
└─────────────────────────────────────┘

Asymmetric Commitments

Alice and Bob hold different commitment transactions:

Alice’s commitment:

  • Alice’s balance: delayed (CSV timelock)
  • Bob’s balance: immediate (or revocable)

Bob’s commitment:

  • Bob’s balance: delayed (CSV timelock)
  • Alice’s balance: immediate (or revocable)

This asymmetry enables revocation—if Bob broadcasts an old state, Alice can sweep all funds using the revocation key.

Channel Capacity

Capacity = Total BTC locked in the channel Local balance = Your spendable amount Remote balance = Peer’s spendable amount

Channel Capacity: 0.1 BTC
├── Alice (local): 0.06 BTC ──→ Can send up to 0.06 BTC
└── Bob (remote):  0.04 BTC ──→ Can receive up to 0.04 BTC

Inbound vs Outbound Liquidity

TypeDescriptionAgent Use
OutboundFunds you can sendMaking payments
InboundFunds you can receiveReceiving payments

Key insight: To receive payments, you need inbound liquidity (funds on the remote side of your channels).

Channel States

Valid States

┌──────────┐    open_channel    ┌───────────┐
│  Closed  │ ─────────────────→ │  Opening  │
└──────────┘                    └───────────┘

                             funding_confirmed

┌──────────┐   closing_signed   ┌───────────┐
│ Closing  │ ←───────────────── │   Open    │
└──────────┘                    └───────────┘
     │                                ↑
     │ tx_confirmed                   │
     ↓                          update_add_htlc
┌──────────┐                   commitment_signed
│  Closed  │
└──────────┘

Force Close Scenarios

ScenarioResolution
Peer offlineUnilateral close after timeout
Peer maliciousRevocation transaction
Peer unresponsiveForce close with CSV delay

Agent Implementation

Opening a Channel

# Via LND gRPC
channel_point = lnd.open_channel(
    node_pubkey=peer_pubkey,
    local_funding_amount=100000,  # satoshis
    push_sat=0,                   # initial remote balance
    private=False                 # announce to network
)

Checking Channel Status

# Get channel info
channels = lnd.list_channels()

for channel in channels:
    print(f"Capacity: {channel.capacity}")
    print(f"Local: {channel.local_balance}")
    print(f"Remote: {channel.remote_balance}")
    print(f"Active: {channel.active}")

Closing a Channel

# Cooperative close (preferred)
lnd.close_channel(
    channel_point=channel_point,
    force=False
)

# Force close (peer unresponsive)
lnd.close_channel(
    channel_point=channel_point,
    force=True
)

Channel Parameters

ParameterDescriptionTypical Value
funding_satoshisChannel capacity100,000 - 16,777,215
push_msatInitial remote balance0
dust_limit_satoshisMinimum output354
max_htlc_value_in_flight_msatMax pending HTLCsChannel capacity
channel_reserve_satoshisMinimum local balance1% of capacity
htlc_minimum_msatMinimum HTLC1000
to_self_delayCSV blocks for force close144 (1 day)
max_accepted_htlcsMax concurrent HTLCs483

Reserve Requirements

Each party must maintain a channel reserve—a minimum balance that can’t be spent. This creates a penalty if they broadcast an old state.

Channel: 1,000,000 sats
Reserve: 10,000 sats (1%)

Alice can spend: local_balance - 10,000

Anchor Outputs

Modern channels use anchor outputs—small outputs that allow fee bumping via CPFP (Child Pays For Parent).

Commitment TX
├── Alice's balance
├── Bob's balance
├── Alice's anchor (330 sats)
└── Bob's anchor (330 sats)

Anchors ensure commitment transactions can be confirmed even if fees spike.

Channel Types

TypeAnnouncementRoutingUse Case
PublicBroadcast to networkYesRouting nodes
PrivateKnown only to peersNoEnd-user wallets
UnannouncedNot in gossipPossibleTemporary channels

Best Practices for Agents

  1. Channel size: Open channels with enough capacity for expected volume
  2. Multiple channels: Don’t rely on a single channel
  3. Well-connected peers: Choose peers with good routing connectivity
  4. Monitor capacity: Rebalance before liquidity runs out
  5. Backup channel state: Store SCBs (Static Channel Backups)
  • HTLCs - How payments traverse channels
  • Liquidity - Managing channel capacity
  • Routing - Multi-hop payments
  • BOLT-02 - Peer Protocol specification

Machine-Readable Summary

{
  "topic": "payment-channels",
  "key_concepts": [
    "funding-transaction",
    "commitment-transaction",
    "channel-capacity",
    "revocation"
  ],
  "operations": [
    "open_channel",
    "update_commitment",
    "close_channel"
  ],
  "parameters": {
    "min_channel_size": 20000,
    "max_channel_size": 16777215,
    "typical_reserve": "1%"
  }
}