1tonic::include_proto!("cln");
2
3#[cfg(feature = "server")]
4pub use cln_rpc::primitives::Sha256;
5#[cfg(feature = "server")]
6mod convert {
7 use super::*;
8 use bitcoin::hashes::Hash;
9 use std::str::FromStr;
10
11 use cln_rpc::primitives::{
12 Amount as JAmount, AmountOrAll as JAmountOrAll, AmountOrAny as JAmountOrAny,
13 Feerate as JFeerate, Outpoint as JOutpoint, OutputDesc as JOutputDesc,
14 };
15
16 impl From<JAmount> for Amount {
17 fn from(a: JAmount) -> Self {
18 Amount { msat: a.msat() }
19 }
20 }
21
22 impl From<Amount> for JAmount {
23 fn from(a: Amount) -> Self {
24 JAmount::from_msat(a.msat)
25 }
26 }
27
28 impl From<JOutpoint> for Outpoint {
29 fn from(a: JOutpoint) -> Self {
30 Outpoint {
31 txid: <Sha256 as AsRef<[u8]>>::as_ref(&a.txid).to_vec(),
32 outnum: a.outnum,
33 }
34 }
35 }
36
37 impl From<Outpoint> for JOutpoint {
38 fn from(a: Outpoint) -> Self {
39 JOutpoint {
40 txid: bitcoin::hashes::sha256::Hash::from_slice(&a.txid).unwrap(),
41 outnum: a.outnum,
42 }
43 }
44 }
45
46 impl From<Feerate> for cln_rpc::primitives::Feerate {
47 fn from(f: Feerate) -> cln_rpc::primitives::Feerate {
48 use feerate::Style;
49 match f.style.unwrap() {
50 Style::Slow(_) => JFeerate::Slow,
51 Style::Normal(_) => JFeerate::Normal,
52 Style::Urgent(_) => JFeerate::Urgent,
53 Style::Perkw(i) => JFeerate::PerKw(i),
54 Style::Perkb(i) => JFeerate::PerKb(i),
55 }
56 }
57 }
58
59 impl From<cln_rpc::primitives::Feerate> for Feerate {
60 fn from(f: cln_rpc::primitives::Feerate) -> Feerate {
61 use feerate::Style;
62 let style = Some(match f {
63 JFeerate::Slow => Style::Slow(true),
64 JFeerate::Normal => Style::Normal(true),
65 JFeerate::Urgent => Style::Urgent(true),
66 JFeerate::PerKb(i) => Style::Perkb(i),
67 JFeerate::PerKw(i) => Style::Perkw(i),
68 });
69 Self { style }
70 }
71 }
72
73 impl From<OutputDesc> for JOutputDesc {
74 fn from(od: OutputDesc) -> JOutputDesc {
75 JOutputDesc {
76 address: od.address,
77 amount: od.amount.unwrap().into(),
78 }
79 }
80 }
81
82 impl From<JOutputDesc> for OutputDesc {
83 fn from(od: JOutputDesc) -> Self {
84 Self {
85 address: od.address,
86 amount: Some(od.amount.into()),
87 }
88 }
89 }
90
91 impl From<JAmountOrAll> for AmountOrAll {
92 fn from(a: JAmountOrAll) -> Self {
93 match a {
94 JAmountOrAll::Amount(a) => AmountOrAll {
95 value: Some(amount_or_all::Value::Amount(a.into())),
96 },
97 JAmountOrAll::All => AmountOrAll {
98 value: Some(amount_or_all::Value::All(true)),
99 },
100 }
101 }
102 }
103
104 impl From<AmountOrAll> for JAmountOrAll {
105 fn from(a: AmountOrAll) -> Self {
106 match a.value {
107 Some(amount_or_all::Value::Amount(a)) => JAmountOrAll::Amount(a.into()),
108 Some(amount_or_all::Value::All(_)) => JAmountOrAll::All,
109 None => panic!("AmountOrAll is neither amount nor all: {:?}", a),
110 }
111 }
112 }
113
114 impl From<JAmountOrAny> for AmountOrAny {
115 fn from(a: JAmountOrAny) -> Self {
116 match a {
117 JAmountOrAny::Amount(a) => AmountOrAny {
118 value: Some(amount_or_any::Value::Amount(a.into())),
119 },
120 JAmountOrAny::Any => AmountOrAny {
121 value: Some(amount_or_any::Value::Any(true)),
122 },
123 }
124 }
125 }
126 impl From<AmountOrAny> for JAmountOrAny {
127 fn from(a: AmountOrAny) -> Self {
128 match a.value {
129 Some(amount_or_any::Value::Amount(a)) => JAmountOrAny::Amount(a.into()),
130 Some(amount_or_any::Value::Any(_)) => JAmountOrAny::Any,
131 None => panic!("AmountOrAll is neither amount nor any: {:?}", a),
132 }
133 }
134 }
135 impl From<RouteHop> for cln_rpc::primitives::Routehop {
136 fn from(c: RouteHop) -> Self {
137 Self {
138 id: cln_rpc::primitives::PublicKey::from_slice(&c.id).unwrap(),
139 scid: cln_rpc::primitives::ShortChannelId::from_str(&c.scid).unwrap(),
140 feebase: c.feebase.unwrap().into(),
141 feeprop: c.feeprop,
142 expirydelta: c.expirydelta as u16,
143 }
144 }
145 }
146
147 impl From<Routehint> for cln_rpc::primitives::Routehint {
148 fn from(c: Routehint) -> Self {
149 Self {
150 hops: c.hops.into_iter().map(|h| h.into()).collect(),
151 }
152 }
153 }
154
155 impl From<RoutehintList> for cln_rpc::primitives::RoutehintList {
156 fn from(c: RoutehintList) -> Self {
157 Self {
158 hints: c.hints.into_iter().map(|h| h.into()).collect(),
159 }
160 }
161 }
162
163 impl From<cln_rpc::primitives::Routehop> for RouteHop {
164 fn from(c: cln_rpc::primitives::Routehop) -> Self {
165 Self {
166 id: c.id.serialize().to_vec(),
167 feebase: Some(c.feebase.into()),
168 feeprop: c.feeprop,
169 expirydelta: c.expirydelta as u32,
170 scid: c.scid.to_string(),
171 }
172 }
173 }
174
175 impl From<cln_rpc::primitives::Routehint> for Routehint {
176 fn from(c: cln_rpc::primitives::Routehint) -> Self {
177 Self {
178 hops: c.hops.into_iter().map(|h| h.into()).collect(),
179 }
180 }
181 }
182
183 impl From<cln_rpc::primitives::RoutehintList> for RoutehintList {
184 fn from(c: cln_rpc::primitives::RoutehintList) -> Self {
185 Self {
186 hints: c.hints.into_iter().map(|e| e.into()).collect(),
187 }
188 }
189 }
190
191 impl From<DecodeRouteHop> for cln_rpc::primitives::DecodeRoutehop {
192 fn from(c: DecodeRouteHop) -> Self {
193 Self {
194 pubkey: cln_rpc::primitives::PublicKey::from_slice(&c.pubkey).unwrap(),
195 short_channel_id: cln_rpc::primitives::ShortChannelId::from_str(
196 &c.short_channel_id,
197 )
198 .unwrap(),
199 fee_base_msat: c.fee_base_msat.unwrap().into(),
200 fee_proportional_millionths: c.fee_proportional_millionths,
201 cltv_expiry_delta: c.cltv_expiry_delta as u16,
202 }
203 }
204 }
205
206 impl From<DecodeRoutehint> for cln_rpc::primitives::DecodeRoutehint {
207 fn from(c: DecodeRoutehint) -> Self {
208 Self {
209 hops: c.hops.into_iter().map(|h| h.into()).collect(),
210 }
211 }
212 }
213
214 impl From<DecodeRoutehintList> for cln_rpc::primitives::DecodeRoutehintList {
215 fn from(c: DecodeRoutehintList) -> Self {
216 Self {
217 hints: c.hints.into_iter().map(|h| h.into()).collect(),
218 }
219 }
220 }
221
222 impl From<cln_rpc::primitives::DecodeRoutehop> for DecodeRouteHop {
223 fn from(c: cln_rpc::primitives::DecodeRoutehop) -> Self {
224 Self {
225 pubkey: c.pubkey.serialize().to_vec(),
226 fee_base_msat: Some(c.fee_base_msat.into()),
227 fee_proportional_millionths: c.fee_proportional_millionths,
228 cltv_expiry_delta: c.cltv_expiry_delta as u32,
229 short_channel_id: c.short_channel_id.to_string(),
230 }
231 }
232 }
233
234 impl From<cln_rpc::primitives::DecodeRoutehint> for DecodeRoutehint {
235 fn from(c: cln_rpc::primitives::DecodeRoutehint) -> Self {
236 Self {
237 hops: c.hops.into_iter().map(|h| h.into()).collect(),
238 }
239 }
240 }
241
242 impl From<cln_rpc::primitives::DecodeRoutehintList> for DecodeRoutehintList {
243 fn from(c: cln_rpc::primitives::DecodeRoutehintList) -> Self {
244 Self {
245 hints: c.hints.into_iter().map(|e| e.into()).collect(),
246 }
247 }
248 }
249
250 impl From<TlvStream> for cln_rpc::primitives::TlvStream {
251 fn from(s: TlvStream) -> Self {
252 Self {
253 entries: s.entries.into_iter().map(|e| e.into()).collect(),
254 }
255 }
256 }
257
258 impl From<TlvEntry> for cln_rpc::primitives::TlvEntry {
259 fn from(e: TlvEntry) -> Self {
260 Self {
261 typ: e.r#type,
262 value: e.value,
263 }
264 }
265 }
266
267 impl From<cln_rpc::primitives::TlvStream> for TlvStream {
268 fn from(s: cln_rpc::primitives::TlvStream) -> Self {
269 Self {
270 entries: s.entries.into_iter().map(|e| e.into()).collect(),
271 }
272 }
273 }
274
275 impl From<cln_rpc::primitives::TlvEntry> for TlvEntry {
276 fn from(e: cln_rpc::primitives::TlvEntry) -> Self {
277 Self {
278 r#type: e.typ,
279 value: e.value,
280 }
281 }
282 }
283
284 #[cfg(test)]
285 mod test {
286 use super::*;
287 use serde_json::json;
288
289 #[test]
290 fn test_listpeers() {
291 let j: serde_json::Value = json!({
292 "peers": [
293 {
294 "id": "0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518",
295 "connected": true,
296 "netaddr": [
297 "127.0.0.1:39152"
298 ],
299 "features": "8808226aa2",
300 "num_channels": 0,
301 "channels": [
302 {
303 "state": "CHANNELD_NORMAL",
304 "scratch_txid": "fd4659658d235c20c81f96f7bc867c17abbfd20fcdd46c27eaad74ea52eaee90",
305 "last_tx_fee_msat": "14257000msat",
306 "feerate": {
307 "perkw": 11000,
308 "perkb": 44000
309 },
310 "owner": "channeld",
311 "short_channel_id": "103x2x1",
312 "direction": 0,
313 "channel_id": "44b77a6d66ca54f0c365c84b13a95fbde462415a0549228baa25ee1bb1dfef66",
314 "funding_txid": "67efdfb11bee25aa8b2249055a4162e4bd5fa9134bc865c3f054ca666d7ab744",
315 "funding_outnum": 1,
316 "close_to_addr": "bcrt1q9tc6q49l6wrrtp8ul45rj92hsleehwwxty32zu",
317 "close_to": "00142af1a054bfd3863584fcfd6839155787f39bb9c6",
318 "private": false,
319 "opener": "remote",
320 "features": [
321 "option_static_remotekey",
322 "option_anchor_outputs"
323 ],
324 "funding": {
325 "local_msat": "0msat",
326 "remote_msat": "1000000000msat",
327 "pushed_msat": "0msat",
328 "local_funds_msat": "0msat",
329 "remote_funds_msat": "0msat"
330 },
331 "msatoshi_to_us": 0,
332 "to_us_msat": "0msat",
333 "msatoshi_to_us_min": 0,
334 "min_to_us_msat": "0msat",
335 "msatoshi_to_us_max": 0,
336 "max_to_us_msat": "0msat",
337 "msatoshi_total": 1000000000,
338 "total_msat": "1000000000msat",
339 "fee_base_msat": "1msat",
340 "fee_proportional_millionths": 10,
341 "dust_limit_satoshis": 546,
342 "dust_limit_msat": "546000msat",
343 "max_total_htlc_in_msat": "18446744073709551615msat",
344 "their_channel_reserve_satoshis": 10000,
345 "their_reserve_msat": "10000000msat",
346 "our_channel_reserve_satoshis": 10000,
347 "our_reserve_msat": "10000000msat",
348 "spendable_msatoshi": 0,
349 "spendable_msat": "0msat",
350 "receivable_msatoshi": 853257998,
351 "receivable_msat": "853257998msat",
352 "htlc_minimum_msat": 0,
353 "minimum_htlc_in_msat": "0msat",
354 "their_to_self_delay": 5,
355 "our_to_self_delay": 5,
356 "max_accepted_htlcs": 483,
357 "state_changes": [
358 {
359 "timestamp": "2022-03-25T13:57:33.322Z",
360 "old_state": "CHANNELD_AWAITING_LOCKIN",
361 "new_state": "CHANNELD_NORMAL",
362 "cause": "remote",
363 "message": "Lockin complete"
364 }
365 ],
366 "status": [
367 "CHANNELD_NORMAL:Funding transaction locked. Channel announced."
368 ],
369 "in_payments_offered": 1,
370 "in_msatoshi_offered": 100002002,
371 "in_offered_msat": "100002002msat",
372 "in_payments_fulfilled": 0,
373 "in_msatoshi_fulfilled": 0,
374 "in_fulfilled_msat": "0msat",
375 "out_payments_offered": 0,
376 "out_msatoshi_offered": 0,
377 "out_offered_msat": "0msat",
378 "out_payments_fulfilled": 0,
379 "out_msatoshi_fulfilled": 0,
380 "out_fulfilled_msat": "0msat",
381 "htlcs": [
382 {
383 "direction": "in",
384 "id": 0,
385 "msatoshi": 100002002,
386 "amount_msat": "100002002msat",
387 "expiry": 131,
388 "payment_hash": "d17a42c4f7f49648064a0ce7ce848bd92c4c50f24d35fe5c3d1f3a7a9bf474b2",
389 "state": "RCVD_ADD_ACK_REVOCATION"
390 }
391 ]
392 }
393 ]
394 },
395 {
396 "id": "035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d",
397 "connected": true,
398 "netaddr": [
399 "127.0.0.1:38321"
400 ],
401 "features": "8808226aa2",
402 "num_channels": 0,
403 "channels": [
404 {
405 "state": "CHANNELD_NORMAL",
406 "scratch_txid": "30530d3f522862773100b7600d8ea8921a5ee84df17a2317326f9aa2c4829326",
407 "last_tx_fee_msat": "16149000msat",
408 "feerate": {
409 "perkw": 11000,
410 "perkb": 44000
411 },
412 "owner": "channeld",
413 "short_channel_id": "103x1x0",
414 "direction": 0,
415 "channel_id": "006a2044fc72fa5c4a54c9fddbf208970a7b3b4fd2aaa70a96abba757c01769e",
416 "funding_txid": "9e76017c75baab960aa7aad24f3b7b0a9708f2dbfdc9544a5cfa72fc44206a00",
417 "funding_outnum": 0,
418 "close_to_addr": "bcrt1qhfmyce4ujce2pyugew2435tlwft6p6w4s3py6d",
419 "close_to": "0014ba764c66bc9632a09388cb9558d17f7257a0e9d5",
420 "private": false,
421 "opener": "local",
422 "features": [
423 "option_static_remotekey",
424 "option_anchor_outputs"
425 ],
426 "funding": {
427 "local_msat": "1000000000msat",
428 "remote_msat": "0msat",
429 "pushed_msat": "0msat",
430 "local_funds_msat": "0msat",
431 "remote_funds_msat": "0msat"
432 },
433 "msatoshi_to_us": 1000000000,
434 "to_us_msat": "1000000000msat",
435 "msatoshi_to_us_min": 1000000000,
436 "min_to_us_msat": "1000000000msat",
437 "msatoshi_to_us_max": 1000000000,
438 "max_to_us_msat": "1000000000msat",
439 "msatoshi_total": 1000000000,
440 "total_msat": "1000000000msat",
441 "fee_base_msat": "1msat",
442 "fee_proportional_millionths": 10,
443 "dust_limit_satoshis": 546,
444 "dust_limit_msat": "546000msat",
445 "max_total_htlc_in_msat": "18446744073709551615msat",
446 "their_channel_reserve_satoshis": 10000,
447 "their_reserve_msat": "10000000msat",
448 "our_channel_reserve_satoshis": 10000,
449 "our_reserve_msat": "10000000msat",
450 "spendable_msatoshi": 749473998,
451 "spendable_msat": "749473998msat",
452 "receivable_msatoshi": 0,
453 "receivable_msat": "0msat",
454 "htlc_minimum_msat": 0,
455 "minimum_htlc_in_msat": "0msat",
456 "their_to_self_delay": 5,
457 "our_to_self_delay": 5,
458 "max_accepted_htlcs": 483,
459 "state_changes": [
460 {
461 "timestamp": "2022-03-25T13:57:33.325Z",
462 "old_state": "CHANNELD_AWAITING_LOCKIN",
463 "new_state": "CHANNELD_NORMAL",
464 "cause": "user",
465 "message": "Lockin complete"
466 }
467 ],
468 "status": [
469 "CHANNELD_NORMAL:Funding transaction locked. Channel announced."
470 ],
471 "in_payments_offered": 0,
472 "in_msatoshi_offered": 0,
473 "in_offered_msat": "0msat",
474 "in_payments_fulfilled": 0,
475 "in_msatoshi_fulfilled": 0,
476 "in_fulfilled_msat": "0msat",
477 "out_payments_offered": 2,
478 "out_msatoshi_offered": 200002002,
479 "out_offered_msat": "200002002msat",
480 "out_payments_fulfilled": 0,
481 "out_msatoshi_fulfilled": 0,
482 "out_fulfilled_msat": "0msat",
483 "htlcs": [
484 {
485 "direction": "out",
486 "id": 1,
487 "msatoshi": 100001001,
488 "amount_msat": "100001001msat",
489 "expiry": 125,
490 "payment_hash": "d17a42c4f7f49648064a0ce7ce848bd92c4c50f24d35fe5c3d1f3a7a9bf474b2",
491 "state": "SENT_ADD_ACK_REVOCATION"
492 },
493 {
494 "direction": "out",
495 "id": 0,
496 "msatoshi": 100001001,
497 "amount_msat": "100001001msat",
498 "expiry": 124,
499 "payment_hash": "d17a42c4f7f49648064a0ce7ce848bd92c4c50f24d35fe5c3d1f3a7a9bf474b2",
500 "state": "SENT_ADD_ACK_REVOCATION"
501 }
502 ]
503 }
504 ]
505 }
506 ]
507 });
508 let u: cln_rpc::model::responses::ListpeersResponse =
509 serde_json::from_value(j).unwrap();
510 let _g: ListpeersResponse = u.into();
511 }
512 }
513}