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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ For more detail on the process, please read [bLIP-0001](./blip-0001.md) and
| [51](./blip-0051.md) | LSPS1: Channel Requests | Severin Bühler | Active |
| [52](./blip-0052.md) | LSPS2: JIT Channel Negotiation | ZmnSCPxj jxPCSnmZ | Active |
| [55](./blip-0055.md) | LSPS5: Webhook Registration | ZmnSCPxj jxPCSnmZ | Active |
| [70](./blip-0070.md) | RGB Asset Support | will-bitlightlabs | Draft |
44 changes: 42 additions & 2 deletions blip-0002.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,13 @@ network split.
* [Messages](#messages)
* [TLV fields in BOLT messages](#tlv-fields-in-bolt-messages)
* [`init`](#init)
* [`ping`](#ping)
* [`open_channel`](#open_channel)
* [`open_channel2`](#open_channel2)
* [`update_add_htlc`](#update_add_htlc)
* [`channel_announcement`](#channel_announcement)
* [`channel_update`](#channel_update)
* [`ping`](#ping)
* [`payment_onion_payload`](#payment_onion_payload)
* [Onion Messages](#onion-messages)

### Feature bits
Expand All @@ -53,6 +58,7 @@ bLIPs may reserve feature bits by adding them to the following table:
| 260/261 | `htlc_endorsement` | This node forwards experimental htlc endorsement signals | N | | [bLIP 4](./blip-004.md) |
| 262/263 | `bolt11_blinded_path` | This invoice may contain a new blinded path tagged field | I | `option_route_blinding` | [bLIP 39](./blip-0039.md) |
| 729 | `option_supports_lsps` | This node supports LSPS protocol(s) | IN | | [bLIP 50](./blip-0050.md) |
| 826/827 | `rgb_channel` | RGB colored channel support | INCT | | [bLIP 70](./blip-0070.md) |

### Messages

Expand Down Expand Up @@ -98,12 +104,45 @@ The following table contains extension tlv fields for the `init` message:
|-------|-----------------------------|--------------------------------|
| 65536 | `tlv_field_name` | Link to the corresponding bLIP |

#### `open_channel`

The following table contains extension tlv fields for the `open_channel` message:

| Type | Name | Link |
|--------|-----------------------------|--------------------------------|
| 827167 | `rgb_context_data` | [bLIP 70](./blip-0070.md) |

#### `open_channel2`

The following table contains `opening_tlvs` fields for the `open_channel2` message:

| Type | Name | Link |
|--------|-----------------------------|--------------------------------|
| 827167 | `rgb_context_data` | [bLIP 70](./blip-0070.md) |

#### `channel_announcement`

The following table contains trailing TLV fields appended after the defined fields in the `channel_announcement` message:

| Type | Name | Link |
|--------|-----------------------------|--------------------------------|
| 827167 | `rgb_asset_id` | [bLIP 70](./blip-0070.md) |

#### `channel_update`

The following table contains trailing TLV fields appended after the defined fields in the `channel_update` message:

| Type | Name | Link |
|--------|-----------------------------|--------------------------------|
| 827167 | `rgb_htlc_maximum` | [bLIP 70](./blip-0070.md) |

#### `payment_onion_payload`

The following table contains extension tlv fields for the `payment_onion_payload` message:

| Type | Name | Link |
|-------------|-----------------------------|--------------------------------|
| 827167 | `rgb_amount_to_forward` | [bLIP 70](./blip-0070.md) |
| 7629169 | `podcasting_2_0` | [bLIP 10](./blip-0010.md) |
| 5482373484 | `keysend_preimage` | [bLIP 3](./blip-0003.md) |

Expand All @@ -113,8 +152,9 @@ The following table contains extension tlv fields for the `update_add_htlc` mess

| Type | Name | Link |
|--------|-----------------------------|--------------------------------|
| 106823 | `endorsed` | [bLIP 4](./blip-0004.md) |
| 65537 | `extra_fee` | [bLIP 25](./blip-0025.md) |
| 106823 | `endorsed` | [bLIP 4](./blip-0004.md) |
| 827167 | `rgb_amount` | [bLIP 70](./blip-0070.md) |

#### `ping`

Expand Down
266 changes: 266 additions & 0 deletions blip-0070.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
```
bLIP: 70
Title: RGB Asset Support for Lightning Network
Status: Draft
Author: will-bitlightlabs <jayabb@bitlightlabs.com>
Created: 2026-03-27
License: CC0
```

## Abstract

This bLIP defines protocol extensions for carrying RGB colored assets over Lightning
Network channels. It introduces a feature bit for RGB channel negotiation and TLV
fields in wire messages and onion payloads for asset metadata exchange. Standard
Lightning nodes that do not support this extension safely ignore all additions
following the "it's ok to be odd" convention.

## Copyright

This bLIP is licensed under the CC0 license.

## Motivation

The Lightning Network currently only supports BTC payments. However, the RGB
protocol enables issuance and transfer of arbitrary assets on Bitcoin using
client-side validation. Integrating RGB with Lightning allows these assets to
be transferred instantly over payment channels.

Without standardized protocol extensions, RGB-enabled Lightning implementations
would use ad-hoc wire format modifications that break interoperability with
standard nodes. This bLIP provides a minimal, backward-compatible extension
that allows RGB and non-RGB nodes to coexist on the same network.

## Rationale

### Why a feature bit instead of implicit detection

Explicit feature bit negotiation (bit 826 in `channel_type`) ensures that both
peers understand and agree on the RGB channel semantics before any commitment
transaction is built. Without this, a peer might accept an RGB channel without
understanding the OP_RETURN output in commitment transactions, leading to
signature mismatches.

### Why 827167 for TLV type

Using a value derived from SLIP-0044 provides clear provenance and avoids
collision with existing bLIP registrations. The odd parity ensures standard
nodes ignore unknown fields per BOLT #1.

### Why trailing TLV for gossip messages

`channel_announcement` and `channel_update` use a different serialization
pattern than other BOLT messages — they do not have a TLV extension stream.
Instead, any future fields are appended as trailing data after the defined
fields. RGB fields are appended as TLV in this trailing region, which is
covered by the message signature (BOLT #7: signature covers all bytes from
the message body through the end of the message).

## Specification

### Feature Bit

| Bits | Name | Description | Context | Dependencies |
|------|------|-------------|---------|--------------|
| 826/827 | `rgb_channel` | RGB colored channel support | INCT | |

Bit 827 (odd/optional) is set in `init` and `node_announcement` to advertise RGB
support. Bit 826 (even/required) is set in `channel_type` to negotiate a specific
RGB channel. Bit 827 (odd/optional) is set in `channel_announcement` features to
mark a channel as RGB-capable in gossip.

### Wire Message TLV Fields

#### `open_channel`

1. `tlv_stream`: `open_channel_tlvs`
2. types:
1. type: 827167 (`rgb_context_data`)
2. data:
- [`...*byte`:`data`]

#### `open_channel2`

1. `tlv_stream`: `opening_tlvs`
2. types:
1. type: 827167 (`rgb_context_data`)
2. data:
- [`...*byte`:`data`]

`rgb_context_data` is an opaque byte blob. Implementations SHOULD encode it as
a UTF-8 consignment endpoint URL. Supported URL schemes:
- `https://<host>/<path>` — HTTP(S) endpoint for fetching RGB consignment
- `http://<host>/<path>` — HTTP endpoint
- `file://<path>` — local filesystem (testing only)

The URL MAY contain a `{txid}` placeholder, which the receiver replaces with
the funding transaction ID. Example: `https://proxy.example.com/consignment/{txid}`

The writer:
* MUST set `rgb_context_data` when opening an RGB colored channel
* MUST NOT set `rgb_context_data` for pure BTC channels
* SHOULD encode the value as a valid UTF-8 URL with a recognized scheme

The receiver:
* If `rgb_context_data` is present but the receiver does not support `rgb_channel`:
* MUST ignore the TLV field (odd type rule)
* MUST NOT treat the channel as an RGB channel
* If the data cannot be parsed as valid UTF-8 or contains an unrecognized URL
scheme, the receiver SHOULD silently ignore the field and proceed without
prefetching the RGB consignment

#### `update_add_htlc`

1. `tlv_stream`: `update_add_htlc_tlvs`
2. types:
1. type: 827167 (`rgb_amount`)
2. data:
- [`u64`:`amount`]

The writer:
* MUST set `rgb_amount` to the RGB asset amount carried by this HTLC
* MUST NOT set `rgb_amount` for pure BTC HTLCs

The receiver:
* If `rgb_amount` is present but the receiver does not support `rgb_channel`:
* MUST ignore the TLV field
* If `rgb_amount` is present and the receiver supports `rgb_channel`:
* MUST process the HTLC as carrying the specified RGB asset amount

#### `channel_announcement` (trailing TLV)

1. `tlv_stream`: appended as trailing data after the defined fields
2. types:
1. type: 827167 (`rgb_asset_id`)
2. data:
- [`32*byte`:`contract_id`]

`rgb_asset_id` is a 32-byte RGB contract identifier (`ContractId` in RGB v0.12).

The writer:
* MUST set `rgb_asset_id` to the 32-byte RGB contract identifier for an RGB channel
* MUST NOT set `rgb_asset_id` for pure BTC channels
* MUST set feature bit 827 (odd) in the `features` field

The receiver:
* SHOULD verify the field is exactly 32 bytes; if the length does not match,
the field SHOULD be treated as invalid and the channel SHOULD NOT be
considered for RGB routing
* MAY use `rgb_asset_id` for RGB-aware route selection
* This field is covered by the `channel_announcement` signature

#### `channel_update` (trailing TLV)

1. `tlv_stream`: appended as trailing data after the defined fields
2. types:
1. type: 827167 (`rgb_htlc_maximum`)
2. data:
- [`u64`:`amount`]

The writer:
* MUST set `rgb_htlc_maximum` to the maximum HTLC amount in RGB asset units
* MUST NOT set `rgb_htlc_maximum` for pure BTC channels

The receiver:
* MAY use `rgb_htlc_maximum` for RGB-aware route capacity checks
* This field is covered by the `channel_update` signature

### Onion Payload TLV Field

#### Per-hop `payload` (BOLT #4)

1. `tlv_stream`: `payload`
2. types:
1. type: 827167 (`rgb_amount_to_forward`)
2. data:
- [`u64`:`amount`]

The writer:
* MUST set `rgb_amount_to_forward` to the RGB asset amount the next hop should forward
* For the final hop, this is the amount the receiver should claim

The receiver:
* If forwarding: MUST set `rgb_amount` in the outgoing `update_add_htlc` to this value
* If final hop: MUST verify the received RGB amount matches expectations

Note: This TLV is encoded within the encrypted onion payload. Intermediate nodes
that do not support RGB cannot read or modify this value.

### TLV Type Selection

All TLV fields use type **827167** (`0x000C9F1F`), derived from
[SLIP-0044](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) RGB on
Bitcoin (testnet) coin type. Feature bit 826/827 echoes the same SLIP-0044 prefix.

BigSize encoding: `fe 00 0c 9f 1f` (5 bytes). Same cost as other bLIP TLV types
(e.g., `endorsed` at 106823, `extra_fee` at 65537).

### Commitment Transaction

When `channel_type` includes the `rgb_channel` feature bit (826), the commitment
transaction base weight includes an additional **172 weight units** for an
OP_RETURN output used by the RGB protocol for deterministic Bitcoin commitment
(DBC). This ensures both parties agree on fee calculations.

#### OP_RETURN Output Format

The OP_RETURN output is 43 serialized bytes × 4 = 172 weight units:

```
8 bytes output value (always 0)
1 byte scriptPubKey length varint (0x22 = 34)
1 byte OP_RETURN opcode (0x6a)
1 byte OP_PUSHBYTES_32 opcode (0x20)
32 bytes MPC commitment (mpc::Commitment, fixed 32 bytes)
──────
43 bytes × 4 = 172 weight units
```

#### Placement

The OP_RETURN output is always placed at the **last output index**, after all
standard outputs (to_local, to_remote, HTLCs, anchors) have been constructed
and sorted per BIP 69. Both holder and counterparty commitment transactions
include this output.

## Universality

This feature is NOT intended to be universal. RGB asset support is an
application-layer extension for nodes that choose to participate in the RGB
ecosystem. Standard Lightning nodes (CLN, LND, Eclair) can safely ignore all
RGB extensions:

- Unknown odd feature bits in `init` are ignored (BOLT #1)
- Unknown odd feature bits in `channel_announcement` are ignored (BOLT #7)
- Unknown odd TLV fields in wire messages are ignored (BOLT #1)
- Onion payload fields are encrypted and only visible to intended recipients
- Gossip messages with RGB data are relayed unmodified (signature covers all trailing data)

A node that does not support RGB will never accidentally open an RGB channel,
because `channel_type` negotiation requires explicit agreement (BOLT #2).

## Backwards Compatibility

All extensions use odd-numbered identifiers:

| Extension | Value | Parity | Standard node behavior |
|-----------|-------|--------|----------------------|
| Feature bit | 827 (in init/node/channel) | odd | Safely ignored |
| Feature bit | 826 (in channel_type) | even | Channel type rejected if unknown — correct behavior |
| TLV type | 827167 | odd | Safely ignored |

There are no backwards compatibility issues for standard Lightning nodes. The
extensions are fully additive and do not modify any existing BOLT behavior.

For RGB-enabled nodes, the commitment transaction includes an OP_RETURN output
(+172 weight units). This is negotiated via `channel_type` feature bit 826,
ensuring both peers use the same fee calculation.

## Reference Implementation

A reference implementation based on LDK (rust-lightning) is under development by
Bitlight Labs. The implementation will be made available upon public release.

TLV type and feature bit values are derived from
[SLIP-0044](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) RGB
coin type registration (827166/827167) by Dr. Maxim Orlovsky.