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