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