bLIP: 51
Title: LSPS1: Channel Requests
Status: Active
Author: Severin Bühler <severin@synonym.to>
Created: 2024-12-02
License: MIT
The goal of this specification is to provide a standardized LSP API for wallets to purchase a channel from an LSP directly.
LSPS1 depends on the LSPS0/bLIP 50 and therefore BOLT8 as a transport layer.
A reference implementation of this protocol can be found as part of the
lightning-liquidity
crate.
This specification uses data types defined in LSPS0: Common Schemas.
LSP
is the API provider. Client
is the client of the API.
client_balance
are the funds on the client side. lsp_balance
are the funds on the LSP side.
The LSP is allowed to overprovision channels/on-chain-payments/on-chain-fees as long as it benefits the client.
Rationale The LSP may need to "bin" UTXOs.
LSP will return errors according to the JSON-RPC 2.0 specification (see LSPS0 Error Handling).
In general, LSPS1 is developed on the basis that the client trust the LSP to deliver the promised goods. Channel purchases are not atomic and therefore the client risks not getting the promised goods if the LSP is malicious.
- Client calls
lsps1.get_info
to get the LSP's options. - Client calls
lsps1.create_order
to create an order. - Client pays the order either on-chain or off-chain.
- LSP opens the channel as soon as they payment is confirmed.
- Channel open failed: LSP refunds the client.
JSON-RPC Method | lsps1.get_info |
---|---|
Idempotent | Yes |
lsps1.get_info
is the entrypoint for each client using the API. It lists all options in a dictionary.
- The LSP SHOULD NOT change the values in
lsps1.get_info
more than once per day.
Rationale Change frequency The LSP should not change values in
lsps1.get_info
too frequently. Lightning Explorers may scrape these values and provide an overview of all LSPs. If the values change too frequently, Lightning Explorers may not be able to keep up with the changes. Changing them a maximum of once a day gives explorer enough time to scrape. Once a day has been chosen as it is a similar rate-limit that core-lightning puts on the lightning gossip.
The client MUST call lsps1.get_info
first.
Request No parameters needed.
Response
{
"min_required_channel_confirmations": 0,
"min_funding_confirms_within_blocks" : 6,
"supports_zero_channel_reserve": true,
"max_channel_expiry_blocks": 20160,
"min_initial_client_balance_sat": "20000",
"max_initial_client_balance_sat": "100000000",
"min_initial_lsp_balance_sat": "0",
"max_initial_lsp_balance_sat": "100000000",
"min_channel_balance_sat": "50000",
"max_channel_balance_sat": "100000000"
}
min_required_channel_confirmations <uint16>
Smallest number of confirmations needed for the LSP to accept a channel as confirmed and sends channel_ready (previouslyfunding_locked
).- MAY be 0 to allow 0conf channels.
- MUST be 0 or greater.
min_funding_confirms_within_blocks <uint16>
Smallest number of blocks in which the LSP can confirm the funding transaction.- MUST be 1 or greater
supports_zero_channel_reserve <boolean>
Indicates if the LSP supports zeroreserve.max_channel_expiry_blocks <uint32>
The maximum number of blocks a channel can be leased for.- MUST be 1 or greater.
min_initial_client_balance_sat
<LSPS0.sat> Minimum number of satoshi that the client MUST request.- MUST be 0 or greater.
max_initial_client_balance_sat
<LSPS0.sat> Maximum number of satoshi that the client MUST request.- MUST be 0 or greater.
min_initial_lsp_balance_sat
<LSPS0.sat> Minimum number of satoshi that the LSP will provide to the channel.- MUST be 0 or greater.
max_initial_lsp_balance_sat
<LSPS0.sat> Maximum number of satoshi that the LSP will provide to the channel.- MUST be 0 or greater.
min_channel_balance_sat
<LSPS0.sat> Minimal channel size.- MUST be 0 or greater.
max_channel_balance_sat
<LSPS0.sat> Maximum channel size.- MUST be 0 or greater.
Every min/max
options pair MUST ensure that min <= max
.
Errors No additional errors are defined for this method.
JSON-RPC Method | lsps1.create_order |
---|---|
Idempotent | No |
The request is constructed depending on the client's needs.
Request
{
"lsp_balance_sat": "5000000",
"client_balance_sat": "2000000",
"required_channel_confirmations" : 0,
"funding_confirms_within_blocks": 6,
"channel_expiry_blocks": 144,
"token": "",
"refund_onchain_address": "bc1qvmsy0f3yyes6z9jvddk8xqwznndmdwapvrc0xrmhd3vqj5rhdrrq6hz49h",
"announce_channel": true
}
lsp_balance_sat
<LSPS0.sat> How many satoshi the LSP will provide on their side.- MUST be 1 or greater.
- MUST be equal or below
base_api.max_initial_lsp_balance_sat
. - MUST be equal or greater
base_api.min_initial_lsp_balance_sat
.
client_balance_sat
<LSPS0.sat> How many satoshi the client will provide on their side. The client send these funds to the LSP. The LSP will push these funds back to the client.- MUST be 0 or greater.
- MUST be below or equal
base_api.max_initial_client_balance_sat
. - MUST be greater or equal
base_api.min_initial_client_balance_sat
.
required_channel_confirmations <uint16>
Number of confirmations the funding tx must have before the LSP sendschannel_ready
- MUST be greater or equal to
base_api.min_required_channel_confirmations
- LSP MAY always confirm the channel faster than requested
- MUST be greater or equal to
funding_confirms_within_blocks <uint16>
The maximum number of blocks the client wants to wait until the funding transaction is confirmed.- MUST be greater or equal to
base_api.min_funding_confirms_within_blocks
- LSP MAY always confirm the funding transaction faster than requested.
- MUST be greater or equal to
channel_expiry_blocks <uint32>
How long the channel is leased for in block time.- MUST be 1 or greater.
- MUST be below or equal
base_api.max_channel_expiry_blocks
.
token <string>
Field for arbitrary data like a coupon code or a authentication token.- Client MAY omit this field.
refund_onchain_address
<LSPS0.onchain_address> Address where the LSP will send the funds if the order fails.- Client MAY omit this field.
- LSP MUST disable on-chain payments if the client omits this field.
announce_channel <boolean>
If the channel should be announced to the network (also known as public/private channels).
Rationale
client_balance_sat
Client MAY want to have initial spending balance on their wallet or start with a balanced channel.
The client MUST check if option_support_large_channel is enabled before they order a channel larger than 16,777,216 satoshi.
Response
{
"order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c",
"lsp_balance_sat": "5000000",
"client_balance_sat": "2000000",
"required_channel_confirmations" : 0,
"funding_confirms_within_blocks": 1,
"channel_expiry_blocks": 12,
"token": "",
"created_at": "2012-04-23T18:25:43.511Z",
"announce_channel": true,
"order_state": "CREATED",
"payment": {
"bolt11": {
"state": "EXPECT_PAYMENT",
"expires_at": "2015-01-25T19:29:44.612Z",
"fee_total_sat": "8888",
"order_total_sat": "2008888",
"invoice" : "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05"
},
"onchain": {
"state": "EXPECT_PAYMENT",
"expires_at": "2015-01-25T19:29:44.612Z",
"fee_total_sat": "9999",
"order_total_sat": "2009999",
"address" : "bc1p5uvtaxzkjwvey2tfy49k5vtqfpjmrgm09cvs88ezyy8h2zv7jhas9tu4yr",
"min_fee_for_0conf": 253,
"min_onchain_payment_confirmations": 0,
"refund_onchain_address": "bc1qvmsy0f3yyes6z9jvddk8xqwznndmdwapvrc0xrmhd3vqj5rhdrrq6hz49h"
}
},
"channel": null
}
order_id <string>
Id of this specific order.- MUST be unique.
- MUST be at most 64 characters long.
- SHOULD be a valid UUID version 4 (aka random UUID).
lsp_balance_sat
<LSPS0.sat> Mirrored from the request.client_balance_sat
<LSPS0.sat> Mirrored from the request.required_channel_confirmations <uint16>
Mirrored from the request.funding_confirms_within_blocks <uint16>
Mirrored from the request.channel_expiry_blocks <uint32>
Mirrored from the request.token <string>
Mirrored from the request.- MUST be an empty string if the token was not provided.
announce_channel <boolean>
Mirrored from the request.created_at
<LSPS0.datetime> Datetime when the order was created.order_state <string enum>
Current state of the order.CREATED
Order has been created. Default value.COMPLETED
LSP has published funding transaction.FAILED
Order failed.
payment <object>
Contains everything about payments, see 3. Payment.channel <object or null>
Contains information about the channel, see 4 Channel.- MUST be
null
if the channel funding transaction is not published yet.
- MUST be
Client
- SHOULD validate the
fee_total_sat
is reasonable. - SHOULD validate
fee_total_sat
+client_balance_sat
=order_total_sat
. - MAY abort the flow here.
Errors
Code | Message | Data | Description |
---|---|---|---|
-32602 | Invalid params | {"property": %invalid_property%, "message": %human_message% } | Invalid method parameter(s). |
001 | Client rejected | {"message": %human_message% } | LSPS0.client_rejected_error |
100 | Option mismatch | {"property": %option_mismatch_property%, "message": %human_message% } | The order doesnt match the options defined in lsps1.get_info.options . |
-
LSP MUST validate the order against the options defined in
lsps1.get_info.options
. LSP MUST return an100
error in case of a mismatch.%option_mismatch_property%
MUST be one of the fields inlsps1.get_info.options
.- Example:
{ "property": "min_initial_client_balance_sat" }
.
-
LSP MUST validate the request fields. LSP MUST return a
-32602
error in case of an invalid request field.%invalid_property%
MUST be one of the fields in the request body. MUST use.
to separate nested fields.- Example:
{ "property": "announce_channel", "message": "Not a boolean" }
.
-
LSP MUST validate the
token
field and return an error if the token is invalid.
Rationale
token
validation The client should be informed if the token is invalid. Ignoring the invalid token and creating an order without the potentially discount or other side effect is not good UX. Ignoring the invalid token will also NOT prevent anybody bruteforcing the token because the client will still detect if the LSP has given a discount.
Rationale Client rejected LSPs can reject a client for example for misbehaviour. LSPs can reject a node on two levels: Prevent a peer connection OR disable order creation. Preventing a peer connection might not work in case you still want to allow other functions to keep working, for example an existing channel.
JSON-RPC Method | lsps1.get_order |
---|---|
Idempotent | Yes |
The client MAY check the current status of the order at any point.
Request
{
"order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c"
}
Response is the same as defined in lsps1.create_order
.
Errors
Code | Message | Data | Description |
---|---|---|---|
101 | Not found | {} | Order with the requested order_id has not been found. |
This section describes the payment
object returned by lsps1.create_order
and lsps1.get_order
.
{
"bolt11": {
"state" : "EXPECT_PAYMENT",
"expires_at": "2025-01-01T00:00:00Z",
"fee_total_sat": "8888",
"order_total_sat": "200888",
"invoice": "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05"
},
"onchain": {
"state": "EXPECT_PAYMENT",
"expires_at": "2025-01-01T00:00:00Z",
"fee_total_sat": "9999",
"order_total_sat": "200999",
"address": "bc1p5uvtaxzkjwvey2tfy49k5vtqfpjmrgm09cvs88ezyy8h2zv7jhas9tu4yr",
"min_onchain_payment_confirmations": 1,
"min_fee_for_0conf": 253,
"refund_onchain_address": "bc1qvmsy0f3yyes6z9jvddk8xqwznndmdwapvrc0xrmhd3vqj5rhdrrq6hz49h"
}
}
The Client MUST ignore unkown payment options.
The LSP MAY omit payment options.
Rationale: E.g.: The LSP might not support onchain payments.
Rationale: Fees and expiry dates are defined on the level of the payment-option. This allows an LSP to provide the cheapest service for each payment option.
An LSP might choose to have a lower fee for lightning than for onchain payments. Onchain payments might
- be more costly for the LSP as they might have to spend a small UTXO in the future
- be more risky for the LSP in case of 0-conf channels
- require longer confirmation times than a lightning payment. (Risk of changing on-chain fees)
{
"state" : "EXPECT_PAYMENT",
"expires_at": "2025-01-01T00:00:00Z",
"fee_total_sat": "8888",
"order_total_sat": "200888",
"invoice": "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05"
}
state
EXPECT_PAYMENT
Payment expected.HOLD
Lighting payment arrived, preimage NOT released.PAID
When the has been preimage releasedREFUNDED
Lightning payment has been refunded.This state has been deprecated.CANCELLED
Lightning payment has been cancelled.- The LSP MUST use
REFUNDED
for a cancelled or refunded invoice. - Earlier versions of this spec MAY still use this state.
- Clients SHOULD still support this state for backwards compatibility.
- The LSP MUST use
expires_at
<LSPS0.datetime> The timestamp at which the payment option for this order expiresfee_total_sat
<LSPS0.sat> The total fee the LSP will charge to open this channel in satoshi.order_total_sat
<LSPS0.sat> What the client needs to pay in total to open the requested channel.- MUST be the
fee_total_sat
plus theclient_balance_sat
requested in satoshi.
- MUST be the
invoice <string>
- MUST be a Lightning BOLT 11 invoice for the number of
order_total_sat
. - Invoice MUST be a HOLD invoice.
- MUST be at most 2048 characters long.
- MUST be a Lightning BOLT 11 invoice for the number of
Client
- MAY pay the
invoice
. - MAY pull
lsps1.get_order
to check the success of the payment. - The client gets refunded automatically in case the channel open failed, the order expires, or just before the payment times out.
LSP
- MUST change the
payment.state
toHOLD
when the payment arrived. - If the channel has been opened successfully
- MUST release the preimage and therefore complete the payment.
- MUST set the
payment.state
toPAID
.
- If the channel failed to open or the order expired or shortly before the payment times out:
- MUST reject the payment.
- MUST set the
payment.state
toCANCELLED
.
Onchain payments dictionary MUST be omitted if the client didn't provide a refund_onchain_address
and/or the LSP disabled onchain payments.
{
"state": "EXPECT_PAYMENT",
"expires_at": "2025-01-01T00:00:00Z",
"fee_total_sat": "9999",
"order_total_sat": "200999",
"address": "bc1p5uvtaxzkjwvey2tfy49k5vtqfpjmrgm09cvs88ezyy8h2zv7jhas9tu4yr",
"min_onchain_payment_confirmations": 1,
"min_fee_for_0conf": 253,
"refund_onchain_address": "bc1qvmsy0f3yyes6z9jvddk8xqwznndmdwapvrc0xrmhd3vqj5rhdrrq6hz49h"
}
state
EXPECT_PAYMENT
: Payment expectedPAID
: Onchain payment is confirmedREFUNDED
: Onchain payment has been refunded
expires_at
<LSPS0.datetime> The timestamp at which the payment option for this order expiresfee_total_sat
<LSPS0.sat> The total fee the LSP will charge to open this channel in satoshi.order_total_sat
<LSPS0.sat> What the client needs to pay in total to open the requested channel.- MUST be the
fee_total_sat
plus theclient_balance_sat
requested in satoshi.
- MUST be the
address
<LSPS0.onchain_address> On-chain address the client can pay theorder_total_sat
tomin_onchain_payment_confirmations <uint16>
Minimum number of block confirmations that are required for the on-chain payment to be considered confirmed.- MUST be equal or greater than
options.min_onchain_payment_confirmations
.
- MUST be equal or greater than
min_fee_for_0conf <LSPS0.onchain_fee>
Fee rate for on-chain payment in case the client wants the payment to be confirmed without a confirmation.- MUST be
null
or absent ifmin_onchain_payment_confirmations
is greater than 0. - SHOULD choose a high enough fee to lower the risk of a double spend.
- MUST be
refund_onchain_address
<LSPS0.onchain_address> Client supplied refund address.- LSP SHOULD set this to mirror the order creation request.
- LSP MAY omit this field as it wasn't present in earlier versions of this specification.
Rationale
min_onchain_payment_confirmations
The main risk for an LSP is that the client pays the on-chain payment and then double spends the transaction. This is especially critical in case the client requested a highclient_balance
. Opening a 0conf channel alone has no risk attached to it IF the on-chain payment is confirmed. Therefore, the LSP can mitigate this risk by waiting for a certain number of block confirmations before opening the channel.
Rationale
min_fee_for_0conf
The client MAY want to have instant confirmation of the on-chain payment. The LSP can mitigate the risk of a double spend by requiring a high fee rate. The client can then decide if he wants to pay the high fee rate or wait for the on-chain payment to be confirmed once.
Client
- MUST pay
order_total_sat
toaddress
. - MAY pull
lsps1.get_order
to check the success of the payment.
LSP Payment confirmation
- MUST monitor the blockchain and update
onchain_payment
. - IF
min_onchain_payment_confirmations
is 0 and incoming transaction fee is greater thanmin_fee_for_0conf
:- SHOULD set the transaction as confirmed.
- IF
min_onchain_payment_confirmations
is equal or greater than 1:- SHOULD set the transaction as confirmed after
min_onchain_payment_confirmations
confirmations.
- SHOULD set the transaction as confirmed after
- MAY always set the transaction as confirmed before
min_onchain_payment_confirmations
confirmations. - In rare circumstances, MAY take longer than
min_onchain_payment_confirmations
confirmations in case the LSP doesn't trust the transaction. - MUST always set the transaction as confirmed after 6 block confirmations.
LSP State change
- MUST change the
payment.state
toPAID
when the payment for the order is confirmed. - If the order expired and the channel has NOT been opened, OR the channel open failed.
- MUST refund the client to
refund_onchain_address
.- The number of satoshi to refund
- MUST be
order_total_sat
MINUS transaction size * onchain fee rate. The LSP MUST choose a reasonable fee rate. - MAY overprovision.
- MUST be
- The LSP MUST bump the fee in case the transaction doesn't resolve within 6 hours.
- The number of satoshi to refund
- MUST set the payment
payment.state
toREFUNDED
.
- MUST refund the client to
0conf risk management
Every LSP that accepts 0conf transactions is responsible to do their own risk management. min_onchain_payment_confirmations
and min_fee_for_0conf
are the risk management tools the LSP has. The main risk lies in the fact that the client can double spend the on-chain payment. Opening a 0conf channel is not risky for the LSP anymore if the LSP is sure of the on-chain payment.
min_onchain_payment_confirmations
and min_fee_for_0conf
are the best estimates of the LSP makes at the time of the order creation. These estimates MAY change over time so the LSP MAY confirm a transaction earlier or later. Therefore, the client MUST NOT rely on the LSP confirming the transaction within the given time frame.
Channel object
{
"funded_at": "2012-04-23T18:25:43.511Z",
"funding_outpoint": "0301e0480b374b32851a9462db29dc19fe830a7f7d7a88b81612b9d42099c0ae:0",
"expires_at": "2012-04-23T18:25:43.511Z"
}
channel <object>
Contains channel information.- MUST be
null
if the channel opening transaction has not been published yet. funded_at
<LSPS0.datetime> Datetime when the funding transaction has been published.funding_outpoint
<LSPS0.outpoint> Outpoint of the funding transaction.expires_at
<LSPS0.datetime> Earliest datetime when the channel MAY be closed by the LSP.- MUST respect
channel_expiry_blocks
. - MAY overprovision.
- MUST respect
- MUST be
The LSP MUST open the channel under the following conditions:
payment.state
isHOLD
(lightning) orPAID
(on-chain).
LSP
- MUST wait for a peer connection before attempting a channel open.
- MUST attempt a channel open.
- MUST respect the
announce_channel
flag. - MUST open the channel with at least a capacity of
lsp_balance_sat
+client_balance_sat
.- MAY overprovision.
- MUST push
client_balance_sat
to the client.- MAY overprovision.
- MUST use a high enough on-chain fee rate to ensure the funding transaction confirms within `funding_confirms_within_blocks after the client paid the order.
- MAY overprovision.
- MUST respect the
- MUST send
channel_ready
after the funding transaction hasrequired_channel_confirmations
. - MUST allow zero channel reserves if
supports_zero_channel_reserve
.
In case the channel open succeeds
- MUST set
order_state
toCOMPLETED
. - MUST update the channel object.
In case the channel open failed
- MUST set
order_state
toFAILED
. - MUST issue a refund.
LSP
- MAY open channels in batches, opening multiple channels in one transaction.
- The LSP MUST still ensure that the funding transaction gets confirmed within
funding_confirms_within_blocks
blocks after the client payment completed.
- The LSP MUST still ensure that the funding transaction gets confirmed within
For orders where required_channel_confirmations = 0
the LSP MUST attempt to open the channel immediately after receiving the payment.
Rationale
funding_confirms_within_blocks
We usefunding_confirms_within_blocks
instead offee_rate
to allow the LSP to batch channel funding transactions. For example, if a client orders a channel within five blocks, the LSP may wait to publish the funding transaction for three blocks to batch channel openings and add a fee to the funding transaction to ensure it confirms within two blocks.