use super::AdaptorInfo;
use crate::error::Error;
use crate::payout_curve::{PayoutFunction, RoundingIntervals};
use bitcoin::{Amount, Script, Transaction};
use dlc::{Payout, RangePayout};
use dlc_trie::multi_oracle_trie::MultiOracleTrie;
use dlc_trie::multi_oracle_trie_with_diff::MultiOracleTrieWithDiff;
use dlc_trie::{DlcTrie, OracleNumericInfo};
use secp256k1_zkp::{All, EcdsaAdaptorSignature, PublicKey, Secp256k1, SecretKey};
#[cfg(feature = "use-serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "use-serde",
derive(Serialize, Deserialize),
serde(rename_all = "camelCase")
)]
pub struct DifferenceParams {
pub max_error_exp: usize,
pub min_support_exp: usize,
pub maximize_coverage: bool,
}
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "use-serde",
derive(Serialize, Deserialize),
serde(rename_all = "camelCase")
)]
pub struct NumericalDescriptor {
pub payout_function: PayoutFunction,
pub rounding_intervals: RoundingIntervals,
pub difference_params: Option<DifferenceParams>,
pub oracle_numeric_infos: OracleNumericInfo,
}
impl NumericalDescriptor {
pub fn get_range_payouts(&self, total_collateral: Amount) -> Result<Vec<RangePayout>, Error> {
self.payout_function
.to_range_payouts(total_collateral, &self.rounding_intervals)
}
pub fn validate(&self, max_value: u64) -> Result<(), Error> {
self.rounding_intervals.validate()?;
self.payout_function.validate(max_value)
}
pub fn get_payouts(&self, total_collateral: Amount) -> Result<Vec<Payout>, Error> {
Ok(self
.get_range_payouts(total_collateral)?
.iter()
.map(|x| x.payout.clone())
.collect())
}
pub fn verify_and_get_adaptor_info(
&self,
secp: &Secp256k1<All>,
total_collateral: Amount,
fund_pubkey: &PublicKey,
funding_script_pubkey: &Script,
fund_output_value: Amount,
threshold: usize,
precomputed_points: &[Vec<Vec<PublicKey>>],
cets: &[Transaction],
adaptor_pairs: &[EcdsaAdaptorSignature],
adaptor_index_start: usize,
) -> Result<(AdaptorInfo, usize), Error> {
match &self.difference_params {
Some(params) => {
let mut multi_trie = MultiOracleTrieWithDiff::new(
&self.oracle_numeric_infos,
threshold,
params.min_support_exp,
params.max_error_exp,
)?;
let index = multi_trie.generate_verify(
secp,
fund_pubkey,
funding_script_pubkey,
fund_output_value,
&self.get_range_payouts(total_collateral)?,
cets,
precomputed_points,
adaptor_pairs,
adaptor_index_start,
)?;
Ok((AdaptorInfo::NumericalWithDifference(multi_trie), index))
}
None => {
let mut trie = MultiOracleTrie::new(&self.oracle_numeric_infos, threshold)?;
let index = trie.generate_verify(
secp,
fund_pubkey,
funding_script_pubkey,
fund_output_value,
&self.get_range_payouts(total_collateral)?,
cets,
precomputed_points,
adaptor_pairs,
adaptor_index_start,
)?;
Ok((AdaptorInfo::Numerical(trie), index))
}
}
}
pub fn get_adaptor_info(
&self,
secp: &Secp256k1<All>,
total_collateral: Amount,
fund_priv_key: &SecretKey,
funding_script_pubkey: &Script,
fund_output_value: Amount,
threshold: usize,
precomputed_points: &[Vec<Vec<PublicKey>>],
cets: &[Transaction],
adaptor_index_start: usize,
) -> Result<(AdaptorInfo, Vec<EcdsaAdaptorSignature>), Error> {
match &self.difference_params {
Some(params) => {
let mut multi_trie = MultiOracleTrieWithDiff::new(
&self.oracle_numeric_infos,
threshold,
params.min_support_exp,
params.max_error_exp,
)?;
let adaptor_pairs = multi_trie.generate_sign(
secp,
fund_priv_key,
funding_script_pubkey,
fund_output_value,
&self.get_range_payouts(total_collateral)?,
cets,
precomputed_points,
adaptor_index_start,
)?;
Ok((
AdaptorInfo::NumericalWithDifference(multi_trie),
adaptor_pairs,
))
}
None => {
let mut trie = MultiOracleTrie::new(&self.oracle_numeric_infos, threshold)?;
let sigs = trie.generate_sign(
secp,
fund_priv_key,
funding_script_pubkey,
fund_output_value,
&self.get_range_payouts(total_collateral)?,
cets,
precomputed_points,
adaptor_index_start,
)?;
Ok((AdaptorInfo::Numerical(trie), sigs))
}
}
}
}