B++ Logo

Hash Time-Locked Contracts (HTLCs)

HTLCs are the mechanism that enables payments to route through the Lightning Network. They ensure that payments can only be claimed with the correct preimage, and expire after a certain time if unclaimed. An HTLC is a conditional payment that requires:

  1. Hash Lock: Knowledge of a secret (preimage) that hashes to a known value
  2. Time Lock: Expires after a certain block height (CLTV)
HTLC Conditions:
- If preimage is revealed before expiry → Payment goes to recipient
- If time lock expires → Payment returns to sender

How HTLCs Work in Lightning

Payment Flow

  1. Recipient generates preimage: Random 32-byte secret, shares SHA256 hash
  2. Sender creates HTLC chain: Locks funds with hash and decreasing expiries
  3. HTLCs propagate: Each hop creates an HTLC to the next
  4. Recipient reveals preimage: Claims final HTLC
  5. Preimage propagates back: Each hop claims their incoming HTLC
  6. Settlement complete: All HTLCs resolved atomically

Example Route

Alice → Bob → Carol → Dave

Alice creates HTLC to Bob:
  - Amount: 1000 + 3 sats (fees)
  - Hash: SHA256(preimage)
  - Expiry: Block 850,040

Bob creates HTLC to Carol:
  - Amount: 1000 + 1 sats (fees)  
  - Hash: SHA256(preimage) [same]
  - Expiry: Block 850,030 [earlier]

Carol creates HTLC to Dave:
  - Amount: 1000 sats
  - Hash: SHA256(preimage) [same]
  - Expiry: Block 850,020 [earliest]

Why Decreasing Expiries?

Each hop needs an expiry delta (CLTV delta) buffer to:

  • Have time to claim incoming HTLC after learning preimage
  • Handle blockchain congestion
  • Account for clock differences between nodes

Rule: Outgoing HTLC expiry < Incoming HTLC expiry (by at least cltv_expiry_delta)


HTLC Script Structure

HTLCs in commitment transactions use this script pattern:

# Offered HTLC (you're offering payment)
OP_DUP OP_HASH160 <revocation_pubkey_hash> OP_EQUAL
OP_IF
    OP_CHECKSIG                           # Revocation path
OP_ELSE
    <remote_htlc_pubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
    OP_IF
        OP_HASH160 <payment_hash> OP_EQUALVERIFY  # Success path
        2 OP_SWAP <local_htlc_pubkey> 2 OP_CHECKMULTISIG
    OP_ELSE
        OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
        OP_CHECKSIG                       # Timeout path
    OP_ENDIF
OP_ENDIF

HTLC Verification


HTLC States

An HTLC in a channel transitions through these states:

StateDescriptionOutcome
OfferedSent to peer, awaiting response→ Accepted or Failed
AcceptedPeer acknowledged, awaiting preimage→ Settled or Failed
SettledPreimage revealed, funds transferredComplete
FailedTimeout or error, funds returnedComplete
Lifecycle:
Offered → Accepted → Settled (success)
    ↓         ↓
  Failed   Failed (timeout/error)

HTLC Security Properties

Atomicity

Either the entire payment succeeds or fails completely:

  • All HTLCs in the route share the same payment hash
  • Revealing the preimage settles all HTLCs
  • Timeout returns all funds to senders

Hash Lock Security

  • Preimage must be exactly 32 bytes
  • SHA256 is collision-resistant
  • Only the recipient knows the preimage initially

Time Lock Security

  • CLTV (CheckLockTimeVerify) enforced by Bitcoin consensus
  • Sufficient delta prevents race conditions
  • Allows time for breach detection

Common Issues

HTLC Timeout

Problem: HTLC expires before payment completes.

Causes:

  • Route too long (accumulated CLTV deltas)
  • Slow intermediate nodes
  • Network congestion

Solutions:

  • Increase max_cltv_expiry setting
  • Use shorter routes
  • Retry with different path

Stuck HTLCs

Problem: HTLC neither settles nor fails.

Causes:

  • Peer offline
  • Bug in implementation
  • Network partition

Solutions:

  • Wait for CLTV expiry
  • Force close channel if necessary

Summary

HTLCs are the atomic building blocks of Lightning payments:

  • Hash locks ensure only the recipient can claim funds
  • Time locks enable safe routing through untrusted intermediaries
  • Decreasing expiries prevent routing attacks
  • Atomicity guarantees all-or-nothing settlement