ddk_manager/contract/
mod.rs

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