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
7pub 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::{
26 Amount, OutPoint, extensible_associated_module_type, plugin_types_trait_impl_common,
27};
28pub use fedimint_ln_common::client::GatewayApi;
29use lightning_invoice::Bolt11Invoice;
30use serde::{Deserialize, Serialize};
31use thiserror::Error;
32use tpe::AggregateDecryptionKey;
33
34use crate::contracts::{IncomingContract, OutgoingContract};
35
36#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
37pub enum Bolt11InvoiceDescription {
38 Direct(String),
39 Hash(sha256::Hash),
40}
41
42#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Decodable, Encodable)]
43pub enum LightningInvoice {
44 Bolt11(Bolt11Invoice),
45}
46
47pub const KIND: ModuleKind = ModuleKind::from_static_str("lnv2");
48pub const MODULE_CONSENSUS_VERSION: ModuleConsensusVersion = ModuleConsensusVersion::new(1, 0);
49
50pub const MINIMUM_INCOMING_CONTRACT_AMOUNT: Amount = Amount::from_sats(5);
53
54#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
55pub struct ContractId(pub sha256::Hash);
56
57extensible_associated_module_type!(
58 LightningInput,
59 LightningInputV0,
60 UnknownLightningInputVariantError
61);
62
63#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
64pub enum LightningInputV0 {
65 Outgoing(OutPoint, OutgoingWitness),
66 Incoming(OutPoint, AggregateDecryptionKey),
67}
68
69#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
70pub enum OutgoingWitness {
71 Claim([u8; 32]),
72 Refund,
73 Cancel(Signature),
74}
75
76impl std::fmt::Display for LightningInputV0 {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 write!(f, "LightningInputV0",)
79 }
80}
81
82extensible_associated_module_type!(
83 LightningOutput,
84 LightningOutputV0,
85 UnknownLightningOutputVariantError
86);
87
88#[allow(clippy::large_enum_variant)]
89#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
90pub enum LightningOutputV0 {
91 Outgoing(OutgoingContract),
92 Incoming(IncomingContract),
93}
94
95impl std::fmt::Display for LightningOutputV0 {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 write!(f, "LightningOutputV0")
98 }
99}
100
101#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
102pub struct LightningOutputOutcome;
103
104impl std::fmt::Display for LightningOutputOutcome {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 write!(f, "LightningOutputOutcome")
107 }
108}
109
110#[derive(Debug, Clone, Eq, PartialEq, Hash, Error, Encodable, Decodable)]
111pub enum LightningInputError {
112 #[error("The lightning input version is not supported by this federation")]
113 UnknownInputVariant(#[from] UnknownLightningInputVariantError),
114 #[error("No contract found for given ContractId")]
115 UnknownContract,
116 #[error("The preimage is invalid")]
117 InvalidPreimage,
118 #[error("The contracts locktime has passed")]
119 Expired,
120 #[error("The contracts locktime has not yet passed")]
121 NotExpired,
122 #[error("The aggregate decryption key is invalid")]
123 InvalidDecryptionKey,
124 #[error("The forfeit signature is invalid")]
125 InvalidForfeitSignature,
126}
127
128#[derive(Debug, Clone, Eq, PartialEq, Hash, Error, Encodable, Decodable)]
129pub enum LightningOutputError {
130 #[error("The lightning input version is not supported by this federation")]
131 UnknownOutputVariant(#[from] UnknownLightningOutputVariantError),
132 #[error("The contract is invalid")]
133 InvalidContract,
134 #[error("The contract is expired")]
135 ContractExpired,
136}
137
138#[derive(Debug, Clone, Hash, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
139pub enum LightningConsensusItem {
140 BlockCountVote(u64),
141 UnixTimeVote(u64),
142 #[encodable_default]
143 Default {
144 variant: u64,
145 bytes: Vec<u8>,
146 },
147}
148
149impl std::fmt::Display for LightningConsensusItem {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 LightningConsensusItem::BlockCountVote(c) => {
153 write!(f, "LNv2 Block Count {c}")
154 }
155 LightningConsensusItem::UnixTimeVote(t) => {
156 write!(f, "LNv2 Unix Time {t}")
157 }
158 LightningConsensusItem::Default { variant, bytes } => write!(
159 f,
160 "LNv2 Unknown - variant: {variant}, bytes_len: {}",
161 bytes.len()
162 ),
163 }
164 }
165}
166
167#[derive(Debug)]
168pub struct LightningCommonInit;
169
170impl CommonModuleInit for LightningCommonInit {
171 const CONSENSUS_VERSION: ModuleConsensusVersion = MODULE_CONSENSUS_VERSION;
172 const KIND: ModuleKind = KIND;
173
174 type ClientConfig = LightningClientConfig;
175
176 fn decoder() -> Decoder {
177 LightningModuleTypes::decoder()
178 }
179}
180
181pub struct LightningModuleTypes;
182
183plugin_types_trait_impl_common!(
184 KIND,
185 LightningModuleTypes,
186 LightningClientConfig,
187 LightningInput,
188 LightningOutput,
189 LightningOutputOutcome,
190 LightningConsensusItem,
191 LightningInputError,
192 LightningOutputError
193);