dlc_manager/contract/
mod.rs

1//! Module containing structures and functions related to contracts.
2
3use crate::error::Error;
4use crate::ContractId;
5use bitcoin::{SignedAmount, Transaction};
6use dlc_messages::{
7    oracle_msgs::{EventDescriptor, OracleAnnouncement, OracleAttestation},
8    AcceptDlc, SignDlc,
9};
10use dlc_trie::multi_oracle_trie::MultiOracleTrie;
11use dlc_trie::multi_oracle_trie_with_diff::MultiOracleTrieWithDiff;
12use secp256k1_zkp::PublicKey;
13#[cfg(feature = "use-serde")]
14use serde::{Deserialize, Serialize};
15use signed_contract::SignedContract;
16
17use self::utils::unordered_equal;
18
19pub mod accepted_contract;
20pub mod contract_info;
21pub mod contract_input;
22pub mod enum_descriptor;
23pub mod numerical_descriptor;
24pub mod offered_contract;
25pub mod ser;
26pub mod signed_contract;
27pub(crate) mod utils;
28
29#[derive(Clone)]
30/// Enum representing the possible states of a DLC.
31pub enum Contract {
32    /// Initial state where a contract is being proposed.
33    Offered(offered_contract::OfferedContract),
34    /// A contract that was accepted.
35    Accepted(accepted_contract::AcceptedContract),
36    /// A contract for which signatures have been produced.
37    Signed(signed_contract::SignedContract),
38    /// A contract whose funding transaction was included in the blockchain.
39    Confirmed(signed_contract::SignedContract),
40    /// A contract for which a CET was broadcasted, but not neccesarily confirmed to blockchain
41    PreClosed(PreClosedContract),
42    /// A contract for which a CET was confirmed to blockchain
43    Closed(ClosedContract),
44    /// A contract whose refund transaction was broadcast.
45    Refunded(signed_contract::SignedContract),
46    /// A contract that failed when verifying information from an accept message.
47    FailedAccept(FailedAcceptContract),
48    /// A contract that failed when verifying information from a sign message.
49    FailedSign(FailedSignContract),
50    /// A contract that was rejected by the party to whom it was offered.
51    Rejected(offered_contract::OfferedContract),
52}
53
54impl std::fmt::Debug for Contract {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        let state = match self {
57            Contract::Offered(_) => "offered",
58            Contract::Accepted(_) => "accepted",
59            Contract::Signed(_) => "signed",
60            Contract::Confirmed(_) => "confirmed",
61            Contract::PreClosed(_) => "pre-closed",
62            Contract::Closed(_) => "closed",
63            Contract::Refunded(_) => "refunded",
64            Contract::FailedAccept(_) => "failed accept",
65            Contract::FailedSign(_) => "failed sign",
66            Contract::Rejected(_) => "rejected",
67        };
68        f.debug_struct("Contract").field("state", &state).finish()
69    }
70}
71
72impl Contract {
73    /// Get the id of a contract. Returns the temporary contract id for offered
74    /// and failed accept contracts.
75    pub fn get_id(&self) -> ContractId {
76        match self {
77            Contract::Offered(o) | Contract::Rejected(o) => o.id,
78            Contract::Accepted(o) => o.get_contract_id(),
79            Contract::Signed(o) | Contract::Confirmed(o) | Contract::Refunded(o) => {
80                o.accepted_contract.get_contract_id()
81            }
82            Contract::FailedAccept(c) => c.offered_contract.id,
83            Contract::FailedSign(c) => c.accepted_contract.get_contract_id(),
84            Contract::PreClosed(c) => c.signed_contract.accepted_contract.get_contract_id(),
85            Contract::Closed(c) => c.contract_id,
86        }
87    }
88
89    /// Returns the temporary contract id of a contract.
90    pub fn get_temporary_id(&self) -> ContractId {
91        match self {
92            Contract::Offered(o) | Contract::Rejected(o) => o.id,
93            Contract::Accepted(o) => o.offered_contract.id,
94            Contract::Signed(o) | Contract::Confirmed(o) | Contract::Refunded(o) => {
95                o.accepted_contract.offered_contract.id
96            }
97            Contract::FailedAccept(c) => c.offered_contract.id,
98            Contract::FailedSign(c) => c.accepted_contract.offered_contract.id,
99            Contract::PreClosed(c) => c.signed_contract.accepted_contract.offered_contract.id,
100            Contract::Closed(c) => c.temporary_contract_id,
101        }
102    }
103
104    /// Returns the public key of the counter party's node.
105    pub fn get_counter_party_id(&self) -> PublicKey {
106        match self {
107            Contract::Offered(o) | Contract::Rejected(o) => o.counter_party,
108            Contract::Accepted(a) => a.offered_contract.counter_party,
109            Contract::Signed(s) | Contract::Confirmed(s) | Contract::Refunded(s) => {
110                s.accepted_contract.offered_contract.counter_party
111            }
112            Contract::PreClosed(c) => {
113                c.signed_contract
114                    .accepted_contract
115                    .offered_contract
116                    .counter_party
117            }
118            Contract::Closed(c) => c.counter_party_id,
119            Contract::FailedAccept(f) => f.offered_contract.counter_party,
120            Contract::FailedSign(f) => f.accepted_contract.offered_contract.counter_party,
121        }
122    }
123}
124
125/// Information about a contract that failed while verifying an accept message.
126#[derive(Clone)]
127pub struct FailedAcceptContract {
128    /// The offered contract that was accepted.
129    pub offered_contract: offered_contract::OfferedContract,
130    /// The received accept message.
131    pub accept_message: AcceptDlc,
132    /// The error message that was generated.
133    pub error_message: String,
134}
135
136/// Information about a contract that failed while verifying a sign message.
137#[derive(Clone)]
138pub struct FailedSignContract {
139    /// The accepted contract that was signed.
140    pub accepted_contract: accepted_contract::AcceptedContract,
141    /// The sign message that was received.
142    pub sign_message: SignDlc,
143    /// The error message that was generated.
144    pub error_message: String,
145}
146
147/// Information about a contract that is almost closed by a broadcasted, but not confirmed CET.
148#[derive(Clone)]
149pub struct PreClosedContract {
150    /// The signed contract that was closed.
151    pub signed_contract: SignedContract,
152    /// The attestations that were used to decrypt the broadcast CET.
153    pub attestations: Option<Vec<OracleAttestation>>,
154    /// The signed version of the CET that was broadcast.
155    pub signed_cet: Transaction,
156}
157
158/// Information about a contract that was closed by a CET that was confirmed on the blockchain.
159#[derive(Clone)]
160pub struct ClosedContract {
161    /// The attestations that were used to decrypt the broadcast CET.
162    pub attestations: Option<Vec<OracleAttestation>>,
163    /// The signed version of the CET that was broadcast.
164    pub signed_cet: Option<Transaction>,
165    /// The id of the contract
166    pub contract_id: ContractId,
167    /// The temporary id of the contract.
168    pub temporary_contract_id: ContractId,
169    /// The public key of the counter-party's node.
170    pub counter_party_id: PublicKey,
171    /// The profit and loss for the given contract
172    pub pnl: SignedAmount,
173}
174
175/// Information about the adaptor signatures and the CET for which they are
176/// valid.
177#[derive(Clone)]
178pub enum AdaptorInfo {
179    /// For enumeration outcome DLC, no special information needs to be kept.
180    Enum,
181    /// For numerical outcome DLC, a trie is used to store the information.
182    Numerical(MultiOracleTrie),
183    /// For numerical outcome DLC where oracles are allowed to diverge to some
184    /// extent in the outcome value, a trie of trie is used to store the information.
185    NumericalWithDifference(MultiOracleTrieWithDiff),
186}
187
188/// The descriptor of a contract.
189#[derive(Clone, Debug)]
190#[cfg_attr(
191    feature = "use-serde",
192    derive(Serialize, Deserialize),
193    serde(rename_all = "camelCase")
194)]
195pub enum ContractDescriptor {
196    /// Case for enumeration outcome DLC.
197    Enum(enum_descriptor::EnumDescriptor),
198    /// Case for numerical outcome DLC.
199    Numerical(numerical_descriptor::NumericalDescriptor),
200}
201
202impl ContractDescriptor {
203    /// Get the parameters on allowed divergence between oracle if any.
204    pub fn get_oracle_params(&self) -> Option<numerical_descriptor::DifferenceParams> {
205        match self {
206            ContractDescriptor::Enum(_) => None,
207            ContractDescriptor::Numerical(n) => n.difference_params.clone(),
208        }
209    }
210
211    /// Validate that all possible outcomes that can be attested by the oracle(s)
212    /// have a single associated payout.
213    pub fn validate(
214        &self,
215        announcements: &Vec<OracleAnnouncement>,
216    ) -> Result<(), crate::error::Error> {
217        let first = announcements
218            .first()
219            .expect("to have at least one element.");
220        match &first.oracle_event.event_descriptor {
221            EventDescriptor::EnumEvent(ee) => {
222                for announcement in announcements {
223                    match &announcement.oracle_event.event_descriptor {
224                        EventDescriptor::EnumEvent(enum_desc) => {
225                            if !unordered_equal(&ee.outcomes, &enum_desc.outcomes) {
226                                return Err(Error::InvalidParameters(
227                                    "Oracles don't have same enum outcomes.".to_string(),
228                                ));
229                            }
230                        }
231                        _ => {
232                            return Err(Error::InvalidParameters(
233                                "Expected enum event descriptor.".to_string(),
234                            ))
235                        }
236                    }
237                }
238                match self {
239                    ContractDescriptor::Enum(ed) => ed.validate(ee),
240                    _ => Err(Error::InvalidParameters(
241                        "Event descriptor from contract and oracle differ.".to_string(),
242                    )),
243                }
244            }
245            EventDescriptor::DigitDecompositionEvent(_) => match self {
246                ContractDescriptor::Numerical(n) => {
247                    let min_nb_digits = n.oracle_numeric_infos.get_min_nb_digits();
248                    let max_value = n
249                        .oracle_numeric_infos
250                        .base
251                        .checked_pow(min_nb_digits as u32)
252                        .ok_or_else(|| {
253                            Error::InvalidParameters("Could not compute max value".to_string())
254                        })?;
255                    n.validate((max_value - 1) as u64)
256                }
257                _ => Err(Error::InvalidParameters(
258                    "Event descriptor from contract and oracle differ.".to_string(),
259                )),
260            },
261        }
262    }
263}