fedimint_ln_common/contracts/
mod.rs

1pub mod incoming;
2pub mod outgoing;
3
4use std::io::Error;
5
6use bitcoin::hashes::sha256::Hash as Sha256;
7use bitcoin::hashes::{Hash as BitcoinHash, hash_newtype};
8use fedimint_core::encoding::{Decodable, DecodeError, Encodable};
9use fedimint_core::module::registry::ModuleDecoderRegistry;
10use fedimint_core::{OutPoint, secp256k1};
11use serde::{Deserialize, Serialize};
12
13/// Anything representing a contract which thus has an associated [`ContractId`]
14pub trait IdentifiableContract: Encodable {
15    fn contract_id(&self) -> ContractId;
16}
17
18hash_newtype!(
19    /// The hash of a LN incoming contract
20    pub struct ContractId(Sha256);
21);
22
23/// A contract before execution as found in transaction outputs
24// TODO: investigate if this is actually a problem
25#[allow(clippy::large_enum_variant)]
26#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
27pub enum Contract {
28    Incoming(incoming::IncomingContract),
29    Outgoing(outgoing::OutgoingContract),
30}
31
32/// A contract after execution as saved in the database
33#[allow(clippy::large_enum_variant)]
34#[derive(Debug, Clone, Eq, PartialEq, Hash, Encodable, Decodable, Serialize, Deserialize)]
35pub enum FundedContract {
36    Incoming(incoming::FundedIncomingContract),
37    Outgoing(outgoing::OutgoingContract),
38}
39
40/// Outcome of a contract. Only incoming contracts currently need to communicate
41/// anything back to the user (the decrypted preimage).
42#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
43pub enum ContractOutcome {
44    Incoming(DecryptedPreimage),
45    Outgoing(OutgoingContractOutcome),
46}
47
48impl ContractOutcome {
49    pub fn is_permanent(&self) -> bool {
50        match self {
51            ContractOutcome::Incoming(o) => o.is_permanent(),
52            ContractOutcome::Outgoing(_) => true,
53        }
54    }
55}
56
57#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
58pub struct OutgoingContractOutcome {}
59
60impl IdentifiableContract for Contract {
61    fn contract_id(&self) -> ContractId {
62        match self {
63            Contract::Incoming(c) => c.contract_id(),
64            Contract::Outgoing(c) => c.contract_id(),
65        }
66    }
67}
68
69impl IdentifiableContract for FundedContract {
70    fn contract_id(&self) -> ContractId {
71        match self {
72            FundedContract::Incoming(c) => c.contract.contract_id(),
73            FundedContract::Outgoing(c) => c.contract_id(),
74        }
75    }
76}
77
78impl Contract {
79    /// Creates the initial contract outcome that is created on transaction
80    /// acceptance. Depending on the contract type it is not yet final.
81    pub fn to_outcome(&self) -> ContractOutcome {
82        match self {
83            Contract::Incoming(_) => ContractOutcome::Incoming(DecryptedPreimage::Pending),
84            Contract::Outgoing(_) => ContractOutcome::Outgoing(OutgoingContractOutcome {}),
85        }
86    }
87
88    /// Converts a contract to its executed version.
89    pub fn to_funded(self, out_point: OutPoint) -> FundedContract {
90        match self {
91            Contract::Incoming(incoming) => {
92                FundedContract::Incoming(incoming::FundedIncomingContract {
93                    contract: incoming,
94                    out_point,
95                })
96            }
97            Contract::Outgoing(outgoing) => FundedContract::Outgoing(outgoing),
98        }
99    }
100}
101
102impl Encodable for ContractId {
103    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
104        self.to_byte_array().consensus_encode(writer)
105    }
106}
107
108impl Decodable for ContractId {
109    fn consensus_decode_partial<D: std::io::Read>(
110        d: &mut D,
111        modules: &ModuleDecoderRegistry,
112    ) -> Result<Self, DecodeError> {
113        Ok(ContractId::from_byte_array(
114            Decodable::consensus_decode_partial(d, modules)?,
115        ))
116    }
117}
118
119#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
120pub struct Preimage(pub [u8; 32]);
121
122#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
123pub struct PreimageKey(#[serde(with = "serde_big_array::BigArray")] pub [u8; 33]);
124
125impl PreimageKey {
126    /// Create a Schnorr public key
127    ///
128    /// # Errors
129    ///
130    /// Returns [`secp256k1::Error::InvalidPublicKey`] if the Preimage does not
131    /// represent a valid Secp256k1 point x coordinate.
132    pub fn to_public_key(&self) -> Result<secp256k1::PublicKey, secp256k1::Error> {
133        secp256k1::PublicKey::from_slice(&self.0)
134    }
135}
136
137/// Current status of preimage decryption
138#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
139pub enum DecryptedPreimageStatus {
140    /// There aren't enough decryption shares yet
141    Pending,
142    /// The decrypted preimage was valid
143    Some(Preimage),
144    /// The decrypted preimage was invalid
145    Invalid,
146}
147
148/// Possible outcomes of preimage decryption
149#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
150pub enum DecryptedPreimage {
151    /// There aren't enough decryption shares yet
152    Pending,
153    /// The decrypted preimage was valid
154    Some(PreimageKey),
155    /// The decrypted preimage was invalid
156    Invalid,
157}
158
159impl DecryptedPreimage {
160    pub fn is_permanent(&self) -> bool {
161        match self {
162            DecryptedPreimage::Pending => false,
163            DecryptedPreimage::Some(_) | DecryptedPreimage::Invalid => true,
164        }
165    }
166}
167/// Threshold-encrypted [`Preimage`]
168#[derive(Debug, Clone, Eq, PartialEq, Hash, Encodable, Decodable, Deserialize, Serialize)]
169pub struct EncryptedPreimage(pub threshold_crypto::Ciphertext);
170
171/// Share to decrypt an [`EncryptedPreimage`]
172#[derive(Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Serialize, Deserialize)]
173pub struct PreimageDecryptionShare(pub threshold_crypto::DecryptionShare);
174
175impl EncryptedPreimage {
176    pub fn new(preimage_key: &PreimageKey, key: &threshold_crypto::PublicKey) -> EncryptedPreimage {
177        EncryptedPreimage(key.encrypt(preimage_key.0))
178    }
179}