1use std::collections::HashSet;
8use std::sync::Arc;
9
10use crate::builder::script::{
11 BaseDepositScript, Multisig, ReplacementDepositScript, SpendableScript, TimelockScript,
12};
13use crate::builder::transaction::create_move_to_vault_txhandler;
14use crate::config::protocol::ProtocolParamset;
15use crate::musig2::AggregateFromPublicKeys;
16use crate::utils::ScriptBufExt;
17use bitcoin::address::NetworkUnchecked;
18use bitcoin::secp256k1::PublicKey;
19use bitcoin::{Address, OutPoint, Txid, XOnlyPublicKey};
20use clementine_errors::BridgeError;
21use clementine_primitives::EVMAddress;
22use clementine_primitives::RoundIndex;
23use eyre::Context;
24
25#[derive(
27 Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Ord, PartialOrd,
28)]
29pub struct KickoffData {
30 pub operator_xonly_pk: XOnlyPublicKey,
31 pub round_idx: RoundIndex,
32 pub kickoff_idx: u32,
33}
34
35impl std::fmt::Display for KickoffData {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 write!(
38 f,
39 "Kickoff(operator_xonly_pk: {}, round_idx: {}, kickoff_idx: {})",
40 self.operator_xonly_pk, self.round_idx, self.kickoff_idx
41 )
42 }
43}
44
45#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq)]
51pub struct DepositData {
52 pub nofn_xonly_pk: Option<XOnlyPublicKey>,
54 pub deposit: DepositInfo,
55 pub actors: Actors,
56 pub security_council: SecurityCouncil,
57}
58
59impl PartialEq for DepositData {
60 fn eq(&self, other: &Self) -> bool {
61 self.security_council == other.security_council
65 && self.deposit.deposit_outpoint == other.deposit.deposit_outpoint
66 && self.get_operators() == other.get_operators()
69 && self.get_verifiers() == other.get_verifiers()
70 && self.get_watchtowers() == other.get_watchtowers()
71 && self.deposit.deposit_type == other.deposit.deposit_type
72 }
73}
74
75impl DepositData {
76 pub fn get_move_txid(
78 &mut self,
79 paramset: &'static ProtocolParamset,
80 ) -> Result<Txid, BridgeError> {
81 Ok(*create_move_to_vault_txhandler(self, paramset)?.get_txid())
82 }
83}
84
85#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
87pub struct DepositInfo {
88 pub deposit_outpoint: OutPoint,
89 pub deposit_type: DepositType,
90}
91
92#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
94pub enum DepositType {
95 BaseDeposit(BaseDepositData),
96 ReplacementDeposit(ReplacementDepositData),
97}
98
99impl DepositData {
100 pub fn get_deposit_outpoint(&self) -> OutPoint {
102 self.deposit.deposit_outpoint
103 }
104 pub fn get_nofn_xonly_pk(&mut self) -> Result<XOnlyPublicKey, BridgeError> {
106 if let Some(pk) = self.nofn_xonly_pk {
107 return Ok(pk);
108 }
109 let verifiers = self.get_verifiers();
110 let nofn_xonly_pk = bitcoin::XOnlyPublicKey::from_musig2_pks(verifiers, None)?;
111 self.nofn_xonly_pk = Some(nofn_xonly_pk);
112 Ok(nofn_xonly_pk)
113 }
114 pub fn get_num_verifiers(&self) -> usize {
116 self.actors.verifiers.len()
117 }
118 pub fn get_num_watchtowers(&self) -> usize {
120 self.get_num_verifiers() + self.actors.watchtowers.len()
121 }
122 pub fn get_verifier_index(&self, public_key: &PublicKey) -> Result<usize, eyre::Report> {
124 self.get_verifiers()
125 .iter()
126 .position(|pk| pk == public_key)
127 .ok_or_else(|| eyre::eyre!("Verifier with public key {} not found", public_key))
128 }
129 pub fn get_watchtower_index(&self, xonly_pk: &XOnlyPublicKey) -> Result<usize, eyre::Report> {
131 self.get_watchtowers()
132 .iter()
133 .position(|pk| pk == xonly_pk)
134 .ok_or_else(|| eyre::eyre!("Watchtower with xonly key {} not found", xonly_pk))
135 }
136 pub fn get_operator_index(&self, xonly_pk: XOnlyPublicKey) -> Result<usize, eyre::Report> {
138 self.get_operators()
139 .iter()
140 .position(|pk| pk == &xonly_pk)
141 .ok_or_else(|| eyre::eyre!("Operator with xonly key {} not found", xonly_pk))
142 }
143 pub fn get_verifiers(&self) -> Vec<PublicKey> {
145 let mut verifiers = self.actors.verifiers.clone();
146 verifiers.sort();
147
148 verifiers
149 }
150 pub fn get_watchtowers(&self) -> Vec<XOnlyPublicKey> {
154 let mut watchtowers = self
155 .actors
156 .verifiers
157 .iter()
158 .map(|pk| pk.x_only_public_key().0)
159 .collect::<Vec<_>>();
160 watchtowers.extend(self.actors.watchtowers.iter());
161 watchtowers.sort();
162 watchtowers
163 }
164 pub fn get_operators(&self) -> Vec<XOnlyPublicKey> {
166 let mut operators = self.actors.operators.clone();
167 operators.sort();
168 operators
169 }
170 pub fn get_num_operators(&self) -> usize {
172 self.actors.operators.len()
173 }
174 pub fn get_deposit_scripts(
177 &mut self,
178 paramset: &'static ProtocolParamset,
179 ) -> Result<Vec<Arc<dyn SpendableScript>>, BridgeError> {
180 let nofn_xonly_pk = self.get_nofn_xonly_pk()?;
181
182 match &mut self.deposit.deposit_type {
183 DepositType::BaseDeposit(original_deposit_data) => {
184 let deposit_script = Arc::new(BaseDepositScript::new(
185 nofn_xonly_pk,
186 original_deposit_data.evm_address,
187 ));
188
189 let recovery_script_pubkey = original_deposit_data
190 .recovery_taproot_address
191 .clone()
192 .assume_checked()
193 .script_pubkey();
194
195 let recovery_extracted_xonly_pk = recovery_script_pubkey
196 .try_get_taproot_pk()
197 .wrap_err("Recovery taproot address is not a valid taproot address")?;
198
199 let script_timelock = Arc::new(TimelockScript::new(
200 Some(recovery_extracted_xonly_pk),
201 paramset.user_takes_after,
202 ));
203
204 Ok(vec![deposit_script, script_timelock])
205 }
206 DepositType::ReplacementDeposit(replacement_deposit_data) => {
207 let deposit_script: Arc<dyn SpendableScript> =
208 Arc::new(ReplacementDepositScript::new(
209 nofn_xonly_pk,
210 replacement_deposit_data.old_move_txid,
211 ));
212 let security_council_script: Arc<dyn SpendableScript> = Arc::new(
213 Multisig::from_security_council(self.security_council.clone()),
214 );
215
216 Ok(vec![deposit_script, security_council_script])
217 }
218 }
219 }
220
221 pub fn are_all_verifiers_unique(&self) -> bool {
223 let set: HashSet<_> = self.actors.verifiers.iter().collect();
224 set.len() == self.actors.verifiers.len()
225 }
226
227 pub fn are_all_watchtowers_unique(&self) -> bool {
229 let set: HashSet<_> = self.get_watchtowers().into_iter().collect();
230 set.len() == self.get_num_watchtowers()
231 }
232
233 pub fn are_all_operators_unique(&self) -> bool {
235 let set: HashSet<_> = self.actors.operators.iter().collect();
236 set.len() == self.actors.operators.len()
237 }
238}
239
240#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
242pub struct Actors {
243 pub verifiers: Vec<PublicKey>,
245 pub watchtowers: Vec<XOnlyPublicKey>,
248 pub operators: Vec<XOnlyPublicKey>,
250}
251
252#[derive(Debug, Clone, PartialEq, Eq)]
254pub struct SecurityCouncil {
255 pub pks: Vec<XOnlyPublicKey>,
256 pub threshold: u32,
257}
258
259impl std::str::FromStr for SecurityCouncil {
260 type Err = eyre::Report;
261
262 fn from_str(s: &str) -> Result<Self, Self::Err> {
263 let mut parts = s.split(':');
264 let threshold_str = parts
265 .next()
266 .ok_or_else(|| eyre::eyre!("Missing threshold"))?;
267 let pks_str = parts
268 .next()
269 .ok_or_else(|| eyre::eyre!("Missing public keys"))?;
270
271 if parts.next().is_some() {
272 return Err(eyre::eyre!("Too many parts in security council string"));
273 }
274
275 let threshold = threshold_str
276 .parse::<u32>()
277 .map_err(|e| eyre::eyre!("Invalid threshold: {}", e))?;
278
279 let pks: Result<Vec<XOnlyPublicKey>, _> = pks_str
280 .split(',')
281 .map(|pk_str| {
282 let bytes = hex::decode(pk_str)
283 .map_err(|e| eyre::eyre!("Invalid hex in public key: {}", e))?;
284 XOnlyPublicKey::from_slice(&bytes)
285 .map_err(|e| eyre::eyre!("Invalid public key: {}", e))
286 })
287 .collect();
288
289 let pks = pks?;
290
291 if pks.is_empty() {
292 return Err(eyre::eyre!("No public keys provided"));
293 }
294
295 if threshold > pks.len() as u32 {
296 return Err(eyre::eyre!(
297 "Threshold cannot be greater than number of public keys"
298 ));
299 }
300
301 Ok(SecurityCouncil { pks, threshold })
302 }
303}
304
305impl serde::Serialize for SecurityCouncil {
306 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
307 where
308 S: serde::Serializer,
309 {
310 serializer.serialize_str(&self.to_string())
311 }
312}
313
314impl<'de> serde::Deserialize<'de> for SecurityCouncil {
315 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
316 where
317 D: serde::Deserializer<'de>,
318 {
319 let s = String::deserialize(deserializer)?;
320 s.parse().map_err(serde::de::Error::custom)
321 }
322}
323
324impl std::fmt::Display for SecurityCouncil {
325 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
326 write!(f, "{}:", self.threshold)?;
327 let pks_str = self
328 .pks
329 .iter()
330 .map(|pk| hex::encode(pk.serialize()))
331 .collect::<Vec<_>>()
332 .join(",");
333 write!(f, "{pks_str}")
334 }
335}
336
337#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
339pub struct BaseDepositData {
340 pub evm_address: EVMAddress,
342 pub recovery_taproot_address: bitcoin::Address<NetworkUnchecked>,
344}
345
346#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
349pub struct ReplacementDepositData {
350 pub old_move_txid: Txid,
352}
353
354#[derive(Debug, Clone, serde::Serialize, PartialEq, Eq)]
357pub struct OperatorData {
358 pub xonly_pk: XOnlyPublicKey,
359 pub reimburse_addr: Address,
360 pub collateral_funding_outpoint: OutPoint,
361}
362
363impl<'de> serde::Deserialize<'de> for OperatorData {
364 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
365 where
366 D: serde::Deserializer<'de>,
367 {
368 #[derive(serde::Deserialize)]
369 struct OperatorDataHelper {
370 xonly_pk: XOnlyPublicKey,
371 reimburse_addr: Address<NetworkUnchecked>,
372 collateral_funding_outpoint: OutPoint,
373 }
374
375 let helper = OperatorDataHelper::deserialize(deserializer)?;
376
377 Ok(OperatorData {
378 xonly_pk: helper.xonly_pk,
379 reimburse_addr: helper.reimburse_addr.assume_checked(),
380 collateral_funding_outpoint: helper.collateral_funding_outpoint,
381 })
382 }
383}