fedimint_wallet_common/
config.rs

1use std::collections::BTreeMap;
2
3use bitcoin::Network;
4use bitcoin::secp256k1::SecretKey;
5use fedimint_core::core::ModuleKind;
6use fedimint_core::encoding::btc::NetworkLegacyEncodingWrapper;
7use fedimint_core::encoding::{Decodable, Encodable};
8use fedimint_core::envs::BitcoinRpcConfig;
9use fedimint_core::module::serde_json;
10use fedimint_core::{Feerate, PeerId, plugin_types_trait_impl_config};
11use miniscript::descriptor::{Wpkh, Wsh};
12use serde::{Deserialize, Serialize};
13
14use crate::keys::CompressedPublicKey;
15use crate::{PegInDescriptor, WalletCommonInit};
16
17/// Helps against dust attacks where an attacker deposits UTXOs that, with
18/// higher fee levels, cannot be spent profitably.
19const DEFAULT_DEPOSIT_FEE_SATS: u64 = 1000;
20
21#[derive(Clone, Debug, Serialize, Deserialize)]
22pub struct WalletConfig {
23    pub private: WalletConfigPrivate,
24    pub consensus: WalletConfigConsensus,
25}
26
27#[derive(Clone, Debug, Serialize, Deserialize, Decodable, Encodable)]
28pub struct WalletConfigLocal {
29    /// Configures which bitcoin RPC to use
30    pub bitcoin_rpc: BitcoinRpcConfig,
31}
32
33#[derive(Clone, Debug, Serialize, Deserialize)]
34pub struct WalletConfigPrivate {
35    /// Secret key for signing bitcoin multisig transactions
36    pub peg_in_key: SecretKey,
37}
38
39#[derive(Clone, Debug, Serialize, Deserialize, Encodable, Decodable)]
40pub struct WalletConfigConsensus {
41    /// Bitcoin network (e.g. testnet, bitcoin)
42    pub network: NetworkLegacyEncodingWrapper,
43    /// The federations public peg-in-descriptor
44    pub peg_in_descriptor: PegInDescriptor,
45    /// The public keys for the bitcoin multisig
46    pub peer_peg_in_keys: BTreeMap<PeerId, CompressedPublicKey>,
47    /// How many bitcoin blocks to wait before considering a transaction
48    /// confirmed
49    pub finality_delay: u32,
50    /// If we cannot determine the feerate from our bitcoin node, default to
51    /// this
52    pub default_fee: Feerate,
53    /// Fees for bitcoin transactions
54    pub fee_consensus: FeeConsensus,
55    /// Points to a Bitcoin API that the client can use to interact with the
56    /// Bitcoin blockchain (mostly for deposits). *Eventually the backend should
57    /// become configurable locally and this should merely be a suggested
58    /// default by the federation.*
59    ///
60    /// **This is only used by the client, the RPC used by the server is defined
61    /// in [`WalletConfigLocal`].**
62    pub client_default_bitcoin_rpc: BitcoinRpcConfig,
63}
64
65#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
66pub struct WalletClientConfig {
67    /// The federations public peg-in-descriptor
68    pub peg_in_descriptor: PegInDescriptor,
69    /// The bitcoin network the client will use
70    pub network: NetworkLegacyEncodingWrapper,
71    /// Confirmations required for a peg in to be accepted by federation
72    pub finality_delay: u32,
73    pub fee_consensus: FeeConsensus,
74    /// Points to a Bitcoin API that the client can use to interact with the
75    /// Bitcoin blockchain (mostly for deposits). *Eventually the backend should
76    /// become configurable locally and this should merely be a suggested
77    /// default by the federation.*
78    pub default_bitcoin_rpc: BitcoinRpcConfig,
79}
80
81impl std::fmt::Display for WalletClientConfig {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        write!(
84            f,
85            "WalletClientConfig {}",
86            serde_json::to_string(self).map_err(|_e| std::fmt::Error)?
87        )
88    }
89}
90
91#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
92pub struct FeeConsensus {
93    pub peg_in_abs: fedimint_core::Amount,
94    pub peg_out_abs: fedimint_core::Amount,
95}
96
97impl Default for FeeConsensus {
98    fn default() -> Self {
99        Self {
100            peg_in_abs: fedimint_core::Amount::from_sats(DEFAULT_DEPOSIT_FEE_SATS),
101            peg_out_abs: fedimint_core::Amount::ZERO,
102        }
103    }
104}
105
106impl WalletConfig {
107    #[allow(clippy::too_many_arguments)]
108    pub fn new(
109        pubkeys: BTreeMap<PeerId, CompressedPublicKey>,
110        sk: SecretKey,
111        threshold: usize,
112        network: Network,
113        finality_delay: u32,
114        client_default_bitcoin_rpc: BitcoinRpcConfig,
115        fee_consensus: FeeConsensus,
116    ) -> Self {
117        let peg_in_descriptor = if pubkeys.len() == 1 {
118            PegInDescriptor::Wpkh(
119                Wpkh::new(
120                    *pubkeys
121                        .values()
122                        .next()
123                        .expect("there is exactly one pub key"),
124                )
125                .expect("Our key type is always compressed"),
126            )
127        } else {
128            PegInDescriptor::Wsh(
129                Wsh::new_sortedmulti(threshold, pubkeys.values().copied().collect()).unwrap(),
130            )
131        };
132
133        Self {
134            private: WalletConfigPrivate { peg_in_key: sk },
135            consensus: WalletConfigConsensus {
136                network: NetworkLegacyEncodingWrapper(network),
137                peg_in_descriptor,
138                peer_peg_in_keys: pubkeys,
139                finality_delay,
140                default_fee: Feerate { sats_per_kvb: 1000 },
141                fee_consensus,
142                client_default_bitcoin_rpc,
143            },
144        }
145    }
146}
147
148plugin_types_trait_impl_config!(
149    WalletCommonInit,
150    WalletConfig,
151    WalletConfigPrivate,
152    WalletConfigConsensus,
153    WalletClientConfig
154);