1use 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)]
31pub enum Contract {
33 Offered(offered_contract::OfferedContract),
35 Accepted(accepted_contract::AcceptedContract),
37 Signed(signed_contract::SignedContract),
39 Confirmed(signed_contract::SignedContract),
41 PreClosed(PreClosedContract),
43 Closed(ClosedContract),
45 Refunded(signed_contract::SignedContract),
47 FailedAccept(FailedAcceptContract),
49 FailedSign(FailedSignContract),
51 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 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 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 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 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 pub fn is_offer_party(&self) -> bool {
139 match self {
140 Contract::Offered(o) | Contract::Rejected(o) => o.is_offer_party,
141 Contract::Accepted(a) => a.offered_contract.is_offer_party,
142 Contract::Signed(s) | Contract::Confirmed(s) | Contract::Refunded(s) => {
143 s.accepted_contract.offered_contract.is_offer_party
144 }
145 Contract::FailedAccept(f) => f.offered_contract.is_offer_party,
146 Contract::FailedSign(f) => f.accepted_contract.offered_contract.is_offer_party,
147 Contract::PreClosed(c) => {
148 c.signed_contract
149 .accepted_contract
150 .offered_contract
151 .is_offer_party
152 }
153 Contract::Closed(_) => false,
154 }
155 }
156
157 pub fn get_collateral(
159 &self,
160 ) -> (
161 u64, u64, u64, ) {
165 match self {
167 Contract::Offered(o) => (
168 o.offer_params.collateral,
169 o.total_collateral - o.offer_params.collateral,
170 o.total_collateral,
171 ),
172 Contract::Accepted(a) => (
173 a.offered_contract.offer_params.collateral,
174 a.accept_params.collateral,
175 a.offered_contract.total_collateral,
176 ),
177 Contract::Signed(s) | Contract::Confirmed(s) | Contract::Refunded(s) => (
178 s.accepted_contract.offered_contract.offer_params.collateral,
179 s.accepted_contract.accept_params.collateral,
180 s.accepted_contract.offered_contract.total_collateral,
181 ),
182 Contract::FailedAccept(f) => (
183 f.offered_contract.offer_params.collateral,
184 0,
185 f.offered_contract.total_collateral,
186 ),
187 Contract::FailedSign(f) => (
188 f.accepted_contract.offered_contract.offer_params.collateral,
189 f.accepted_contract.accept_params.collateral,
190 f.accepted_contract.offered_contract.total_collateral,
191 ),
192 Contract::PreClosed(p) => (
193 p.signed_contract
194 .accepted_contract
195 .offered_contract
196 .offer_params
197 .collateral,
198 p.signed_contract.accepted_contract.accept_params.collateral,
199 p.signed_contract
200 .accepted_contract
201 .offered_contract
202 .total_collateral,
203 ),
204 Contract::Closed(_) => (0, 0, 0),
205 Contract::Rejected(_) => (0, 0, 0),
206 }
207 }
208
209 pub fn get_cet_locktime(&self) -> u32 {
211 match self {
212 Contract::Offered(o) => o.cet_locktime,
213 Contract::Accepted(a) => a.offered_contract.cet_locktime,
214 Contract::Signed(s) => s.accepted_contract.offered_contract.cet_locktime,
215 Contract::Confirmed(c) => c.accepted_contract.offered_contract.cet_locktime,
216 Contract::PreClosed(p) => {
217 p.signed_contract
218 .accepted_contract
219 .offered_contract
220 .cet_locktime
221 }
222 Contract::Closed(c) => c.signed_cet.as_ref().unwrap().lock_time.to_consensus_u32(),
223 Contract::Refunded(r) => r.accepted_contract.offered_contract.cet_locktime,
224 Contract::FailedAccept(f) => f.offered_contract.cet_locktime,
225 Contract::FailedSign(f) => f.accepted_contract.offered_contract.cet_locktime,
226 Contract::Rejected(_) => 0,
227 }
228 }
229
230 pub fn get_refund_locktime(&self) -> u32 {
232 match self {
233 Contract::Offered(o) => o.refund_locktime,
234 Contract::Accepted(a) => a.offered_contract.refund_locktime,
235 Contract::Signed(s) => s.accepted_contract.offered_contract.refund_locktime,
236 Contract::Confirmed(c) => c.accepted_contract.offered_contract.refund_locktime,
237 Contract::PreClosed(p) => {
238 p.signed_contract
239 .accepted_contract
240 .offered_contract
241 .refund_locktime
242 }
243 Contract::Closed(c) => c.signed_cet.as_ref().unwrap().lock_time.to_consensus_u32(),
244 Contract::Refunded(r) => r.accepted_contract.offered_contract.refund_locktime,
245 Contract::FailedAccept(f) => f.offered_contract.refund_locktime,
246 Contract::FailedSign(f) => f.accepted_contract.offered_contract.refund_locktime,
247 Contract::Rejected(_) => 0,
248 }
249 }
250
251 pub fn get_pnl(&self) -> i64 {
253 match self {
254 Contract::Offered(_) => 0,
255 Contract::Accepted(_) => 0,
256 Contract::Signed(_) => 0,
257 Contract::Confirmed(_) => 0,
258 Contract::PreClosed(_) => 0,
259 Contract::Closed(c) => c.pnl,
260 Contract::Refunded(_) => 0,
261 Contract::FailedAccept(_) => 0,
262 Contract::FailedSign(_) => 0,
263 Contract::Rejected(_) => 0,
264 }
265 }
266}
267
268#[derive(Clone)]
270pub struct FailedAcceptContract {
271 pub offered_contract: offered_contract::OfferedContract,
273 pub accept_message: AcceptDlc,
275 pub error_message: String,
277}
278
279#[derive(Clone)]
281pub struct FailedSignContract {
282 pub accepted_contract: accepted_contract::AcceptedContract,
284 pub sign_message: SignDlc,
286 pub error_message: String,
288}
289
290#[derive(Clone)]
292pub struct PreClosedContract {
293 pub signed_contract: SignedContract,
295 pub attestations: Option<Vec<OracleAttestation>>,
297 pub signed_cet: Transaction,
299}
300
301#[derive(Clone)]
303pub struct ClosedContract {
304 pub attestations: Option<Vec<OracleAttestation>>,
306 pub signed_cet: Option<Transaction>,
308 pub contract_id: ContractId,
310 pub temporary_contract_id: ContractId,
312 pub counter_party_id: PublicKey,
314 pub pnl: i64,
316}
317
318#[derive(Clone)]
321pub enum AdaptorInfo {
322 Enum,
324 Numerical(MultiOracleTrie),
326 NumericalWithDifference(MultiOracleTrieWithDiff),
329}
330
331#[derive(Clone, Debug)]
333#[cfg_attr(
334 feature = "use-serde",
335 derive(Serialize, Deserialize),
336 serde(rename_all = "camelCase")
337)]
338pub enum ContractDescriptor {
339 Enum(enum_descriptor::EnumDescriptor),
341 Numerical(numerical_descriptor::NumericalDescriptor),
343}
344
345impl ContractDescriptor {
346 pub fn get_oracle_params(&self) -> Option<numerical_descriptor::DifferenceParams> {
348 match self {
349 ContractDescriptor::Enum(_) => None,
350 ContractDescriptor::Numerical(n) => n.difference_params.clone(),
351 }
352 }
353
354 pub fn validate(
357 &self,
358 announcements: &Vec<OracleAnnouncement>,
359 ) -> Result<(), crate::error::Error> {
360 let first = announcements
361 .first()
362 .expect("to have at least one element.");
363 match &first.oracle_event.event_descriptor {
364 EventDescriptor::EnumEvent(ee) => {
365 for announcement in announcements {
366 match &announcement.oracle_event.event_descriptor {
367 EventDescriptor::EnumEvent(enum_desc) => {
368 if !unordered_equal(&ee.outcomes, &enum_desc.outcomes) {
369 return Err(Error::InvalidParameters(
370 "Oracles don't have same enum outcomes.".to_string(),
371 ));
372 }
373 }
374 _ => {
375 return Err(Error::InvalidParameters(
376 "Expected enum event descriptor.".to_string(),
377 ))
378 }
379 }
380 }
381 match self {
382 ContractDescriptor::Enum(ed) => ed.validate(ee),
383 _ => Err(Error::InvalidParameters(
384 "Event descriptor from contract and oracle differ.".to_string(),
385 )),
386 }
387 }
388 EventDescriptor::DigitDecompositionEvent(_) => match self {
389 ContractDescriptor::Numerical(n) => {
390 let min_nb_digits = n.oracle_numeric_infos.get_min_nb_digits();
391 let max_value = n
392 .oracle_numeric_infos
393 .base
394 .checked_pow(min_nb_digits as u32)
395 .ok_or_else(|| {
396 Error::InvalidParameters("Could not compute max value".to_string())
397 })?;
398 n.validate((max_value - 1) as u64)
399 }
400 _ => Err(Error::InvalidParameters(
401 "Event descriptor from contract and oracle differ.".to_string(),
402 )),
403 },
404 }
405 }
406}