fedimint_walletv2_common/
config.rs1use std::collections::BTreeMap;
2
3use bitcoin::Network;
4use bitcoin::hashes::{Hash, sha256};
5use fedimint_core::core::ModuleKind;
6use fedimint_core::encoding::{Decodable, Encodable};
7use fedimint_core::{Amount, PeerId, plugin_types_trait_impl_config, weight_to_vbytes};
8use secp256k1::{PublicKey, SecretKey};
9use serde::{Deserialize, Serialize};
10
11use crate::{WalletCommonInit, descriptor};
12
13plugin_types_trait_impl_config!(
14 WalletCommonInit,
15 WalletConfig,
16 WalletConfigPrivate,
17 WalletConfigConsensus,
18 WalletClientConfig
19);
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)]
28pub struct WalletConfigPrivate {
29 pub bitcoin_sk: SecretKey,
30}
31
32#[derive(Clone, Debug, Serialize, Deserialize, Encodable, Decodable)]
33pub struct WalletConfigConsensus {
34 pub bitcoin_pks: BTreeMap<PeerId, PublicKey>,
36 pub send_tx_vbytes: u64,
38 pub receive_tx_vbytes: u64,
40 pub feerate_base: u64,
43 pub dust_limit: bitcoin::Amount,
45 pub fee_consensus: FeeConsensus,
47 pub network: Network,
49}
50
51impl WalletConfigConsensus {
52 pub fn new(
76 bitcoin_pks: BTreeMap<PeerId, PublicKey>,
77 fee_consensus: FeeConsensus,
78 network: Network,
79 ) -> Self {
80 let tx_overhead_weight = 4 * 4 + 1 + 1 + 4 + 4 + 4 * 4; let change_witness_weight = descriptor(&bitcoin_pks, &sha256::Hash::all_zeros())
88 .max_weight_to_satisfy()
89 .expect("Cannot satisfy the change descriptor.")
90 .to_wu();
91
92 let change_input_weight = 32 * 4 + 4 * 4 + 4 + 4 * 4 + change_witness_weight;
97
98 let change_output_weight = 8 * 4 + 4 + 34 * 4; let destination_output_weight = 8 * 4 + 4 + 34 * 4; Self {
107 bitcoin_pks,
108 send_tx_vbytes: weight_to_vbytes(
109 tx_overhead_weight
110 + change_input_weight
111 + change_output_weight
112 + destination_output_weight,
113 ),
114 receive_tx_vbytes: weight_to_vbytes(
115 tx_overhead_weight
116 + change_input_weight
117 + change_input_weight
118 + change_output_weight,
119 ),
120 feerate_base: 250,
125 dust_limit: bitcoin::Amount::from_sat(10_000),
126 fee_consensus,
127 network,
128 }
129 }
130}
131
132#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
133pub struct FeeConsensus {
134 pub base: Amount,
135 pub parts_per_million: u64,
136}
137
138impl FeeConsensus {
139 pub fn new(parts_per_million: u64) -> anyhow::Result<Self> {
150 anyhow::ensure!(
151 parts_per_million <= 10_000,
152 "Relative fee over ten thousand parts per million is excessive"
153 );
154
155 Ok(Self {
156 base: Amount::from_sats(100),
157 parts_per_million,
158 })
159 }
160
161 pub fn fee(&self, amount: Amount) -> Amount {
162 Amount::from_msats(self.fee_msats(amount.msats))
163 }
164
165 fn fee_msats(&self, msats: u64) -> u64 {
166 msats
167 .saturating_mul(self.parts_per_million)
168 .saturating_div(1_000_000)
169 .checked_add(self.base.msats)
170 .expect("The division creates sufficient headroom to add the base fee")
171 }
172}
173
174#[test]
175fn test_fee_consensus() {
176 let fee_consensus = FeeConsensus::new(10_000).expect("Relative fee is within range");
177
178 assert_eq!(
179 fee_consensus.fee(Amount::from_msats(99)),
180 Amount::from_sats(100)
181 );
182
183 assert_eq!(
184 fee_consensus.fee(Amount::from_sats(1)),
185 Amount::from_msats(10) + Amount::from_sats(100)
186 );
187
188 assert_eq!(
189 fee_consensus.fee(Amount::from_sats(1000)),
190 Amount::from_sats(10) + Amount::from_sats(100)
191 );
192
193 assert_eq!(
194 fee_consensus.fee(Amount::from_bitcoins(1)),
195 Amount::from_sats(1_000_000) + Amount::from_sats(100)
196 );
197
198 assert_eq!(
199 fee_consensus.fee(Amount::from_bitcoins(10_000)),
200 Amount::from_bitcoins(100) + Amount::from_sats(100)
201 );
202}
203
204#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
205pub struct WalletClientConfig {
206 pub bitcoin_pks: BTreeMap<PeerId, PublicKey>,
208 pub send_tx_vbytes: u64,
210 pub receive_tx_vbytes: u64,
212 pub feerate_base: u64,
215 pub dust_limit: bitcoin::Amount,
217 pub fee_consensus: FeeConsensus,
219 pub network: Network,
221}
222
223impl std::fmt::Display for WalletClientConfig {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 write!(f, "WalletClientConfig {self:?}")
226 }
227}