# Liquidity Ads Case Study
## Metadata
**Status**:: #x
**Zettel**:: #zettel/literature
**Created**:: [[2025-11-19]]
**Reference**:: [lightning/bolts#1153](https://github.com/lightning/bolts/pull/1153)
## Overview
- Sellers advertise available liquidity (funding rates + supported payment_types) via `node_announcement` TLVs (`option_will_fund / will_fund_rates`).
- A buyer picks a seller, chooses a `funding_rate` and `payment_type`, then includes a `request_funding / request_funds` TLV in the `open_channel2` message to initiate channel creation.
- The seller verifies the request matches its advertised rates and supported `payment_type`. If accepted it replies with `provide_funding / will_fund` containing funding_script + signature committing to the terms.
- The interactive transaction construction proceeds; fees are collected according to the chosen `payment_type` (today: `from_channel_balance` — the buyer’s contribution is adjusted so the seller receives the fee in channel balance). The channel is then completed.
- The buyer and seller can re-negotiate the funding options in the funding rbf (replace by fee) flow.
- Extensibility: `payment_type` is TLV-encoded so new payment methods can be added later without changing core messages.
## Key new TLVs
### `option_will_fund`
Sellers advertise their rates and payment types using `will_fund_rates` in `node_announcement`:
* `funding_rates`: List of offered funding rates.
* `payment_types`: List of supported payment methods.
Each funding rate includes following fields:
- Seller's accepted funding amount range.
- Base fee paid to seller.
- Proportional fee paid to seller based on the seller's funding amount.
- Creation fee paid to seller when the buyer is creating a new channel.
- Portion of the on-chain tx fee that the buyer needs to pay.
### `request_funding`
Buyers select a specific rate and a `payment_type` offered by the seller
and use `request_funding` in `open_channel2` or `tx_init_rbf` to purchase that liquidity.
- `requested_sats`: Seller funding amount
* `funding_rate`: The funding rate selected from `option_will_fund.funding_rates`
* `payment_type`: The payment method selected from `option_will_fund.payment_types`
### `provide_funding`
Sellers accept the purchase with `provide_funding` in `accept_channel2` or `tx_ack_rbf`.
- `funding_rate`: Accepted funding rate
- `funding_script`: Seller funding assets source address
- `signature`: Signature on `SHA256("liquidity_ads_purchase" || funding_rate || funding_script)`. It binds the seller to the exact `funding_rate` and the `funding_script`. The buyer gets proof the seller committed to those parameters.
## Funding Process
The liquidity purchase negotiation succeeds when buyers have validated and accepted the `accept_channel2` or `tx_ack_rbf` containing the TLV `provide_funding`.
When negotiation succeeds, each side funds the on-chain inputs/outputs they agreed in the interactive negotiation.
Minimum funds that the buyer must contribute:
- b1: Amount declared in `open_channel2.funding_satoshis`
- b2: Funding fee paid to seller.
- b3: Buyer's portion of the funding fee paid to miner for on-chain involved transactions.
Minimum funds that the seller must contribute:
- s1: Amount declared in `accept_channel2.funding_satoshis`
- s2: Seller's portion of the funding fee paid to miner for on-chain involved transactions.
When the payment method is `from_channel_balance`. The balance distribution of the new channel is:
- Buyer: b1
- Seller: s1 + b2
See an example in [BOLT proposal](https://github.com/t-bast/bolts/blob/extensible-liquidity-ads/07-routing-gossip.md#liquidity-ads)
## Alternative Paths
- Seller MAY fail the channel creation negotiation if `request_funding` does not match a rate it advertised. Or seller MAY reject the `request_funding` proposal.
- Seller MAY reject the `request_funding` proposal by not replying `provide_funding`. For example, when seller has no enough liquidity to fulfill the proposal. This leaves buyer to decide whether to continue creating the channel.
- Buyer MAY fail the negotiation if:
- It sent `request_funding` and `provide_funding` is not set.
- It sent `request_funding` and `provide_funding` is et and `accept_channel2.funding_satoshis` is smaller than requested.
- Buyer MUST fail the negotiation if:
- It did not sent `request_funding` and `provide_funding` is set.
- `provide_funding` is set but does not match the proposed `request_funding`
## Visual Flow
```mermaid
sequenceDiagram
participant Buyer
participant Seller
Note over Buyer,Seller: Advertising Phase
Seller->>Buyer: node_announcement(option_will_fund)
Note over Buyer,Seller: Channel Initiation
Buyer->>Seller: open_channel2(request_funding)
alt Seller accepts request
Seller->>Buyer: accept_channel2(provide_funding)
alt Success
Note over Buyer,Seller: Funding Process
else Buyer fails channel creation
Buyer-xSeller: error
end
else Seller rejects liquidity purchase
Seller-xBuyer: accept_channel2(no provide_funding)
else Seller fails channel creation
Seller-xBuyer: error
end
```
## Proposal for Fiber
- Add a feature bit to indicate whether a node supports liquidity ads.
- Add `NodeAnnouncement2` and make it extensible to add new custom records.
- Add a new custom record in `NodeAnnouncement2` to advertise liquidity ads.
- Add `OpenChannel2` and make it extensible to add new custom records.
- Add a new custom record in `OpenChannel2` to propose the liquidity purchase.
- Add `AcceptChannel2` and make it extensible to add new custom records.
- Add a new custom record in `AcceptChannel2` to propose the liquidity purchase.
- Make `TxInitRBF` and `TxAckRBF` extensible to add new custom records. They are not used yet so it is safe to modify the schema.
- Allow configure liquidity ads via config file.
- Expose `request_funding` parameter in the `open_channel` RPC.
- Expose `accept_funding` parameter in the `accept_channel` RPC.
- Add logic to verify `request_funding` and `accept_funding`
- Add logic to automatically accept `request_funding` proposal.
- Update funding process to support liquidity ads.
- Update funding process to support payment method `from_channel_balance`.