fedimint_lnv2_common/
lib.rs

1#![deny(clippy::pedantic)]
2#![allow(clippy::module_name_repetitions)]
3#![allow(clippy::must_use_candidate)]
4#![allow(clippy::missing_errors_doc)]
5#![allow(clippy::missing_panics_doc)]
6
7//! # Lightning Module
8//!
9//! This module allows to atomically and trustlessly (in the federated trust
10//! model) interact with the Lightning network through a Lightning gateway.
11
12pub mod config;
13pub mod contracts;
14pub mod endpoint_constants;
15pub mod gateway_api;
16pub mod lnurl;
17pub mod tweak;
18
19use bitcoin::hashes::sha256;
20use bitcoin::secp256k1::schnorr::Signature;
21use config::LightningClientConfig;
22use fedimint_core::core::{Decoder, ModuleInstanceId, ModuleKind};
23use fedimint_core::encoding::{Decodable, Encodable};
24use fedimint_core::module::{CommonModuleInit, ModuleCommon, ModuleConsensusVersion};
25use fedimint_core::{OutPoint, extensible_associated_module_type, plugin_types_trait_impl_common};
26use lightning_invoice::Bolt11Invoice;
27use serde::{Deserialize, Serialize};
28use thiserror::Error;
29use tpe::AggregateDecryptionKey;
30
31use crate::contracts::{IncomingContract, OutgoingContract};
32
33#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
34pub enum Bolt11InvoiceDescription {
35    Direct(String),
36    Hash(sha256::Hash),
37}
38
39#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Decodable, Encodable)]
40pub enum LightningInvoice {
41    Bolt11(Bolt11Invoice),
42}
43
44pub const KIND: ModuleKind = ModuleKind::from_static_str("lnv2");
45pub const MODULE_CONSENSUS_VERSION: ModuleConsensusVersion = ModuleConsensusVersion::new(1, 0);
46
47#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
48pub struct ContractId(pub sha256::Hash);
49
50extensible_associated_module_type!(
51    LightningInput,
52    LightningInputV0,
53    UnknownLightningInputVariantError
54);
55
56#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
57pub enum LightningInputV0 {
58    Outgoing(OutPoint, OutgoingWitness),
59    Incoming(OutPoint, AggregateDecryptionKey),
60}
61
62#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
63pub enum OutgoingWitness {
64    Claim([u8; 32]),
65    Refund,
66    Cancel(Signature),
67}
68
69impl std::fmt::Display for LightningInputV0 {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        write!(f, "LightningInputV0",)
72    }
73}
74
75extensible_associated_module_type!(
76    LightningOutput,
77    LightningOutputV0,
78    UnknownLightningOutputVariantError
79);
80
81#[allow(clippy::large_enum_variant)]
82#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
83pub enum LightningOutputV0 {
84    Outgoing(OutgoingContract),
85    Incoming(IncomingContract),
86}
87
88impl std::fmt::Display for LightningOutputV0 {
89    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90        write!(f, "LightningOutputV0")
91    }
92}
93
94#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
95pub struct LightningOutputOutcome;
96
97impl std::fmt::Display for LightningOutputOutcome {
98    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99        write!(f, "LightningOutputOutcome")
100    }
101}
102
103#[derive(Debug, Clone, Eq, PartialEq, Hash, Error, Encodable, Decodable)]
104pub enum LightningInputError {
105    #[error("The lightning input version is not supported by this federation")]
106    UnknownInputVariant(#[from] UnknownLightningInputVariantError),
107    #[error("No contract found for given ContractId")]
108    UnknownContract,
109    #[error("The preimage is invalid")]
110    InvalidPreimage,
111    #[error("The contracts locktime has passed")]
112    Expired,
113    #[error("The contracts locktime has not yet passed")]
114    NotExpired,
115    #[error("The aggregate decryption key is invalid")]
116    InvalidDecryptionKey,
117    #[error("The forfeit signature is invalid")]
118    InvalidForfeitSignature,
119}
120
121#[derive(Debug, Clone, Eq, PartialEq, Hash, Error, Encodable, Decodable)]
122pub enum LightningOutputError {
123    #[error("The lightning input version is not supported by this federation")]
124    UnknownOutputVariant(#[from] UnknownLightningOutputVariantError),
125    #[error("The contract is invalid")]
126    InvalidContract,
127    #[error("The contract is expired")]
128    ContractExpired,
129}
130
131#[derive(Debug, Clone, Hash, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
132pub enum LightningConsensusItem {
133    BlockCountVote(u64),
134    UnixTimeVote(u64),
135    #[encodable_default]
136    Default {
137        variant: u64,
138        bytes: Vec<u8>,
139    },
140}
141
142impl std::fmt::Display for LightningConsensusItem {
143    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144        match self {
145            LightningConsensusItem::BlockCountVote(c) => {
146                write!(f, "LNv2 Block Count {c}")
147            }
148            LightningConsensusItem::UnixTimeVote(t) => {
149                write!(f, "LNv2 Unix Time {t}")
150            }
151            LightningConsensusItem::Default { variant, bytes } => write!(
152                f,
153                "LNv2 Unknown - variant: {variant}, bytes_len: {}",
154                bytes.len()
155            ),
156        }
157    }
158}
159
160#[derive(Debug)]
161pub struct LightningCommonInit;
162
163impl CommonModuleInit for LightningCommonInit {
164    const CONSENSUS_VERSION: ModuleConsensusVersion = MODULE_CONSENSUS_VERSION;
165    const KIND: ModuleKind = KIND;
166
167    type ClientConfig = LightningClientConfig;
168
169    fn decoder() -> Decoder {
170        LightningModuleTypes::decoder()
171    }
172}
173
174pub struct LightningModuleTypes;
175
176plugin_types_trait_impl_common!(
177    KIND,
178    LightningModuleTypes,
179    LightningClientConfig,
180    LightningInput,
181    LightningOutput,
182    LightningOutputOutcome,
183    LightningConsensusItem,
184    LightningInputError,
185    LightningOutputError
186);