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