fedimint_recurringd_tests/
fedimint-recurringd-tests.rs

1use 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            // Test admin auth is checked
23            {
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            // Give the LND Gateway a balance, it's the only GW serving LNv1 and recurringd
46            // is currently LNv1-only
47            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}