lightning_liquidity/lsps1/
msgs.rs

1// This file is Copyright its original authors, visible in version control
2// history.
3//
4// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7// You may not use this file except in accordance with one or both of these
8// licenses.
9
10//! Message, request, and other primitive types used to implement bLIP-51 / LSPS1.
11
12use alloc::string::String;
13
14use core::convert::TryFrom;
15
16use crate::lsps0::ser::{
17	string_amount, string_offer, u32_fee_rate, unchecked_address, unchecked_address_option,
18	LSPSDateTime, LSPSMessage, LSPSRequestId, LSPSResponseError,
19};
20
21use bitcoin::{Address, FeeRate, OutPoint};
22
23use lightning::offers::offer::Offer;
24use lightning_invoice::Bolt11Invoice;
25
26use serde::{Deserialize, Serialize};
27
28pub(crate) const LSPS1_GET_INFO_METHOD_NAME: &str = "lsps1.get_info";
29pub(crate) const LSPS1_CREATE_ORDER_METHOD_NAME: &str = "lsps1.create_order";
30pub(crate) const LSPS1_GET_ORDER_METHOD_NAME: &str = "lsps1.get_order";
31
32pub(crate) const _LSPS1_CREATE_ORDER_REQUEST_INVALID_PARAMS_ERROR_CODE: i32 = -32602;
33#[cfg(lsps1_service)]
34pub(crate) const LSPS1_CREATE_ORDER_REQUEST_ORDER_MISMATCH_ERROR_CODE: i32 = 100;
35
36/// The identifier of an order.
37#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Hash)]
38pub struct LSPS1OrderId(pub String);
39
40/// A request made to an LSP to retrieve the supported options.
41///
42/// Please refer to the [bLIP-51 / LSPS1
43/// specification](https://github.com/lightning/blips/blob/master/blip-0051.md#1-lsps1get_info) for
44/// more information.
45#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
46#[serde(default)]
47pub struct LSPS1GetInfoRequest {}
48
49/// An object representing the supported protocol options.
50#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
51pub struct LSPS1Options {
52	/// The smallest number of confirmations needed for the LSP to accept a channel as confirmed.
53	pub min_required_channel_confirmations: u16,
54	/// The smallest number of blocks in which the LSP can confirm the funding transaction.
55	pub min_funding_confirms_within_blocks: u16,
56	/// Indicates if the LSP supports zero reserve.
57	pub supports_zero_channel_reserve: bool,
58	/// The maximum number of blocks a channel can be leased for.
59	pub max_channel_expiry_blocks: u32,
60	/// The minimum number of satoshi that the client MUST request.
61	#[serde(with = "string_amount")]
62	pub min_initial_client_balance_sat: u64,
63	/// The maximum number of satoshi that the client MUST request.
64	#[serde(with = "string_amount")]
65	pub max_initial_client_balance_sat: u64,
66	/// The minimum number of satoshi that the LSP will provide to the channel.
67	#[serde(with = "string_amount")]
68	pub min_initial_lsp_balance_sat: u64,
69	/// The maximum number of satoshi that the LSP will provide to the channel.
70	#[serde(with = "string_amount")]
71	pub max_initial_lsp_balance_sat: u64,
72	/// The minimal channel size.
73	#[serde(with = "string_amount")]
74	pub min_channel_balance_sat: u64,
75	/// The maximal channel size.
76	#[serde(with = "string_amount")]
77	pub max_channel_balance_sat: u64,
78}
79
80/// A response to a [`LSPS1GetInfoRequest`].
81#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
82pub struct LSPS1GetInfoResponse {
83	/// All options supported by the LSP.
84	#[serde(flatten)]
85	pub options: LSPS1Options,
86}
87
88/// A request made to an LSP to create an order.
89///
90/// Please refer to the [bLIP-51 / LSPS1
91/// specification](https://github.com/lightning/blips/blob/master/blip-0051.md#2-lsps1create_order)
92/// for more information.
93#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
94pub struct LSPS1CreateOrderRequest {
95	/// The order made.
96	#[serde(flatten)]
97	pub order: LSPS1OrderParams,
98	/// The address where the LSP will send the funds if the order fails.
99	#[serde(default)]
100	#[serde(skip_serializing_if = "Option::is_none")]
101	#[serde(with = "unchecked_address_option")]
102	pub refund_onchain_address: Option<Address>,
103}
104
105/// An object representing an bLIP-51 / LSPS1 channel order.
106#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
107pub struct LSPS1OrderParams {
108	/// Indicates how many satoshi the LSP will provide on their side.
109	#[serde(with = "string_amount")]
110	pub lsp_balance_sat: u64,
111	/// Indicates how many satoshi the client will provide on their side.
112	///
113	/// The client sends these funds to the LSP, who will push them back to the client upon opening
114	/// the channel.
115	#[serde(with = "string_amount")]
116	pub client_balance_sat: u64,
117	/// The number of confirmations the funding tx must have before the LSP sends `channel_ready`.
118	pub required_channel_confirmations: u16,
119	/// The maximum number of blocks the client wants to wait until the funding transaction is confirmed.
120	pub funding_confirms_within_blocks: u16,
121	/// Indicates how long the channel is leased for in block time.
122	pub channel_expiry_blocks: u32,
123	/// May contain arbitrary associated data like a coupon code or a authentication token.
124	pub token: Option<String>,
125	/// Indicates if the channel should be announced to the network.
126	pub announce_channel: bool,
127}
128
129/// A response to a [`LSPS1CreateOrderRequest`].
130#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
131pub struct LSPS1CreateOrderResponse {
132	/// The id of the channel order.
133	pub order_id: LSPS1OrderId,
134	/// The parameters of channel order.
135	#[serde(flatten)]
136	pub order: LSPS1OrderParams,
137	/// The datetime when the order was created
138	pub created_at: LSPSDateTime,
139	/// The current state of the order.
140	pub order_state: LSPS1OrderState,
141	/// Contains details about how to pay for the order.
142	pub payment: LSPS1PaymentInfo,
143	/// Contains information about the channel state.
144	pub channel: Option<LSPS1ChannelInfo>,
145}
146
147/// An object representing the status of an order.
148#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
149#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
150pub enum LSPS1OrderState {
151	/// The order has been created.
152	Created,
153	/// The LSP has opened the channel and published the funding transaction.
154	Completed,
155	/// The order failed.
156	Failed,
157}
158
159/// Details regarding how to pay for an order.
160#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
161pub struct LSPS1PaymentInfo {
162	/// A Lightning payment using BOLT 11.
163	pub bolt11: Option<LSPS1Bolt11PaymentInfo>,
164	/// A Lightning payment using BOLT 12.
165	pub bolt12: Option<LSPS1Bolt12PaymentInfo>,
166	/// An onchain payment.
167	pub onchain: Option<LSPS1OnchainPaymentInfo>,
168}
169
170/// A Lightning payment using BOLT 11.
171#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
172pub struct LSPS1Bolt11PaymentInfo {
173	/// Indicates the current state of the payment.
174	pub state: LSPS1PaymentState,
175	/// The datetime when the payment option expires.
176	pub expires_at: LSPSDateTime,
177	/// The total fee the LSP will charge to open this channel in satoshi.
178	#[serde(with = "string_amount")]
179	pub fee_total_sat: u64,
180	/// The amount the client needs to pay to have the requested channel openend.
181	#[serde(with = "string_amount")]
182	pub order_total_sat: u64,
183	/// A BOLT11 invoice the client can pay to have to channel opened.
184	pub invoice: Bolt11Invoice,
185}
186
187/// A Lightning payment using BOLT 12.
188#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
189pub struct LSPS1Bolt12PaymentInfo {
190	/// Indicates the current state of the payment.
191	pub state: LSPS1PaymentState,
192	/// The datetime when the payment option expires.
193	pub expires_at: LSPSDateTime,
194	/// The total fee the LSP will charge to open this channel in satoshi.
195	#[serde(with = "string_amount")]
196	pub fee_total_sat: u64,
197	/// The amount the client needs to pay to have the requested channel openend.
198	#[serde(with = "string_amount")]
199	pub order_total_sat: u64,
200	/// A BOLT12 offer the client can pay to have to channel opened.
201	#[serde(with = "string_offer")]
202	pub offer: Offer,
203}
204
205/// An onchain payment.
206#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
207pub struct LSPS1OnchainPaymentInfo {
208	/// Indicates the current state of the payment.
209	pub state: LSPS1PaymentState,
210	/// The datetime when the payment option expires.
211	pub expires_at: LSPSDateTime,
212	/// The total fee the LSP will charge to open this channel in satoshi.
213	#[serde(with = "string_amount")]
214	pub fee_total_sat: u64,
215	/// The amount the client needs to pay to have the requested channel openend.
216	#[serde(with = "string_amount")]
217	pub order_total_sat: u64,
218	/// An on-chain address the client can send [`Self::order_total_sat`] to to have the channel
219	/// opened.
220	#[serde(with = "unchecked_address")]
221	pub address: Address,
222	/// The minimum number of block confirmations that are required for the on-chain payment to be
223	/// considered confirmed.
224	pub min_onchain_payment_confirmations: Option<u16>,
225	/// The minimum fee rate for the on-chain payment in case the client wants the payment to be
226	/// confirmed without a confirmation.
227	#[serde(with = "u32_fee_rate")]
228	pub min_fee_for_0conf: FeeRate,
229	/// The address where the LSP will send the funds if the order fails.
230	#[serde(default)]
231	#[serde(skip_serializing_if = "Option::is_none")]
232	#[serde(with = "unchecked_address_option")]
233	pub refund_onchain_address: Option<Address>,
234}
235
236/// The state of a payment.
237///
238/// *Note*: Previously, the spec also knew a `CANCELLED` state for BOLT11 payments, which has since
239/// been deprecated and `REFUNDED` should be used instead.
240#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
241#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
242pub enum LSPS1PaymentState {
243	/// A payment is expected.
244	ExpectPayment,
245	/// A sufficient payment has been received.
246	Paid,
247	/// The payment has been refunded.
248	#[serde(alias = "CANCELLED")]
249	Refunded,
250}
251
252/// Details regarding a detected on-chain payment.
253#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
254pub struct LSPS1OnchainPayment {
255	/// The outpoint of the payment.
256	pub outpoint: String,
257	/// The amount of satoshi paid.
258	#[serde(with = "string_amount")]
259	pub sat: u64,
260	/// Indicates if the LSP regards the transaction as sufficiently confirmed.
261	pub confirmed: bool,
262}
263
264/// Details regarding the state of an ordered channel.
265#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
266pub struct LSPS1ChannelInfo {
267	/// The datetime when the funding transaction has been published.
268	pub funded_at: LSPSDateTime,
269	/// The outpoint of the funding transaction.
270	pub funding_outpoint: OutPoint,
271	/// The earliest datetime when the channel may be closed by the LSP.
272	pub expires_at: LSPSDateTime,
273}
274
275/// A request made to an LSP to retrieve information about an previously made order.
276///
277/// Please refer to the [bLIP-51 / LSPS1
278/// specification](https://github.com/lightning/blips/blob/master/blip-0051.md#21-lsps1get_order)
279/// for more information.
280#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
281pub struct LSPS1GetOrderRequest {
282	/// The id of the order.
283	pub order_id: LSPS1OrderId,
284}
285
286/// An enum that captures all the valid JSON-RPC requests in the bLIP-51 / LSPS1 protocol.
287#[derive(Clone, Debug, PartialEq, Eq)]
288pub enum LSPS1Request {
289	/// A request to learn about the options supported by the LSP.
290	GetInfo(LSPS1GetInfoRequest),
291	/// A request to create a channel order.
292	CreateOrder(LSPS1CreateOrderRequest),
293	/// A request to query a previously created channel order.
294	GetOrder(LSPS1GetOrderRequest),
295}
296
297/// An enum that captures all the valid JSON-RPC responses in the bLIP-51 / LSPS1 protocol.
298#[derive(Clone, Debug, PartialEq, Eq)]
299pub enum LSPS1Response {
300	/// A successful response to a [`LSPS1GetInfoRequest`].
301	GetInfo(LSPS1GetInfoResponse),
302	/// An error response to a [`LSPS1GetInfoRequest`].
303	GetInfoError(LSPSResponseError),
304	/// A successful response to a [`LSPS1CreateOrderRequest`].
305	CreateOrder(LSPS1CreateOrderResponse),
306	/// An error response to a [`LSPS1CreateOrderRequest`].
307	CreateOrderError(LSPSResponseError),
308	/// A successful response to a [`LSPS1GetOrderRequest`].
309	GetOrder(LSPS1CreateOrderResponse),
310	/// An error response to a [`LSPS1GetOrderRequest`].
311	GetOrderError(LSPSResponseError),
312}
313
314/// An enum that captures all valid JSON-RPC messages in the bLIP-51 / LSPS1 protocol.
315#[derive(Clone, Debug, PartialEq, Eq)]
316pub enum LSPS1Message {
317	/// An LSPS1 JSON-RPC request.
318	Request(LSPSRequestId, LSPS1Request),
319	/// An LSPS1 JSON-RPC response.
320	Response(LSPSRequestId, LSPS1Response),
321}
322
323impl TryFrom<LSPSMessage> for LSPS1Message {
324	type Error = ();
325
326	fn try_from(message: LSPSMessage) -> Result<Self, Self::Error> {
327		if let LSPSMessage::LSPS1(message) = message {
328			return Ok(message);
329		}
330
331		Err(())
332	}
333}
334
335impl From<LSPS1Message> for LSPSMessage {
336	fn from(message: LSPS1Message) -> Self {
337		LSPSMessage::LSPS1(message)
338	}
339}
340
341#[cfg(test)]
342mod tests {
343	use super::*;
344	use crate::alloc::string::ToString;
345
346	#[test]
347	fn options_supported_serialization() {
348		let min_required_channel_confirmations = 0;
349		let min_funding_confirms_within_blocks = 6;
350		let supports_zero_channel_reserve = true;
351		let max_channel_expiry_blocks = 144;
352		let min_initial_client_balance_sat = 10_000_000;
353		let max_initial_client_balance_sat = 100_000_000;
354		let min_initial_lsp_balance_sat = 100_000;
355		let max_initial_lsp_balance_sat = 100_000_000;
356		let min_channel_balance_sat = 100_000;
357		let max_channel_balance_sat = 100_000_000;
358
359		let options_supported = LSPS1Options {
360			min_required_channel_confirmations,
361			min_funding_confirms_within_blocks,
362			supports_zero_channel_reserve,
363			max_channel_expiry_blocks,
364			min_initial_client_balance_sat,
365			max_initial_client_balance_sat,
366			min_initial_lsp_balance_sat,
367			max_initial_lsp_balance_sat,
368			min_channel_balance_sat,
369			max_channel_balance_sat,
370		};
371
372		let json_str = r#"{"max_channel_balance_sat":"100000000","max_channel_expiry_blocks":144,"max_initial_client_balance_sat":"100000000","max_initial_lsp_balance_sat":"100000000","min_channel_balance_sat":"100000","min_funding_confirms_within_blocks":6,"min_initial_client_balance_sat":"10000000","min_initial_lsp_balance_sat":"100000","min_required_channel_confirmations":0,"supports_zero_channel_reserve":true}"#;
373
374		assert_eq!(json_str, serde_json::json!(options_supported).to_string());
375		assert_eq!(options_supported, serde_json::from_str(json_str).unwrap());
376	}
377
378	#[test]
379	fn parse_spec_test_vectors() {
380		// Here, we simply assert that we're able to parse all examples given in LSPS1.
381		let json_str = r#"{}"#;
382		let _get_info_request: LSPS1GetInfoRequest = serde_json::from_str(json_str).unwrap();
383
384		let json_str = r#"{
385			"min_required_channel_confirmations": 0,
386			"min_funding_confirms_within_blocks" : 6,
387			"supports_zero_channel_reserve": true,
388			"max_channel_expiry_blocks": 20160,
389			"min_initial_client_balance_sat": "20000",
390			"max_initial_client_balance_sat": "100000000",
391			"min_initial_lsp_balance_sat": "0",
392			"max_initial_lsp_balance_sat": "100000000",
393			"min_channel_balance_sat": "50000",
394			"max_channel_balance_sat": "100000000"
395		}"#;
396		let _get_info_response: LSPS1GetInfoResponse = serde_json::from_str(json_str).unwrap();
397
398		let json_str = r#"{
399			"lsp_balance_sat": "5000000",
400			"client_balance_sat": "2000000",
401			"required_channel_confirmations" : 0,
402			"funding_confirms_within_blocks": 6,
403			"channel_expiry_blocks": 144,
404			"token": "",
405			"refund_onchain_address": "bc1qvmsy0f3yyes6z9jvddk8xqwznndmdwapvrc0xrmhd3vqj5rhdrrq6hz49h",
406			"announce_channel": true
407		}"#;
408		let _create_order_request: LSPS1CreateOrderRequest =
409			serde_json::from_str(json_str).unwrap();
410
411		let json_str = r#"{
412			"state" : "EXPECT_PAYMENT",
413			"expires_at": "2025-01-01T00:00:00Z",
414			"fee_total_sat": "8888",
415			"order_total_sat": "200888",
416			"invoice": "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05"
417		}"#;
418		let _bolt11_payment: LSPS1Bolt11PaymentInfo = serde_json::from_str(json_str).unwrap();
419
420		let json_str = r#"{
421			"state" : "EXPECT_PAYMENT",
422			"expires_at": "2025-01-01T00:00:00Z",
423			"fee_total_sat": "8888",
424			"order_total_sat": "200888",
425			"offer": "lno1qgsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcgqvp3pwq2q3shxerxzzfqyxdxxkjqxfpt9tz94zj79m4n99kwjddq92uqryuwsu4nt0t3lthfq02jzqla96dtkf4rew8edxw0p85swe89wd8ldekdl5j262n76qyl2qgzajm08clzr74z6ssy0qlvvp9f5kvrxf27yz4pcy99jge69kxu8ttsqt8gw8jsk5397zvvdf4lfd52paf73thcg6xf57xmvtdrwny5mn2r4jw2d5jzalqrq537mmt6u9qpqytzzql6zemrme07jqqwtza76lldcj9wgc0ccd4d2w584cdcx6szsuupvy"
426		}"#;
427		let _bolt11_payment: LSPS1Bolt12PaymentInfo = serde_json::from_str(json_str).unwrap();
428
429		let json_str = r#"{
430			"state": "EXPECT_PAYMENT",
431			"expires_at": "2025-01-01T00:00:00Z",
432			"fee_total_sat": "9999",
433			"order_total_sat": "200999",
434			"address": "bc1p5uvtaxzkjwvey2tfy49k5vtqfpjmrgm09cvs88ezyy8h2zv7jhas9tu4yr",
435			"min_onchain_payment_confirmations": 1,
436			"min_fee_for_0conf": 253
437		}"#;
438		let _onchain_payment: LSPS1OnchainPaymentInfo = serde_json::from_str(json_str).unwrap();
439
440		let json_str = r#"{
441			"bolt11": {
442				"state" : "EXPECT_PAYMENT",
443				"expires_at": "2025-01-01T00:00:00Z",
444				"fee_total_sat": "8888",
445				"order_total_sat": "200888",
446				"invoice": "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05"
447			},
448			"bolt12": {
449				"state" : "EXPECT_PAYMENT",
450				"expires_at": "2025-01-01T00:00:00Z",
451				"fee_total_sat": "8888",
452				"order_total_sat": "200888",
453				"offer": "lno1qgsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcgqvp3pwq2q3shxerxzzfqyxdxxkjqxfpt9tz94zj79m4n99kwjddq92uqryuwsu4nt0t3lthfq02jzqla96dtkf4rew8edxw0p85swe89wd8ldekdl5j262n76qyl2qgzajm08clzr74z6ssy0qlvvp9f5kvrxf27yz4pcy99jge69kxu8ttsqt8gw8jsk5397zvvdf4lfd52paf73thcg6xf57xmvtdrwny5mn2r4jw2d5jzalqrq537mmt6u9qpqytzzql6zemrme07jqqwtza76lldcj9wgc0ccd4d2w584cdcx6szsuupvy"
454			},
455			"onchain": {
456				"state": "EXPECT_PAYMENT",
457				"expires_at": "2025-01-01T00:00:00Z",
458				"fee_total_sat": "9999",
459				"order_total_sat": "200999",
460				"address": "bc1p5uvtaxzkjwvey2tfy49k5vtqfpjmrgm09cvs88ezyy8h2zv7jhas9tu4yr",
461				"min_onchain_payment_confirmations": 1,
462				"min_fee_for_0conf": 253
463			}
464		}"#;
465		let payment: LSPS1PaymentInfo = serde_json::from_str(json_str).unwrap();
466		assert!(payment.bolt11.is_some());
467		assert!(payment.bolt12.is_some());
468		assert!(payment.onchain.is_some());
469
470		let json_str = r#"{
471			"order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c",
472			"lsp_balance_sat": "5000000",
473			"client_balance_sat": "2000000",
474			"required_channel_confirmations" : 0,
475			"funding_confirms_within_blocks": 1,
476			"channel_expiry_blocks": 12,
477			"token": "",
478			"created_at": "2012-04-23T18:25:43.511Z",
479			"announce_channel": true,
480			"order_state": "CREATED",
481			"payment": {
482				"bolt11": {
483					"state": "EXPECT_PAYMENT",
484					"expires_at": "2015-01-25T19:29:44.612Z",
485					"fee_total_sat": "8888",
486					"order_total_sat": "2008888",
487					"invoice" : "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05"
488				},
489				"bolt12": {
490					"state" : "EXPECT_PAYMENT",
491					"expires_at": "2025-01-01T00:00:00Z",
492					"fee_total_sat": "8888",
493					"order_total_sat": "200888",
494					"offer": "lno1qgsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcgqvp3pwq2q3shxerxzzfqyxdxxkjqxfpt9tz94zj79m4n99kwjddq92uqryuwsu4nt0t3lthfq02jzqla96dtkf4rew8edxw0p85swe89wd8ldekdl5j262n76qyl2qgzajm08clzr74z6ssy0qlvvp9f5kvrxf27yz4pcy99jge69kxu8ttsqt8gw8jsk5397zvvdf4lfd52paf73thcg6xf57xmvtdrwny5mn2r4jw2d5jzalqrq537mmt6u9qpqytzzql6zemrme07jqqwtza76lldcj9wgc0ccd4d2w584cdcx6szsuupvy"
495				},
496				"onchain": {
497					"state": "EXPECT_PAYMENT",
498					"expires_at": "2015-01-25T19:29:44.612Z",
499					"fee_total_sat": "9999",
500					"order_total_sat": "2009999",
501					"address" : "bc1p5uvtaxzkjwvey2tfy49k5vtqfpjmrgm09cvs88ezyy8h2zv7jhas9tu4yr",
502					"min_fee_for_0conf": 253,
503					"min_onchain_payment_confirmations": 0,
504					"refund_onchain_address": "bc1qvmsy0f3yyes6z9jvddk8xqwznndmdwapvrc0xrmhd3vqj5rhdrrq6hz49h"
505				}
506			},
507			"channel": null
508		}"#;
509		let create_order_response: LSPS1CreateOrderResponse =
510			serde_json::from_str(json_str).unwrap();
511		assert!(create_order_response.payment.bolt11.is_some());
512		assert!(create_order_response.payment.bolt12.is_some());
513		assert!(create_order_response.payment.onchain.is_some());
514
515		let json_str = r#"{
516			"order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c"
517		}"#;
518		let _get_order_request: LSPS1GetOrderRequest = serde_json::from_str(json_str).unwrap();
519
520		let json_str = r#"{
521			"funded_at": "2012-04-23T18:25:43.511Z",
522			"funding_outpoint": "0301e0480b374b32851a9462db29dc19fe830a7f7d7a88b81612b9d42099c0ae:0",
523			"expires_at": "2012-04-23T18:25:43.511Z"
524		}"#;
525		let _channel: LSPS1ChannelInfo = serde_json::from_str(json_str).unwrap();
526
527		let json_str = r#""CANCELLED""#;
528		let payment_state: LSPS1PaymentState = serde_json::from_str(json_str).unwrap();
529		assert_eq!(payment_state, LSPS1PaymentState::Refunded);
530
531		let json_str = r#""REFUNDED""#;
532		let payment_state: LSPS1PaymentState = serde_json::from_str(json_str).unwrap();
533		assert_eq!(payment_state, LSPS1PaymentState::Refunded);
534	}
535}