lsp_primitives/lsps1/
schema.rs

1use crate::json_rpc::NoParams;
2use crate::lsps0::common_schemas::{
3    FeeRate, IsoDatetime, OnchainAddress, Outpoint, SatAmount
4};
5use crate::lsps0::parameter_validation::ExpectedFields;
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9pub type Lsps1InfoRequest = NoParams;
10
11#[derive(Debug, Serialize, Deserialize, Clone)]
12pub struct Lsps1GetInfoResponse {
13    pub website: Option<String>,
14    pub options: Lsps1Options,
15    // Prevents struct initialization. Use Lsps1InfoResponseBuilder instead
16    #[serde(skip_serializing, default)]
17    pub(crate) _private: (),
18}
19
20/// Options returned when calling lsps1.info
21#[derive(Debug, Serialize, Deserialize, Clone)]
22pub struct Lsps1Options {
23    pub min_channel_confirmations: u8,
24    pub min_onchain_payment_confirmations: Option<u8>,
25    pub supports_zero_channel_reserve: bool,
26    pub min_onchain_payment_size_sat: Option<SatAmount>,
27    pub max_channel_expiry_blocks: u32,
28    pub min_initial_client_balance_sat: SatAmount,
29    pub max_initial_client_balance_sat: SatAmount,
30    pub min_initial_lsp_balance_sat: SatAmount,
31    pub max_initial_lsp_balance_sat: SatAmount,
32    pub min_channel_balance_sat: SatAmount,
33    pub max_channel_balance_sat: SatAmount,
34    // Prevents struct initialization. Use Lsps1OptionsBuilder instead
35    #[serde(skip_serializing, default)]
36    pub(crate) _private: (),
37}
38
39#[derive(Debug, Serialize, Deserialize, Clone)]
40pub struct Lsps1CreateOrderRequest {
41    pub lsp_balance_sat: SatAmount,
42    pub client_balance_sat: SatAmount,
43    pub confirms_within_blocks: u8,
44    pub channel_expiry_blocks: u32,
45    pub token: Option<String>,
46    pub refund_onchain_address: Option<OnchainAddress>,
47    pub announce_channel: bool,
48    // Prevents struct initialization. Use Lsps1OptionsBuilder instead
49    #[serde(skip_serializing, default)]
50    pub(crate) _private: (),
51}
52
53impl ExpectedFields for Lsps1CreateOrderRequest {
54    fn expected_fields() -> Vec<String> {
55        vec![
56            "lsp_balance_sat".to_string(),
57            "client_balance_sat".to_string(),
58            "confirms_within_blocks".to_string(),
59            "channel_expiry_blocks".to_string(),
60            "token".to_string(),
61            "refund_onchain_address".to_string(),
62            "announce_channel".to_string(),
63        ]
64    }
65}
66
67#[derive(Debug, Serialize, Deserialize, Clone)]
68pub struct Lsps1CreateOrderResponse {
69    pub order_id: Uuid,
70    pub lsp_balance_sat: SatAmount,
71    pub client_balance_sat: SatAmount,
72    pub confirms_within_blocks: u8,
73    pub channel_expiry_blocks: u32,
74    pub token: String,
75    #[serde(rename = "announceChannel")]
76    pub announce_channel: bool,
77    pub created_at: IsoDatetime,
78    pub expires_at: IsoDatetime,
79    pub order_state: OrderState,
80
81    pub payment: Payment,
82    pub channel: Option<Channel>,
83    // Prevents struct initialization. Use Lsps1OptionsBuilder instead
84    #[serde(skip_serializing, default)]
85    pub(crate) _private: (),
86}
87
88#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
89pub enum OrderState {
90    #[serde(rename = "CREATED")]
91    Created,
92    #[serde(rename = "COMPLETED")]
93    Completed,
94    #[serde(rename = "FAILED")]
95    Failed,
96}
97
98#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
99pub enum PaymentState {
100    #[serde(rename = "EXPECT_PAYMENT")]
101    ExpectPayment,
102    #[serde(rename = "HOLD")]
103    Hold,
104    #[serde(rename = "PAID")]
105    Paid,
106    #[serde(rename = "REFUNDED")]
107    Refunded,
108}
109
110#[derive(Debug, Serialize, Deserialize, Clone)]
111pub struct OnchainPayment {
112    pub outpoint: String,
113    pub sat: SatAmount,
114    pub confirmed: bool,
115    // Prevents struct initialization. Use OnchainPaymentBuilder instead
116    #[serde(skip_serializing, default)]
117    pub(crate) _private: (),
118}
119
120#[derive(Debug, Serialize, Deserialize, Clone)]
121pub struct Payment {
122    pub state: PaymentState,
123    pub fee_total_sat: SatAmount,
124    pub order_total_sat: SatAmount,
125
126    pub bolt11_invoice: String,
127    pub onchain_address: Option<OnchainAddress>,
128    pub min_onchain_payment_confirmations: Option<u8>,
129
130    pub min_fee_for_0conf: Option<FeeRate>,
131    pub onchain_payment: Option<OnchainPayment>,
132
133    // Prevents struct initialization. Use PaymentBuilder instead
134    #[serde(skip_serializing, default)]
135    pub(crate) _private: (),
136}
137
138#[derive(Debug, Serialize, Deserialize, Clone)]
139pub struct Channel {
140    pub funded_at: IsoDatetime,
141    pub funding_outpoint: Outpoint,
142    pub expires_at: IsoDatetime,
143}
144
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct Lsps1GetOrderRequest {
148    pub order_id: String,
149    #[serde(skip_serializing, default)]
150    pub(crate) _private: (),
151}
152
153impl ExpectedFields for Lsps1GetOrderRequest {
154    fn expected_fields() -> Vec<String> {
155        vec!["order_id".to_string()]
156    }
157}
158
159pub type Lsps1GetOrderResponse = Lsps1CreateOrderResponse;
160
161#[cfg(test)]
162mod test {
163
164    use super::*;
165
166    #[test]
167    fn deserialize_lsps1_options() {
168        // Example is copie pasted from the spec
169        let json_data = serde_json::json!(
170        {
171            "min_channel_confirmations": 0,
172            "min_onchain_payment_confirmations": 1,
173            "supports_zero_channel_reserve": true,
174            "min_onchain_payment_size_sat": null,
175            "max_channel_expiry_blocks": 20160,
176            "min_initial_client_balance_sat": "20000",
177            "max_initial_client_balance_sat": "100000000",
178            "min_initial_lsp_balance_sat": "0",
179            "max_initial_lsp_balance_sat": "100000000",
180            "min_channel_balance_sat": "50000",
181            "max_channel_balance_sat": "100000000"
182        }
183
184        );
185        serde_json::from_value::<Lsps1Options>(json_data).unwrap();
186    }
187
188    #[test]
189    fn deserialize_lsps1_info() {
190        // Example below is copied from the spec
191        let json_data = serde_json::json!(
192        {
193         "supported_versions": [1],
194         "website": "http://example.com/contact",
195         "options": {
196             "min_channel_confirmations": 0,
197             "min_onchain_payment_confirmations": 1,
198             "supports_zero_channel_reserve": true,
199             "min_onchain_payment_size_sat": null,
200             "max_channel_expiry_blocks": 20160,
201             "min_initial_client_balance_sat": "20000",
202             "max_initial_client_balance_sat": "100000000",
203             "min_initial_lsp_balance_sat": "0",
204             "max_initial_lsp_balance_sat": "100000000",
205             "min_channel_balance_sat": "50000",
206             "max_channel_balance_sat": "100000000"
207         }
208        }
209        );
210
211        serde_json::from_value::<Lsps1GetInfoResponse>(json_data).unwrap();
212    }
213
214    #[test]
215    fn lsps1_implements_serialize() {
216        use core::str::FromStr;
217        let onchain = OnchainAddress::from_str("32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf").unwrap();
218
219        let request = Lsps1CreateOrderRequest {
220            lsp_balance_sat: SatAmount::new(100_000),
221            client_balance_sat: SatAmount::new(1_000),
222            confirms_within_blocks: 10,
223            channel_expiry_blocks: 1000,
224            token: None,
225            refund_onchain_address: Some(onchain),
226            announce_channel: false,
227            _private: (),
228        };
229
230        let _ = serde_json::to_value(request).unwrap();
231    }
232}