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