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::util::SafeUrl;
11use fedimint_core::{Feerate, PeerId, plugin_types_trait_impl_config};
12use miniscript::descriptor::{Wpkh, Wsh};
13use serde::{Deserialize, Serialize};
14
15use crate::envs::FM_PORT_ESPLORA_ENV;
16use crate::keys::CompressedPublicKey;
17use crate::{PegInDescriptor, WalletCommonInit};
18
19const DEFAULT_DEPOSIT_FEE_SATS: u64 = 1000;
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct WalletGenParams {
25 pub local: WalletGenParamsLocal,
26 pub consensus: WalletGenParamsConsensus,
27}
28
29impl WalletGenParams {
30 pub fn regtest(bitcoin_rpc: BitcoinRpcConfig) -> WalletGenParams {
31 WalletGenParams {
32 local: WalletGenParamsLocal { bitcoin_rpc },
33 consensus: WalletGenParamsConsensus {
34 network: Network::Regtest,
35 finality_delay: 10,
36 client_default_bitcoin_rpc: BitcoinRpcConfig {
37 kind: "esplora".to_string(),
38 url: SafeUrl::parse(&format!(
39 "http://127.0.0.1:{}/",
40 std::env::var(FM_PORT_ESPLORA_ENV).unwrap_or(String::from("50002"))
41 ))
42 .expect("Failed to parse default esplora server"),
43 },
44 fee_consensus: FeeConsensus::default(),
45 },
46 }
47 }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct WalletGenParamsLocal {
52 pub bitcoin_rpc: BitcoinRpcConfig,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct WalletGenParamsConsensus {
57 pub network: Network,
58 pub finality_delay: u32,
59 pub client_default_bitcoin_rpc: BitcoinRpcConfig,
61 pub fee_consensus: FeeConsensus,
66}
67
68#[derive(Clone, Debug, Serialize, Deserialize)]
69pub struct WalletConfig {
70 pub private: WalletConfigPrivate,
71 pub consensus: WalletConfigConsensus,
72}
73
74#[derive(Clone, Debug, Serialize, Deserialize, Decodable, Encodable)]
75pub struct WalletConfigLocal {
76 pub bitcoin_rpc: BitcoinRpcConfig,
78}
79
80#[derive(Clone, Debug, Serialize, Deserialize)]
81pub struct WalletConfigPrivate {
82 pub peg_in_key: SecretKey,
84}
85
86#[derive(Clone, Debug, Serialize, Deserialize, Encodable, Decodable)]
87pub struct WalletConfigConsensus {
88 pub network: NetworkLegacyEncodingWrapper,
90 pub peg_in_descriptor: PegInDescriptor,
92 pub peer_peg_in_keys: BTreeMap<PeerId, CompressedPublicKey>,
94 pub finality_delay: u32,
97 pub default_fee: Feerate,
100 pub fee_consensus: FeeConsensus,
102 pub client_default_bitcoin_rpc: BitcoinRpcConfig,
110}
111
112#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
113pub struct WalletClientConfig {
114 pub peg_in_descriptor: PegInDescriptor,
116 pub network: NetworkLegacyEncodingWrapper,
118 pub finality_delay: u32,
120 pub fee_consensus: FeeConsensus,
121 pub default_bitcoin_rpc: BitcoinRpcConfig,
126}
127
128impl std::fmt::Display for WalletClientConfig {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 write!(
131 f,
132 "WalletClientConfig {}",
133 serde_json::to_string(self).map_err(|_e| std::fmt::Error)?
134 )
135 }
136}
137
138#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
139pub struct FeeConsensus {
140 pub peg_in_abs: fedimint_core::Amount,
141 pub peg_out_abs: fedimint_core::Amount,
142}
143
144impl Default for FeeConsensus {
145 fn default() -> Self {
146 Self {
147 peg_in_abs: fedimint_core::Amount::from_sats(DEFAULT_DEPOSIT_FEE_SATS),
148 peg_out_abs: fedimint_core::Amount::ZERO,
149 }
150 }
151}
152
153impl WalletConfig {
154 #[allow(clippy::too_many_arguments)]
155 pub fn new(
156 pubkeys: BTreeMap<PeerId, CompressedPublicKey>,
157 sk: SecretKey,
158 threshold: usize,
159 network: Network,
160 finality_delay: u32,
161 client_default_bitcoin_rpc: BitcoinRpcConfig,
162 fee_consensus: FeeConsensus,
163 ) -> Self {
164 let peg_in_descriptor = if pubkeys.len() == 1 {
165 PegInDescriptor::Wpkh(
166 Wpkh::new(
167 *pubkeys
168 .values()
169 .next()
170 .expect("there is exactly one pub key"),
171 )
172 .expect("Our key type is always compressed"),
173 )
174 } else {
175 PegInDescriptor::Wsh(
176 Wsh::new_sortedmulti(threshold, pubkeys.values().copied().collect()).unwrap(),
177 )
178 };
179
180 Self {
181 private: WalletConfigPrivate { peg_in_key: sk },
182 consensus: WalletConfigConsensus {
183 network: NetworkLegacyEncodingWrapper(network),
184 peg_in_descriptor,
185 peer_peg_in_keys: pubkeys,
186 finality_delay,
187 default_fee: Feerate { sats_per_kvb: 1000 },
188 fee_consensus,
189 client_default_bitcoin_rpc,
190 },
191 }
192 }
193}
194
195plugin_types_trait_impl_config!(
196 WalletCommonInit,
197 WalletGenParams,
198 WalletGenParamsLocal,
199 WalletGenParamsConsensus,
200 WalletConfig,
201 WalletConfigPrivate,
202 WalletConfigConsensus,
203 WalletClientConfig
204);