ree_types/
intention.rs

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/// Represents a coin input in an intention.
11#[derive(CandidType, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)]
12pub struct InputCoin {
13    /// The address of the owner of the coins
14    pub from: String,
15    pub coin: CoinBalance,
16}
17
18/// Represents a coin output in an intention.
19#[derive(CandidType, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)]
20pub struct OutputCoin {
21    /// The address of the receiver of the coins
22    pub to: String,
23    pub coin: CoinBalance,
24}
25
26/// Represents an intention to perform an action in a specific pool of an exchange.
27#[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/// Represents a set of intentions to be executed in a transaction.
41#[derive(CandidType, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
42pub struct IntentionSet {
43    /// The address of the initiator of the transaction
44    pub initiator_address: String,
45    /// The fee in satoshis for the transaction
46    pub tx_fee_in_sats: u64,
47    /// The list of intentions to be executed in the transaction
48    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}