fedimint_recurringd_tests/
fedimint-recurringd-tests.rs1use std::ops::ControlFlow;
2
3use devimint::tests::log_binary_versions;
4use devimint::util::{almost_equal, poll};
5use devimint::{DevFed, cmd};
6use lightning_invoice::Bolt11Invoice;
7use tracing::info;
8
9#[tokio::main]
10async fn main() -> anyhow::Result<()> {
11 devimint::run_devfed_test()
12 .call(|dev_fed, process_mgr| async move {
13 log_binary_versions().await?;
14
15 let DevFed {
16 fed,
17 gw_lnd,
18 gw_ldk_second,
19 recurringd,
20 ..
21 } = dev_fed.to_dev_fed(&process_mgr).await?;
22
23 {
25 let dummy_invite = "fed114znk7uk7ppugdjuytr8venqf2tkywd65cqvg3u93um64tu5cw4yr0n3fvn7qmwvm4g48cpndgnm4gqq4waen5te0xyerwt3s9cczuvf6xyurzde597s7crdvsk2vmyarjw9gwyqjdzj";
26 let url = format!("{}lnv1/federations", recurringd.api_url);
27 let client = reqwest::Client::new();
28 let response_no_auth = client
29 .put(&url)
30 .header("Content-Type", "application/json")
31 .json(&serde_json::json!({ "invite": dummy_invite }))
32 .send()
33 .await?;
34 assert!(response_no_auth.status().is_client_error());
35
36 let response_with_wrong_auth = client
37 .put(&url)
38 .header("Authorization", "Bearer wrong-token")
39 .header("Content-Type", "application/json")
40 .json(&serde_json::json!({ "invite": dummy_invite }))
41 .send()
42 .await?;
43 assert!(response_with_wrong_auth.status().is_client_error());
44 }
45
46 fed.pegin_gateways(10_000_000, vec![&gw_lnd]).await?;
49
50 let client = fed.new_joined_client("recurringd-test-client").await?;
51
52 let lnurl = cmd!(
53 client,
54 "module",
55 "ln",
56 "lnurl",
57 "register",
58 recurringd.api_url()
59 )
60 .out_json()
61 .await?["lnurl"]
62 .as_str()
63 .unwrap()
64 .to_owned();
65
66 let lnurl_list = cmd!(client, "module", "ln", "lnurl", "list")
67 .out_json()
68 .await?["codes"]
69 .as_object()
70 .unwrap()
71 .clone();
72
73 assert_eq!(lnurl_list.len(), 1);
74
75 let listed_lnurl = lnurl_list["0"].clone();
76 assert_eq!(listed_lnurl["lnurl"].as_str().unwrap(), &lnurl);
77 assert_eq!(listed_lnurl["last_derivation_index"].as_i64().unwrap(), 0);
78
79 let invoice = cmd!("lnurlp", "--amount", "1000sat", lnurl)
80 .out_string()
81 .await?
82 .parse::<Bolt11Invoice>()
83 .unwrap();
84
85 gw_ldk_second.pay_invoice(invoice.clone()).await?;
86
87 let invoice_op_id = poll("lnurl_receive", || async {
88 cmd!(client, "dev", "wait", "2")
89 .run()
90 .await
91 .map_err(ControlFlow::Break)?;
92
93 let invoice_list = cmd!(client, "module", "ln", "lnurl", "invoices", "0")
94 .out_json()
95 .await
96 .map_err(ControlFlow::Break)?["invoices"]
97 .as_object()
98 .unwrap()
99 .clone();
100
101 if invoice_list.is_empty() {
102 return Err(ControlFlow::Continue(anyhow::anyhow!(
103 "No invoice recognized yet"
104 )));
105 }
106
107 Ok(invoice_list["1"]["operation_id"]
108 .as_str()
109 .unwrap()
110 .to_owned())
111 })
112 .await?;
113
114 let await_invoice_result = cmd!(
115 client,
116 "module",
117 "ln",
118 "lnurl",
119 "await-invoice-paid",
120 invoice_op_id
121 )
122 .out_json()
123 .await?;
124
125 assert_eq!(
126 await_invoice_result["amount_msat"].as_i64().unwrap(),
127 1_000_000
128 );
129 assert_eq!(
130 await_invoice_result["invoice"].as_str().unwrap(),
131 &invoice.to_string()
132 );
133
134 let client_balance = client.balance().await?;
135 almost_equal(client_balance, 1_000_000, 5_000).unwrap();
136 info!("Client balance: {client_balance}");
137
138 Ok(())
139 })
140 .await
141}