use crate::error::Error;
use crate::ContractId;
use bitcoin::Transaction;
use ddk_messages::{
oracle_msgs::{EventDescriptor, OracleAnnouncement, OracleAttestation},
AcceptDlc, SignDlc,
};
use ddk_trie::multi_oracle_trie::MultiOracleTrie;
use ddk_trie::multi_oracle_trie_with_diff::MultiOracleTrieWithDiff;
use secp256k1_zkp::PublicKey;
#[cfg(feature = "use-serde")]
use serde::{Deserialize, Serialize};
use signed_contract::SignedContract;
use self::utils::unordered_equal;
pub mod accepted_contract;
pub mod contract_info;
pub mod contract_input;
pub mod enum_descriptor;
pub mod numerical_descriptor;
pub mod offered_contract;
pub mod ser;
pub mod signed_contract;
pub(crate) mod utils;
#[derive(Clone)]
pub enum Contract {
Offered(offered_contract::OfferedContract),
Accepted(accepted_contract::AcceptedContract),
Signed(signed_contract::SignedContract),
Confirmed(signed_contract::SignedContract),
PreClosed(PreClosedContract),
Closed(ClosedContract),
Refunded(signed_contract::SignedContract),
FailedAccept(FailedAcceptContract),
FailedSign(FailedSignContract),
Rejected(offered_contract::OfferedContract),
}
impl std::fmt::Debug for Contract {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let state = match self {
Contract::Offered(_) => "offered",
Contract::Accepted(_) => "accepted",
Contract::Signed(_) => "signed",
Contract::Confirmed(_) => "confirmed",
Contract::PreClosed(_) => "pre-closed",
Contract::Closed(_) => "closed",
Contract::Refunded(_) => "refunded",
Contract::FailedAccept(_) => "failed accept",
Contract::FailedSign(_) => "failed sign",
Contract::Rejected(_) => "rejected",
};
f.debug_struct("Contract").field("state", &state).finish()
}
}
impl Contract {
pub fn get_id(&self) -> ContractId {
match self {
Contract::Offered(o) | Contract::Rejected(o) => o.id,
Contract::Accepted(o) => o.get_contract_id(),
Contract::Signed(o) | Contract::Confirmed(o) | Contract::Refunded(o) => {
o.accepted_contract.get_contract_id()
}
Contract::FailedAccept(c) => c.offered_contract.id,
Contract::FailedSign(c) => c.accepted_contract.get_contract_id(),
Contract::PreClosed(c) => c.signed_contract.accepted_contract.get_contract_id(),
Contract::Closed(c) => c.contract_id,
}
}
pub fn get_temporary_id(&self) -> ContractId {
match self {
Contract::Offered(o) | Contract::Rejected(o) => o.id,
Contract::Accepted(o) => o.offered_contract.id,
Contract::Signed(o) | Contract::Confirmed(o) | Contract::Refunded(o) => {
o.accepted_contract.offered_contract.id
}
Contract::FailedAccept(c) => c.offered_contract.id,
Contract::FailedSign(c) => c.accepted_contract.offered_contract.id,
Contract::PreClosed(c) => c.signed_contract.accepted_contract.offered_contract.id,
Contract::Closed(c) => c.temporary_contract_id,
}
}
pub fn get_counter_party_id(&self) -> PublicKey {
match self {
Contract::Offered(o) | Contract::Rejected(o) => o.counter_party,
Contract::Accepted(a) => a.offered_contract.counter_party,
Contract::Signed(s) | Contract::Confirmed(s) | Contract::Refunded(s) => {
s.accepted_contract.offered_contract.counter_party
}
Contract::PreClosed(c) => {
c.signed_contract
.accepted_contract
.offered_contract
.counter_party
}
Contract::Closed(c) => c.counter_party_id,
Contract::FailedAccept(f) => f.offered_contract.counter_party,
Contract::FailedSign(f) => f.accepted_contract.offered_contract.counter_party,
}
}
}
#[derive(Clone)]
pub struct FailedAcceptContract {
pub offered_contract: offered_contract::OfferedContract,
pub accept_message: AcceptDlc,
pub error_message: String,
}
#[derive(Clone)]
pub struct FailedSignContract {
pub accepted_contract: accepted_contract::AcceptedContract,
pub sign_message: SignDlc,
pub error_message: String,
}
#[derive(Clone)]
pub struct PreClosedContract {
pub signed_contract: SignedContract,
pub attestations: Option<Vec<OracleAttestation>>,
pub signed_cet: Transaction,
}
#[derive(Clone)]
pub struct ClosedContract {
pub attestations: Option<Vec<OracleAttestation>>,
pub signed_cet: Option<Transaction>,
pub contract_id: ContractId,
pub temporary_contract_id: ContractId,
pub counter_party_id: PublicKey,
pub pnl: i64,
}
#[derive(Clone)]
pub enum AdaptorInfo {
Enum,
Numerical(MultiOracleTrie),
NumericalWithDifference(MultiOracleTrieWithDiff),
}
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "use-serde",
derive(Serialize, Deserialize),
serde(rename_all = "camelCase")
)]
pub enum ContractDescriptor {
Enum(enum_descriptor::EnumDescriptor),
Numerical(numerical_descriptor::NumericalDescriptor),
}
impl ContractDescriptor {
pub fn get_oracle_params(&self) -> Option<numerical_descriptor::DifferenceParams> {
match self {
ContractDescriptor::Enum(_) => None,
ContractDescriptor::Numerical(n) => n.difference_params.clone(),
}
}
pub fn validate(
&self,
announcements: &Vec<OracleAnnouncement>,
) -> Result<(), crate::error::Error> {
let first = announcements
.first()
.expect("to have at least one element.");
match &first.oracle_event.event_descriptor {
EventDescriptor::EnumEvent(ee) => {
for announcement in announcements {
match &announcement.oracle_event.event_descriptor {
EventDescriptor::EnumEvent(enum_desc) => {
if !unordered_equal(&ee.outcomes, &enum_desc.outcomes) {
return Err(Error::InvalidParameters(
"Oracles don't have same enum outcomes.".to_string(),
));
}
}
_ => {
return Err(Error::InvalidParameters(
"Expected enum event descriptor.".to_string(),
))
}
}
}
match self {
ContractDescriptor::Enum(ed) => ed.validate(ee),
_ => Err(Error::InvalidParameters(
"Event descriptor from contract and oracle differ.".to_string(),
)),
}
}
EventDescriptor::DigitDecompositionEvent(_) => match self {
ContractDescriptor::Numerical(n) => {
let min_nb_digits = n.oracle_numeric_infos.get_min_nb_digits();
let max_value = n
.oracle_numeric_infos
.base
.checked_pow(min_nb_digits as u32)
.ok_or_else(|| {
Error::InvalidParameters("Could not compute max value".to_string())
})?;
n.validate((max_value - 1) as u64)
}
_ => Err(Error::InvalidParameters(
"Event descriptor from contract and oracle differ.".to_string(),
)),
},
}
}
}