Skip to main content

lexe_common/
constants.rs

1use std::include_bytes;
2
3use lexe_enclave::enclave::{Measurement, MrShort};
4use lexe_std::const_concat_str;
5
6use crate::{ppm, ppm::Ppm};
7
8/// Timeout constants and hierarchies.
9pub mod timeout;
10
11// --- General --- //
12
13/// If a node release needs to be yanked, add its semver version and measurement
14/// here. See `node::approved_versions` for more info.
15// e.g. "0.1.0", "0.2.1-alpha.1".
16// TODO(max): We could replace these by baking in `releases-archive.json`.
17pub const YANKED_NODE_VERSIONS: [&str; 0] = [];
18pub const YANKED_NODE_MEASUREMENTS: [Measurement; 0] = [];
19lexe_std::const_assert!(
20    YANKED_NODE_VERSIONS.len() == YANKED_NODE_MEASUREMENTS.len()
21);
22
23/// The first node version to serve the `/user/v1/provision` endpoint,
24/// older node versions serve only `/app/provision`.
25///
26/// The backend now never returns pre-`node-v0.9.12` enclaves to provision.
27/// We had to filter the response, as we deployed bad clients which fail to
28/// start up because they erroneously provision via the `/user` endpoint.
29//
30// TODO(max): Remove this once pre-`node-v0.9.12` enclaves are revoked.
31pub const FIRST_USER_API_NODE_VERSION: semver::Version =
32    semver::Version::new(0, 9, 12);
33
34/// Reject backend requests for payments that are too large.
35pub const MAX_PAYMENTS_BATCH_SIZE: u16 = 100;
36pub const DEFAULT_PAYMENTS_BATCH_SIZE: u16 = 50;
37
38/// Reject payment notes that are too large.
39pub const MAX_PAYMENT_NOTE_BYTES: usize = 512;
40
41/// This is both:
42///
43/// - The size of the `ApprovedVersions` window.
44/// - The number of trusted versions that the app will try to keep provisioned.
45///
46/// This strikes a balance between:
47///
48/// 1) having a sufficient number of recent versions approved so that Lexe has
49///    the ability to downgrade users (by yanking versions) if it is discovered
50///    that a node release is broken in some way, and
51/// 2) having so many versions approved that Lexe could downgrade users to an
52///    old version that may contain vulnerabilities.
53pub const RELEASE_WINDOW_SIZE: usize = 2;
54
55// --- Channels and liquidity --- //
56
57/// Our dust limit for e.g. our channel close txo's. If our channel balance,
58/// after paying close fees, is <= this value, we will not get a txo and this
59/// value is lost (goes to fees).
60///
61/// LDK just uses a fixed value here.
62///
63/// See: [`MIN_CHAN_DUST_LIMIT_SATOSHIS`](https://github.com/lightningdevkit/rust-lightning/blob/70add1448b5c36368b8f1c17d672d8871cee14de/lightning/src/ln/channel.rs#L697)
64pub const LDK_DUST_LIMIT_SATS: u32 = 354;
65
66/// The amount of liquidity (in sats) that Lexe supplies to us for free, which
67/// we are not expected to pay interest on. This is also the amount of liquidity
68/// Lexe's LSP will supply to a user in their first JIT zeroconf channel open.
69// 50k sats = 0.0005 BTC = $25 at $50k/BTC or $50 at $100k/BTC
70pub const FREE_LIQUIDITY_SAT: u32 = 50_000;
71
72/// The maximum amount of liquidity that Lexe will supply to a user in one tx.
73//
74// TODO(phlip9): increase once new liquidity model is in
75pub const MAX_LIQUIDITY_SAT: u32 = 1_000_000; // 0.01 BTC
76
77/// User nodes require the LSP to reserve this proportion of the channel value
78/// (in millionths) as potential punishment. LDK clamps the actual reserve
79/// amount to at least 1000 sats. Since the LSP can't send this amount to the
80/// user, the user's inbound liquidity is also reduced by this amount. Used for:
81/// [`lightning::util::config::ChannelHandshakeConfig::their_channel_reserve_proportional_millionths`]
82pub const LSP_RESERVE_PROPORTION: Ppm = ppm!(1.0%);
83
84/// The LSP will only accept new inbound channels with channel value at or above
85/// this limit in satoshis.
86// 0.00005000 BTC = $2.50 at $50k/BTC or $5 at $100k/BTC
87pub const LSP_USERNODE_CHANNEL_MIN_FUNDING_SATS: u32 = 5_000;
88
89/// Unconditional extra fee the LSP<->user channel funder will pay for
90/// coop-close in order to avoid a potential force-close due to fee
91/// disagreement.
92///
93/// During modern "legacy" (not "simple_close") coop-close, the channel funder
94/// proposes a `[min fee, max fee]` range that it's willing to pay. An LDK
95/// counterparty then chooses the `max_fee`.
96///
97/// An LDK funder determines the `max_fee` by estimating the feerate for
98/// [`ConfirmationTarget::NonAnchorChannelFee`] plus this
99/// `FORCE_CLOSE_AVOIDANCE_MAX_FEE_SATS` value.
100///
101/// 2026-06-24: Prior to this date, this was 1000 sats, which meant all our
102/// LSP<->User coop-closes overpaid on-chain fees by ~7-8x market rate.
103///
104/// See: [`lightning::util::config::ChannelConfig::force_close_avoidance_max_fee_satoshis`]
105///
106/// [`ConfirmationTarget::NonAnchorChannelFee`]: lightning::chain::chaininterface::ConfirmationTarget::NonAnchorChannelFee
107pub const FORCE_CLOSE_AVOIDANCE_MAX_FEE_SATS: u64 = 50;
108
109// --- Human Bitcoin Addresses --- //
110
111/// The minimum total wallet balance (in sats) required to claim or update a
112/// custom Human Bitcoin Address. Deters mass-claiming of usernames.
113// 10k sats = $5 at $50k/BTC or $10 at $100k/BTC
114pub const HBA_CLAIM_MIN_BALANCE_SATS: u32 = 10_000;
115
116// --- Networking --- //
117
118/// Fake DNS names used by the reverse proxy to route requests to user nodes.
119/// Provision mode uses "{mr_short}.provision.lexe.app" and run mode uses
120/// "run.lexe.app". These DNS names don't actually resolve.
121pub const NODE_RUN_DNS: &str = "run.lexe.app";
122pub const NODE_RUN_URL: &str = const_concat_str!("https://", NODE_RUN_DNS);
123pub fn node_provision_dns(mr_short: &MrShort) -> String {
124    format!("{mr_short}{NODE_PROVISION_DNS_SUFFIX}")
125}
126pub const NODE_PROVISION_DNS_SUFFIX: &str = ".provision.lexe.app";
127
128// --- Esplora --- //
129// Quickly test these by appending /fee-estimates and opening in browser,
130// e.g. "https://testnet.ltbl.io/api/fee-estimates"
131
132pub const MAINNET_LEXE_MEMPOOL_ESPLORA: &str = "https://lexe.mempool.space/api";
133// Introduced in node-v0.6.8, lsp-v0.6.28
134pub const MAINNET_LEXE_BLOCKSTREAM_ESPLORA: &str =
135    "https://ipwl.blockstream.info/api";
136pub const MAINNET_PUBLIC_BLOCKSTREAM_ESPLORA: &str =
137    "https://blockstream.info/api";
138pub const MAINNET_ESPLORA_WHITELIST: [&str; 3] = [
139    MAINNET_LEXE_MEMPOOL_ESPLORA,
140    MAINNET_LEXE_BLOCKSTREAM_ESPLORA,
141    MAINNET_PUBLIC_BLOCKSTREAM_ESPLORA,
142];
143
144// Introduced in node-v0.7.12
145pub const TESTNET3_LEXE_MEMPOOL_ESPLORA: &str =
146    "https://lexe.mempool.space/testnet/api";
147// Introduced in node-v0.6.8, lsp-v0.6.28
148// NOTE: our ipwl doesn't currently work for testnet3
149pub const TESTNET3_LEXE_BLOCKSTREAM_ESPLORA: &str =
150    "https://ipwl.blockstream.info/testnet/api";
151pub const TESTNET3_PUBLIC_BLOCKSTREAM_ESPLORA: &str =
152    "https://blockstream.info/testnet/api";
153pub const TESTNET3_LTBL_ESPLORA: &str = "https://testnet.ltbl.io/api";
154pub const TESTNET3_LEXE_ESPLORA: &str = "https://esplora.staging.lexe.app/api";
155pub const TESTNET3_ESPLORA_WHITELIST: [&str; 5] = [
156    TESTNET3_LEXE_BLOCKSTREAM_ESPLORA,
157    TESTNET3_PUBLIC_BLOCKSTREAM_ESPLORA,
158    TESTNET3_LEXE_ESPLORA,
159    TESTNET3_LEXE_MEMPOOL_ESPLORA,
160    TESTNET3_LTBL_ESPLORA,
161];
162
163// --- Root CA certs --- //
164//
165// This section contains DER-encoded TLS certs for the root CAs used by various
166// websites that we make requests to, including Lexe itself. For security, we
167// only allow using reqwest with `rustls-tls-manual-roots`, which trusts 0 roots
168// by default. Thus, it is necessary to manually include a root CA cert in our
169// TLS config whenever we make a request to Lexe or an external site. For
170// extra security, once a `reqwest::Client` has been configured to trust a CA
171// root, it should not be reused for requests to sites with different roots.
172//
173// ### Instructions for adding or updating an external root cert
174// (written for Brave / Chrome)
175//
176// - Visit the website in your browser via HTTPS.
177// - Click the HTTPS lock icon and view certificate details.
178// - Navigate up the certificate chain until you have selected the root cert.
179// - Press "Export..."
180// - When prompted for the format, use "DER-encoded binary, single certificate".
181// - Save it to "lexe-common/data/<root_ca_name>_root-ca-cert.der"
182// - Add a `include_bytes!()` entry below with a corresponding test.
183// - Tip: You can see the full human-readable cert info with macOS Quick Look.
184//
185// ### Inspecting a DER-encoded certificate
186//
187// macOS Finder's "Quick Look" works for some certificates.
188// Alternatively, view the cert from the command line:
189//
190// ```bash
191// openssl x509 -inform der -in <certificate-name>.der -text -noout
192// ```
193
194/// The Lexe CA responsible for `lexe.app` and `.lx`.
195// Serial Number : 73:bb:2d:b0:13:58:d7:1c:ca:a5:d3:56:a7:f3:33:5b:4c:3c:60:8e
196//    Not Before : Nov 27 21:44:46 2024 GMT
197//     Not After : Dec  4 21:44:46 2034 GMT
198pub const LEXE_PROD_CA_CERT_DER: &[u8] =
199    include_bytes!("../data/lexe-prod-root-ca-cert.der");
200
201/// The Lexe CA responsible for `staging.lexe.app` and `staging.lx`.
202// Serial Number : 30:ef:fb:a0:ba:ca:82:0b:7f:49:9a:46:b7:8d:05:18:23:91:62:17
203//    Not Before : Jul 30 02:15:24 2024 GMT
204//     Not After : Aug  6 02:15:24 2034 GMT
205pub const LEXE_STAGING_CA_CERT_DER: &[u8] =
206    include_bytes!("../data/lexe-staging-root-ca-cert.der");
207
208/// The Lexe dummy CA used in local testing and development.
209// Serial Number : 37:80:43:1e:b3:5c:74:e0:c4:1a:3d:45:2a:be:d0:bb:83:14:f3:6a
210//    Not Before : Jan  1 00:00:00 1975 GMT
211//     Not After : Jan  1 00:00:00 4096 GMT
212pub const LEXE_DUMMY_CA_CERT_DER: &[u8] =
213    include_bytes!("../data/lexe-dummy-root-ca-cert.der");
214
215/// Google Trust Services Root R1 (RSA), used by `googleapis.com` and
216/// `dns.google`.
217// `curl https://i.pki.goog/r1.crt -o lexe-common/data/google-trust-services-root-r1-ca-cert.der`
218// Serial Number : 02:03:E5:93:6F:31:B0:13:49:88:6B:A2:17
219//    Not Before : Jun 22 00:00:00 2016 GMT
220//     Not After : Jun 22 00:00:00 2036 GMT
221pub const GTS_ROOT_R1_CA_CERT_DER: &[u8] =
222    include_bytes!("../data/google-trust-services-root-r1-ca-cert.der");
223
224/// Google Trust Services Root R2 (RSA), used by `googleapis.com` and
225/// `dns.google`.
226// `curl https://i.pki.goog/r2.crt -o lexe-common/data/google-trust-services-root-r2-ca-cert.der`
227// Serial Number : 02:03:E5:AE:C5:8D:04:25:1A:AB:11:25:AA
228//    Not Before : Jun 22 00:00:00 2016 GMT
229//    Not After  : Jun 22 00:00:00 2036 GMT
230pub const GTS_ROOT_R2_CA_CERT_DER: &[u8] =
231    include_bytes!("../data/google-trust-services-root-r2-ca-cert.der");
232
233/// Google Trust Services Root R3 (ECDSA), used by `googleapis.com` and
234/// `dns.google`.
235// `curl https://i.pki.goog/r3.crt -o lexe-common/data/google-trust-services-root-r3-ca-cert.der`
236// Serial Number : 02:03:E5:B8:82:EB:20:F8:25:27:6D:3D:66
237//    Not Before : Jun 22 00:00:00 2016 GMT
238//    Not After  : Jun 22 00:00:00 2036 GMT
239pub const GTS_ROOT_R3_CA_CERT_DER: &[u8] =
240    include_bytes!("../data/google-trust-services-root-r3-ca-cert.der");
241
242/// Google Trust Services Root R4 (ECDSA), used by `googleapis.com` and
243/// `dns.google`.
244// `curl https://i.pki.goog/r4.crt -o lexe-common/data/google-trust-services-root-r4-ca-cert.der`
245// Serial Number : 02:03:E5:C0:68:EF:63:1A:9C:72:90:50:52
246//    Not Before : Jun 22 00:00:00 2016 GMT
247//    Not After  : Jun 22 00:00:00 2036 GMT
248pub const GTS_ROOT_R4_CA_CERT_DER: &[u8] =
249    include_bytes!("../data/google-trust-services-root-r4-ca-cert.der");
250
251/// GlobalSign Root R4 (ECDSA), used by `googleapis.com` and `dns.google`.
252// `curl https://i.pki.goog/gsr4.crt -o lexe-common/data/globalsign-root-r4-ca-cert.der`
253// Serial Number : 02:03:E5:7E:F5:3F:93:FD:A5:09:21:B2:A6
254//    Not Before : Nov 13 00:00:00 2012 GMT
255//    Not After  : Jan 19 03:14:07 2038 GMT
256pub const GS_ROOT_R4_CA_CERT_DER: &[u8] =
257    include_bytes!("../data/globalsign-root-r4-ca-cert.der");
258
259#[cfg(test)]
260mod test {
261    use asn1_rs::FromDer;
262    use x509_parser::prelude::X509Certificate;
263
264    use super::*;
265
266    #[test]
267    fn test_parse_ca_certs() {
268        X509Certificate::from_der(LEXE_PROD_CA_CERT_DER).unwrap();
269        X509Certificate::from_der(LEXE_STAGING_CA_CERT_DER).unwrap();
270        X509Certificate::from_der(GTS_ROOT_R1_CA_CERT_DER).unwrap();
271        X509Certificate::from_der(GTS_ROOT_R2_CA_CERT_DER).unwrap();
272        X509Certificate::from_der(GTS_ROOT_R3_CA_CERT_DER).unwrap();
273        X509Certificate::from_der(GTS_ROOT_R4_CA_CERT_DER).unwrap();
274    }
275}