1use crate::{
2 CoinBalance, CoinId, Utxo,
3 bitcoin::{OutPoint, Txid},
4};
5use alloc::collections::BTreeSet;
6use alloc::str::FromStr;
7use candid::CandidType;
8use serde::{Deserialize, Serialize};
9
10#[derive(CandidType, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)]
12pub struct InputCoin {
13 pub from: String,
15 pub coin: CoinBalance,
16}
17
18#[derive(CandidType, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)]
20pub struct OutputCoin {
21 pub to: String,
23 pub coin: CoinBalance,
24}
25
26#[derive(CandidType, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
28pub struct Intention {
29 pub exchange_id: String,
30 pub action: String,
31 pub action_params: String,
32 pub pool_address: String,
33 pub nonce: u64,
34 pub pool_utxo_spent: Vec<String>,
35 pub pool_utxo_received: Vec<Utxo>,
36 pub input_coins: Vec<InputCoin>,
37 pub output_coins: Vec<OutputCoin>,
38}
39
40#[derive(CandidType, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
42pub struct IntentionSet {
43 pub initiator_address: String,
45 pub tx_fee_in_sats: u64,
47 pub intentions: Vec<Intention>,
49}
50
51impl Intention {
52 pub fn pool_outpoints(&self) -> Result<Vec<OutPoint>, Box<dyn std::error::Error>> {
53 let outpoints: Vec<_> = self
54 .pool_utxo_spent
55 .iter()
56 .flat_map(|outpoint| {
57 let parts = outpoint.split(':').collect::<Vec<_>>();
58 let txid = parts.get(0).map(|s| Txid::from_str(s).ok()).flatten()?;
59 let vout = parts.get(1).map(|s| s.parse::<u32>().ok()).flatten()?;
60 Some(OutPoint { txid, vout })
61 })
62 .collect();
63 if outpoints.len() != self.pool_utxo_spent.len() {
64 return Err("Invalid outpoint format".into());
65 }
66 return Ok(outpoints);
67 }
68
69 pub fn input_coin_ids(&self) -> Vec<CoinId> {
70 self.input_coins
71 .iter()
72 .map(|input_coin| input_coin.coin.id.clone())
73 .collect()
74 }
75
76 pub fn output_coin_ids(&self) -> Vec<CoinId> {
77 self.output_coins
78 .iter()
79 .map(|output_coin| output_coin.coin.id.clone())
80 .collect()
81 }
82
83 pub fn all_coin_ids(&self) -> Vec<CoinId> {
84 let mut coin_ids: BTreeSet<CoinId> = BTreeSet::new();
85 for coin_id in self.input_coin_ids().into_iter() {
86 coin_ids.insert(coin_id);
87 }
88 for coin_id in self.output_coin_ids().into_iter() {
89 coin_ids.insert(coin_id);
90 }
91 coin_ids.into_iter().collect()
92 }
93}
94
95impl IntentionSet {
96 pub fn all_input_coins(&self) -> Vec<InputCoin> {
97 let mut input_coins = BTreeSet::new();
98 for intention in self.intentions.iter() {
99 for input_coin in intention.input_coins.iter() {
100 input_coins.insert(input_coin.clone());
101 }
102 }
103 input_coins.into_iter().collect()
104 }
105
106 pub fn all_output_coins(&self) -> Vec<OutputCoin> {
107 let mut output_coins = BTreeSet::new();
108 for intention in self.intentions.iter() {
109 for output_coin in intention.output_coins.iter() {
110 output_coins.insert(output_coin.clone());
111 }
112 }
113 output_coins.into_iter().collect()
114 }
115
116 pub fn all_coin_ids(&self) -> Vec<CoinId> {
117 let mut coin_ids: BTreeSet<CoinId> = BTreeSet::new();
118 for intention in self.intentions.iter() {
119 for coin_id in intention.all_coin_ids().into_iter() {
120 coin_ids.insert(coin_id);
121 }
122 }
123 coin_ids.into_iter().collect()
124 }
125}