1pub mod enumeration;
2pub mod options;
3pub(crate) mod options_builder;
4pub mod parlay;
5
6use std::str::FromStr;
7
8use bitcoin::key::XOnlyPublicKey;
9use bitcoin::Amount;
10use ddk_manager::contract::numerical_descriptor::NumericalDescriptor;
11use ddk_manager::{
12 contract::{
13 contract_input::{ContractInput, ContractInputInfo, OracleInput},
14 ContractDescriptor,
15 },
16 payout_curve::{
17 PayoutFunction, PayoutFunctionPiece, PayoutPoint, PolynomialPayoutCurvePiece,
18 RoundingInterval, RoundingIntervals,
19 },
20};
21use ddk_trie::OracleNumericInfo;
22
23pub fn generate_payout_curve(
24 min_price: u64,
25 max_price: u64,
26 offer_collateral: Amount,
27 accept_collateral: Amount,
28 num_steps: u64,
29 max_value: u64,
30) -> anyhow::Result<PayoutFunction> {
31 let total_collateral = offer_collateral + accept_collateral;
32 let price_range = max_price - min_price;
33 let step_size = price_range / (num_steps - 1);
34
35 let mut points = Vec::with_capacity((num_steps).try_into().unwrap());
36
37 for i in 0..num_steps {
38 let price = if i == num_steps - 1 {
39 max_price } else {
41 min_price + i * step_size
42 };
43
44 let payout = if i == num_steps - 1 {
45 total_collateral.to_sat() } else {
47 (i * total_collateral.to_sat()) / (num_steps - 1)
48 };
49 points.push(PayoutPoint {
50 event_outcome: price,
51 extra_precision: 0,
52 outcome_payout: Amount::from_sat(payout),
53 });
54 }
55
56 let final_payout_piece = points[points.len() - 1].clone();
57
58 let max_payout = PayoutPoint {
60 event_outcome: max_value,
61 extra_precision: 0,
62 outcome_payout: total_collateral,
63 };
64
65 let payout_curve_pieces = PolynomialPayoutCurvePiece::new(points)?;
66 let upper_limit = PolynomialPayoutCurvePiece::new(vec![final_payout_piece, max_payout])?;
67 Ok(PayoutFunction::new(vec![
68 PayoutFunctionPiece::PolynomialPayoutCurvePiece(payout_curve_pieces),
69 PayoutFunctionPiece::PolynomialPayoutCurvePiece(upper_limit),
70 ])?)
71}
72
73#[allow(clippy::too_many_arguments)]
74pub fn create_contract_input(
75 min_price: u64,
76 max_price: u64,
77 num_steps: u64,
78 offer_collateral: Amount,
79 accept_collateral: Amount,
80 fee_rate: u64,
81 oracle_pubkey: String,
82 event_id: String,
83) -> ContractInput {
84 let oracle_numeric_infos = OracleNumericInfo {
85 base: 2,
86 nb_digits: vec![20],
87 };
88
89 let max_value = oracle_numeric_infos
91 .base
92 .checked_pow(oracle_numeric_infos.nb_digits[0] as u32)
93 .unwrap() as u64
94 - 1;
95
96 let payout_curve = generate_payout_curve(
97 min_price,
98 max_price,
99 offer_collateral,
100 accept_collateral,
101 num_steps,
102 max_value,
103 )
104 .unwrap();
105 let rounding_intervals = RoundingIntervals {
106 intervals: vec![RoundingInterval {
107 begin_interval: 0,
108 rounding_mod: 1,
109 }],
110 };
111
112 let contract_descriptor = ContractDescriptor::Numerical(NumericalDescriptor {
113 payout_function: payout_curve,
114 rounding_intervals,
115 difference_params: None,
116 oracle_numeric_infos,
117 });
118
119 let oracles = OracleInput {
120 public_keys: vec![XOnlyPublicKey::from_str(&oracle_pubkey).unwrap()],
121 event_id,
122 threshold: 1,
123 };
124 let contract_infos = vec![ContractInputInfo {
125 contract_descriptor,
126 oracles,
127 }];
128 ContractInput {
129 offer_collateral,
130 accept_collateral,
131 fee_rate,
132 contract_flags: 0,
133 contract_infos,
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use bitcoin::Amount;
140
141 use crate::{create_contract_input, generate_payout_curve};
142
143 #[test]
144 fn payout_curve() {
145 let curve = generate_payout_curve(
146 13_000,
147 60_000,
148 Amount::from_sat(50_000),
149 Amount::from_sat(50_000),
150 10,
151 1045686,
152 );
153 assert!(curve.is_ok())
154 }
155
156 #[test]
157 fn create_contract_input_test() {
158 let oracle_pk =
159 "0d829c1cc556aa59060df5a9543c5357199ace5db9bcd5a8ddd6ee2fc7b6d174".to_string();
160 let event_id = "event".to_string();
161 let contract = create_contract_input(
162 0,
163 100_000,
164 3,
165 Amount::from_sat(50_000),
166 Amount::from_sat(50_000),
167 2,
168 oracle_pk,
169 event_id,
170 );
171
172 let json = serde_json::to_string(&contract).unwrap();
173 println!("{}", json)
174 }
175}