Skip to content

Commit c4151da

Browse files
committed
bLIP-57: Channel Lease Extensions (LSPS7)
1 parent 8b09c57 commit c4151da

File tree

1 file changed

+241
-0
lines changed

1 file changed

+241
-0
lines changed

blip-0057.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
```
2+
bLIP: 57
3+
Title: LSPS7: Channel Lease Extensions
4+
Status: Draft
5+
Author: Evan Kaloudis <[email protected]>
6+
Created: 2025-01-10
7+
License: MIT
8+
```
9+
10+
# Channel Lease Extensions (LSPS7)
11+
12+
LSPS7 requires [LSPS0](./blip-0050.md) and therefore [BOLT8](https://github.com/lightning/bolts/blob/master/08-transport.md) as a transport layer. The payment object structure is taken from [LSPS1][].
13+
14+
## Motivation
15+
16+
The goal of this specification is to provide a standardized LSP API for wallets to extend the lifetime of a channel purchased from an LSP.
17+
18+
## Copyright
19+
20+
This bLIP is licensed under the MIT license.
21+
22+
## Order Flow Overview
23+
24+
* Client calls `lsps7.get_extendable_channels` to get the LSP's options.
25+
* Client calls `lsps7.create_order` to create an order.
26+
* Client pays the order either on-chain or off-chain.
27+
* LSP extends the expiry time of the channel as soon as the payment is confirmed.
28+
29+
30+
## API
31+
32+
### 1. lsps7.get_extendable_channels
33+
34+
| JSON-RPC Method | lsps7.get_extendable_channels |
35+
|---------------- |----------- |
36+
| Idempotent | Yes |
37+
38+
39+
`lsps7.get_extendable_channels` is the entrypoint for each client using the API. It lists all options in a dictionary.
40+
41+
The client SHOULD call `lsps7.get_extendable_channels` first.
42+
43+
**Request** No parameters needed.
44+
45+
**Response**
46+
47+
```JSON
48+
{
49+
"extendable_channels": [
50+
{
51+
"original_order": {
52+
"id": "3c2ef2b-195f-0695-b72ef-3929b9138e04",
53+
"service": "LSPS1"
54+
},
55+
"extension_order_ids": [
56+
"142b3ef8-2eca-6135-7f74-7d1afda8b835",
57+
"39afg2a3-7cf7-f3b6-056e-43f0d5b61f3f"
58+
],
59+
"short_channel_id": "871428x964x0",
60+
"max_channel_extension_expiry_blocks": 300,
61+
"expiration_block": 839230
62+
}
63+
]
64+
}
65+
```
66+
67+
`extendable_channels` is an array of channels the LSP will allow you to extend the expiry of. The structure of the `extendable_channel` object can be found in section [3. Extendable Channel](#3-extendable-channel).
68+
69+
70+
**Errors** No additional errors are defined for this method.
71+
72+
### 2. lsps7.create_order
73+
74+
| JSON-RPC Method | lsps7.create_order |
75+
|-------------------- |------------------- |
76+
| Idempotent | No |
77+
78+
79+
The request is constructed depending on the client's needs.
80+
81+
**Request**
82+
83+
```json
84+
{
85+
"short_channel_id": "871428x964x0",
86+
"channel_extension_expiry_blocks": 144,
87+
"token": "",
88+
"refund_onchain_address": "bc1qvmsy0f3yyes6z9jvddk8xqwznndmdwapvrc0xrmhd3vqj5rhdrrq6hz49h"
89+
}
90+
```
91+
92+
- `short_channel_id` <[LSPS0.scid][]> Short Channel Identifier (SCID) of the channel to extend.
93+
- `channel_extension_expiry_blocks <uint32>` How long to extend the lease of the channel in block time.
94+
- MUST be 1 or greater.
95+
- MUST be below or equal to `max_channel_extension_expiry_blocks` returned from the `get_extendable_channels` call.
96+
- `token <string>` Field for arbitrary data like a coupon code or a authentication token.
97+
- Client MAY omit this field.
98+
- `refund_onchain_address <string>` <LSPS0.onchain_address> Address where the LSP will send the funds if the order fails.
99+
- Client MAY omit this field.
100+
101+
**Response**
102+
103+
```json
104+
{
105+
"order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c",
106+
"channel_extension_expiry_blocks": 144,
107+
"new_channel_expiry_blocks": 839374,
108+
"token": "",
109+
"created_at": "2012-04-23T18:25:43.511Z",
110+
"order_state": "CREATED",
111+
"payment": {
112+
"bolt11": {
113+
"state": "EXPECT_PAYMENT",
114+
"expires_at": "2015-01-25T19:29:44.612Z",
115+
"fee_total_sat": "8888",
116+
"order_total_sat": "2008888",
117+
"invoice" : "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05"
118+
},
119+
"onchain": {
120+
"state": "EXPECT_PAYMENT",
121+
"expires_at": "2015-01-25T19:29:44.612Z",
122+
"fee_total_sat": "9999",
123+
"order_total_sat": "2009999",
124+
"address" : "bc1p5uvtaxzkjwvey2tfy49k5vtqfpjmrgm09cvs88ezyy8h2zv7jhas9tu4yr",
125+
"min_fee_for_0conf": 253,
126+
"min_onchain_payment_confirmations": 0,
127+
"refund_onchain_address": "bc1qvmsy0f3yyes6z9jvddk8xqwznndmdwapvrc0xrmhd3vqj5rhdrrq6hz49h"
128+
}
129+
},
130+
"channel": {
131+
"original_order": {
132+
"id": "3c2ef2b-195f-0695-b72ef-3929b9138e04",
133+
"service": "LSPS1"
134+
},
135+
"extension_order_ids": [
136+
"142b3ef8-2eca-6135-7f74-7d1afda8b835",
137+
"39afg2a3-7cf7-f3b6-056e-43f0d5b61f3f"
138+
],
139+
"short_channel_id": "871428x964x0",
140+
"max_channel_extension_expiry_blocks": 300,
141+
"expiration_block": 839230
142+
},
143+
}
144+
```
145+
146+
- `order_id <string>` Id of this specific order.
147+
- MUST be unique.
148+
- MUST be at most 64 characters long.
149+
- SHOULD be a valid [UUID version 4](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)) (aka random UUID).
150+
- `funding_confirms_within_blocks <uint16>` Mirrored from the request.
151+
- `token <string>` Mirrored from the request.
152+
- MUST be an empty string if the token was not provided.
153+
- `created_at` <[LSPS0.datetime][]> Datetime when the order was created.
154+
- `order_state <string enum>` Current state of the order.
155+
- `CREATED` Order has been created. Default value.
156+
- `COMPLETED` LSP has published funding transaction.
157+
- `FAILED` Order failed.
158+
- `payment <object>` Contains everything about payments, see [4. Payment](#4-payment).
159+
- `channel <object>` Contains information about the channel, see [3. Extendable Channel](#3-extendable-channel).
160+
161+
162+
**Client**
163+
- SHOULD validate that `channel_extension_expiry_blocks` + `channel_extension_expiry_blocks` = `new_channel_expiry_blocks`.
164+
- SHOULD validate the `fee_total_sat` is reasonable.
165+
- MAY abort the flow here.
166+
167+
**Errors**
168+
169+
| Code | Message | Data | Description |
170+
| ---- | ------- | ----------- | ---- |
171+
| -32602 | Invalid params | {"property": %invalid_property%, "message": %human_message% } | Invalid method parameter(s). |
172+
| 001 | Client rejected | {"message": %human_message% } | [LSPS0.client_rejected_error][] |
173+
| 100 | Option mismatch | {"property": %option_mismatch_property%, "message": %human_message% } | The order doesnt match the options defined in `lsps7.get_extendable_channels` channel object. |
174+
175+
176+
- LSP MUST validate the order against the options defined in the `lsps7.get_extendable_channels` channel object. LSP MUST return an `100` error in case of a mismatch.
177+
- `%option_mismatch_property%` MUST be one of the fields in the `lsps7.get_extendable_channels` channel object.
178+
- Example: `{ "property": "max_channel_extension_expiry_blocks" }`.
179+
180+
- LSP MUST validate the request fields. LSP MUST return a `-32602` error in case of an invalid request field.
181+
- `%invalid_property%` MUST be one of the fields in the request body. MUST use `.` to separate nested fields.
182+
- Example: `{ "property": "channel_extension_expiry_blocks", "message": "Not an integer" }`.
183+
184+
- LSP MUST validate the `token` field and return an error if the token is invalid.
185+
186+
> **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.
187+
188+
> **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.
189+
190+
191+
### 2.1 lsps7.get_order
192+
193+
| JSON-RPC Method | lsps7.get_order |
194+
|---------------- |---------------- |
195+
| Idempotent | Yes |
196+
197+
The client MAY check the current status of the order at any point.
198+
199+
**Request**
200+
201+
```json
202+
{
203+
"order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c"
204+
}
205+
```
206+
207+
**Response** is the same as defined in `lsps7.create_order`.
208+
209+
**Errors**
210+
211+
| Code | Message | Data | Description |
212+
| ------ | --------- | ------- | ----------------------------------------------------- |
213+
| 101 | Not found | {} | Order with the requested order_id has not been found. |
214+
215+
216+
### 3. Extendable channel
217+
218+
The `extendable_channel` object returned in `lsps7.get_extendable_channels`, `lsps7.create_order`, and `lsps7.get_order`, has the following properties:
219+
220+
- `original_order <object>` An *optional* property for the original order for the channel lease, including the `id <string>` to identify the order and the `service <string>` the purchase occured on.
221+
- `extension_order_ids <string[]>` An *optional* list of order IDs for each time the channel lease has been extended.
222+
- `short_channel_id` <[LSPS0.scid][]> Short Channel Identifier (SCID) of the channel.
223+
- `max_channel_extension_expiry_blocks <uint32>` The maximum number of blocks a channel can be leased for.
224+
- `expiration_block <uint32>` The block height at which the channel lease will expiry. May be marked as 0 if the user opened the channel to the LSP, and the LSP has no obligation to keep open.
225+
- MUST be 0 or greater.
226+
227+
> **Rationale `original_order`** The client MAY want to look up the original order for reference.
228+
229+
> **Rationale `extension_order_ids`** The client MAY want to look up any one of the previous extensions orders for reference.
230+
231+
### 4. Payment
232+
233+
The `payment` object returned by `lsps7.create_order` and `lsps7.get_order`, mirrors the formatting of [LSPS1.payment][].
234+
235+
236+
[LSPS0.onchain_address]: ./blip-0050.md#link-lsps0onchain_address
237+
[LSPS0.datetime]: ./blip-0050.md#link-lsps0datetime\
238+
[LSPS0.scid]: ./blip-0050.md#link-lsps0scid
239+
[LSPS0.client_rejected_error]: ./blip-0050.md#link-lsps0client_rejected_error
240+
[LSPS1]: ./blip-0051.md
241+
[LSPS1.payment]: ./blip-0051.md#3-payment

0 commit comments

Comments
 (0)