breez_sdk_liquid/recover/
model.rs

1use std::collections::HashMap;
2use std::str::FromStr;
3
4use lwk_wollet::elements_miniscript::slip77::MasterBlindingKey;
5use lwk_wollet::WalletTx;
6use sdk_common::utils::Arc;
7
8use crate::chain::liquid::LiquidChainService;
9use crate::prelude::*;
10use crate::swapper::Swapper;
11
12/// A map of all our known LWK onchain txs, indexed by tx ID. Essentially our own cache of the LWK txs.
13#[derive(Clone)]
14pub(crate) struct TxMap {
15    pub(crate) outgoing_tx_map: HashMap<elements::Txid, WalletTx>,
16    pub(crate) incoming_tx_map: HashMap<elements::Txid, WalletTx>,
17}
18impl TxMap {
19    pub(crate) fn from_raw_tx_map(raw_tx_map: HashMap<elements::Txid, WalletTx>) -> Self {
20        let (outgoing_tx_map, incoming_tx_map): (
21            HashMap<elements::Txid, WalletTx>,
22            HashMap<elements::Txid, WalletTx>,
23        ) = raw_tx_map
24            .into_iter()
25            .partition(|(_, tx)| tx.balance.values().sum::<i64>() < 0);
26
27        Self {
28            outgoing_tx_map,
29            incoming_tx_map,
30        }
31    }
32}
33
34/// Swap list containing all swap data indexed by swap ID
35#[derive(Default)]
36pub(crate) struct SwapsList {
37    // Single map for all swap types indexed by swap ID
38    pub(crate) swaps_by_id: HashMap<String, Swap>,
39}
40
41impl TryFrom<Vec<Swap>> for SwapsList {
42    type Error = anyhow::Error;
43
44    fn try_from(swaps: Vec<Swap>) -> std::result::Result<Self, Self::Error> {
45        let mut swaps_list = Self::default();
46
47        for swap in swaps.into_iter() {
48            let swap_id = swap.id();
49            swaps_list.swaps_by_id.insert(swap_id, swap);
50        }
51
52        Ok(swaps_list)
53    }
54}
55
56impl SwapsList {
57    pub(crate) fn get_swap_lbtc_scripts(&self) -> Vec<LBtcScript> {
58        let mut swap_scripts = Vec::new();
59
60        for swap in self.swaps_by_id.values() {
61            match swap {
62                Swap::Send(send_swap) => {
63                    if let Ok(script) = send_swap.get_swap_script() {
64                        if let Some(funding_addr) = script.funding_addrs {
65                            swap_scripts.push(funding_addr.script_pubkey());
66                        }
67                    }
68                }
69                Swap::Receive(receive_swap) => {
70                    // Add claim script
71                    if let Ok(script) = receive_swap.get_swap_script() {
72                        if let Some(funding_addr) = script.funding_addrs {
73                            swap_scripts.push(funding_addr.script_pubkey());
74                        }
75                    }
76
77                    // Add MRH script if available
78                    if let Ok(mrh_address) = elements::Address::from_str(&receive_swap.mrh_address)
79                    {
80                        swap_scripts.push(mrh_address.script_pubkey());
81                    }
82                }
83                Swap::Chain(chain_swap) => {
84                    match chain_swap.direction {
85                        Direction::Outgoing => {
86                            // For outgoing chain swaps, add lockup script
87                            _ = chain_swap
88                                .get_lockup_swap_script()
89                                .and_then(|lockup_script| {
90                                    Ok(lockup_script.as_liquid_script()?.funding_addrs.map(
91                                        |funding_addr| {
92                                            swap_scripts.push(funding_addr.script_pubkey())
93                                        },
94                                    ))
95                                })
96                        }
97                        Direction::Incoming => {
98                            // For incoming chain swaps, add claim script
99                            _ = chain_swap.get_claim_swap_script().and_then(|claim_script| {
100                                Ok(claim_script.as_liquid_script()?.funding_addrs.map(
101                                    |funding_addr| swap_scripts.push(funding_addr.script_pubkey()),
102                                ))
103                            })
104                        }
105                    }
106                }
107            }
108        }
109
110        swap_scripts
111    }
112
113    pub(crate) fn get_swap_btc_scripts(&self) -> Vec<BtcScript> {
114        let mut swap_scripts = Vec::new();
115
116        for swap in self.swaps_by_id.values() {
117            if let Swap::Chain(chain_swap) = swap {
118                match chain_swap.direction {
119                    Direction::Outgoing => {
120                        // For outgoing chain swaps, add claim script (BTC)
121                        _ = chain_swap.get_claim_swap_script().and_then(|claim_script| {
122                            Ok(claim_script.as_bitcoin_script()?.funding_addrs.map(
123                                |funding_addr| swap_scripts.push(funding_addr.script_pubkey()),
124                            ))
125                        })
126                    }
127                    Direction::Incoming => {
128                        // For incoming chain swaps, add lockup script (BTC)
129                        _ = chain_swap
130                            .get_lockup_swap_script()
131                            .and_then(|lockup_script| {
132                                Ok(lockup_script.as_bitcoin_script()?.funding_addrs.map(
133                                    |funding_addr| swap_scripts.push(funding_addr.script_pubkey()),
134                                ))
135                            })
136                    }
137                }
138            }
139        }
140
141        swap_scripts
142    }
143}
144
145pub(crate) struct ReceiveOrSendSwapRecoveryContext {
146    pub(crate) lbtc_script_to_history_map: HashMap<LBtcScript, Vec<LBtcHistory>>,
147    pub(crate) liquid_chain_service: Arc<dyn LiquidChainService>,
148    pub(crate) swapper: Arc<dyn Swapper>,
149    pub(crate) tx_map: TxMap,
150    pub(crate) liquid_tip_height: u32,
151}
152
153pub(crate) struct ChainSwapRecoveryContext {
154    pub(crate) lbtc_script_to_history_map: HashMap<LBtcScript, Vec<LBtcHistory>>,
155    pub(crate) btc_script_to_history_map: HashMap<BtcScript, Vec<BtcHistory>>,
156    pub(crate) btc_script_to_txs_map: HashMap<BtcScript, Vec<bitcoin::Transaction>>,
157    pub(crate) btc_script_to_balance_map: HashMap<BtcScript, BtcScriptBalance>,
158    pub(crate) tx_map: TxMap,
159    pub(crate) master_blinding_key: MasterBlindingKey,
160    pub(crate) liquid_tip_height: u32,
161    pub(crate) bitcoin_tip_height: u32,
162}