lsp_primitives/lsps2/
schema.rs1use serde::de::Error as DeError;
2use serde::{Deserialize, Serialize};
3
4use crate::lsps0::common_schemas::{IsoDatetime, MsatAmount, ShortChannelId};
5
6const MAX_PROMISE_LEN_BYTES: usize = 512;
7#[derive(Debug)]
8struct Promise {
9 promise: String,
10}
11
12impl Promise {
13 fn new(promise: String) -> Result<Self, String> {
14 if promise.len() <= MAX_PROMISE_LEN_BYTES {
15 Ok(Promise { promise })
16 } else {
17 Err(String::from("Promise exceeds maximum length"))
18 }
19 }
20}
21
22impl Serialize for Promise {
23 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
24 where
25 S: serde::Serializer,
26 {
27 serializer.serialize_str(&self.promise)
28 }
29}
30
31impl<'de> Deserialize<'de> for Promise {
35 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
36 where
37 D: serde::Deserializer<'de>,
38 {
39 let str_repr = String::deserialize(deserializer)?;
40 let promise = Promise::new(str_repr.clone());
41 format!("{:?}", &promise);
42 Promise::new(str_repr.clone()).map_err(|_| D::Error::custom("promise exceeds max length"))
43 }
44}
45
46#[derive(Debug, Serialize, Deserialize)]
47pub struct Lsps2GetVersionsResponse {
48 versions: Vec<u64>,
49}
50
51#[derive(Debug, Serialize, Deserialize)]
52pub struct Lsps2GetInfoRequest {
53 version: i64,
54 token: Option<String>,
55}
56
57#[derive(Debug, Serialize, Deserialize)]
58pub struct Lsps2GetInfoResponse {
59 opening_fee_params_menu: Vec<OpeningFeeParamsMenuItem>,
60 min_payment_size_msat: String,
61 max_payment_size_msat: String,
62}
63
64#[derive(Debug, Serialize, Deserialize)]
65#[serde(deny_unknown_fields)]
66pub struct OpeningFeeParamsMenuItem {
67 min_fee_msat: MsatAmount,
68 proportional: u64,
69 valid_until: IsoDatetime,
70 min_lifetime: u64,
71 max_client_to_self_delay: u64,
72 promise: Promise,
73}
74
75#[derive(Debug, Serialize, Deserialize)]
76pub struct Lsps2BuyRequest {
77 version: String,
78 opening_fee_params: OpeningFeeParamsMenuItem,
79 payment_size_msat: MsatAmount,
80}
81
82#[derive(Debug, Serialize, Deserialize)]
83pub struct Lsps2BuyResponse {
84 jit_channel_scid: ShortChannelId,
85 lsp_cltv_expiry_delta: u64,
86 #[serde(default)]
87 client_trusts_lsp: bool,
88}
89
90#[cfg(test)]
91mod test {
92 use super::*;
93
94 #[test]
95 fn parsing_error_when_opening_fee_menu_has_extra_fields() {
96 let fee_menu_item = serde_json::json!(
99 {
100 "min_fee_msat": "546000",
101 "proportional": 1200,
102 "valid_until": "2023-02-23T08:47:30.511Z",
103 "min_lifetime": 1008,
104 "max_client_to_self_delay": 2016,
105 "promise": "abcdefghijklmnopqrstuvwxyz",
106 "extra_field" : "This shouldn't be their"
107 }
108 );
109
110 let parsed_opening_fee_menu_item: Result<OpeningFeeParamsMenuItem, _> =
111 serde_json::from_value(fee_menu_item);
112 assert!(
113 parsed_opening_fee_menu_item.is_err_and(|x| format!("{}", x).contains("extra_field"))
114 )
115 }
116
117 #[test]
118 fn parse_valid_promise() {
119 let promise_json = "\"abcdefghijklmnopqrstuvwxyz\"";
120 let promise = serde_json::from_str::<Promise>(promise_json).expect("Can parse promise");
121 assert_eq!(promise.promise, "abcdefghijklmnopqrstuvwxyz");
122 }
123
124 #[test]
125 fn parse_too_long_promise_fails() {
126 let a_513_chars = "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"";
131 let a_512_chars = "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"";
132
133 serde_json::from_str::<Promise>(a_512_chars)
134 .expect("Should fail because 512 bytes is the max length");
135 serde_json::from_str::<Promise>(a_513_chars).expect_err("Should fail to parse promise ");
136 }
137
138 #[test]
139 fn client_trust_lsp_defaults_to_false() {
140 let data = serde_json::json!({
141 "jit_channel_scid" : "0x12x12",
142 "lsp_cltv_expiry_delta" : 144
143 });
144
145 let buy_response =
146 serde_json::from_value::<Lsps2BuyResponse>(data).expect("The response can be parsed");
147
148 assert!(
149 !buy_response.client_trusts_lsp,
150 "If the field is absent it assumed the client should not trust the LSP"
151 )
152 }
153}