# 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`.