fedimint_mintv2_common/
config.rs1use std::collections::BTreeMap;
2
3use fedimint_core::core::ModuleKind;
4use fedimint_core::encoding::{Decodable, Encodable};
5use fedimint_core::module::{AmountUnit, serde_json};
6use fedimint_core::{Amount, PeerId, plugin_types_trait_impl_config};
7use serde::{Deserialize, Serialize};
8use tbs::{AggregatePublicKey, PublicKeyShare};
9
10use crate::{Denomination, MintCommonInit};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct MintGenParams {
14 pub fee_consensus: FeeConsensus,
15}
16
17pub fn consensus_denominations() -> impl DoubleEndedIterator<Item = Denomination> {
18 (0..42).map(Denomination)
19}
20
21pub fn client_denominations() -> impl DoubleEndedIterator<Item = Denomination> {
22 (9..42).map(Denomination)
23}
24
25#[derive(Clone, Debug, Serialize, Deserialize)]
26pub struct MintConfig {
27 pub private: MintConfigPrivate,
28 pub consensus: MintConfigConsensus,
29}
30
31#[derive(Clone, Debug, Serialize, Deserialize, Encodable, Decodable)]
32pub struct MintConfigConsensus {
33 pub tbs_agg_pks: BTreeMap<Denomination, AggregatePublicKey>,
34 pub tbs_pks: BTreeMap<Denomination, BTreeMap<PeerId, PublicKeyShare>>,
35 pub fee_consensus: FeeConsensus,
36 pub amount_unit: AmountUnit,
37}
38
39#[derive(Clone, Debug, Serialize, Deserialize)]
40pub struct MintConfigPrivate {
41 pub tbs_sks: BTreeMap<Denomination, tbs::SecretKeyShare>,
42}
43
44#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable, Hash)]
45pub struct MintClientConfig {
46 pub tbs_agg_pks: BTreeMap<Denomination, AggregatePublicKey>,
47 pub tbs_pks: BTreeMap<Denomination, BTreeMap<PeerId, PublicKeyShare>>,
48 pub fee_consensus: FeeConsensus,
49 pub amount_unit: AmountUnit,
50}
51
52impl std::fmt::Display for MintClientConfig {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 write!(
55 f,
56 "MintClientConfig {}",
57 serde_json::to_string(self).map_err(|_e| std::fmt::Error)?
58 )
59 }
60}
61
62plugin_types_trait_impl_config!(
64 MintCommonInit,
65 MintConfig,
66 MintConfigPrivate,
67 MintConfigConsensus,
68 MintClientConfig
69);
70
71#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
72pub struct FeeConsensus {
73 base: Amount,
74 parts_per_million: u64,
75}
76
77impl FeeConsensus {
78 pub fn new(parts_per_million: u64) -> anyhow::Result<Self> {
89 anyhow::ensure!(
90 parts_per_million <= 1_000,
91 "Relative fee over one thousand parts per million is excessive"
92 );
93
94 Ok(Self {
95 base: Amount::from_msats(100),
96 parts_per_million,
97 })
98 }
99
100 pub fn zero() -> Self {
102 Self {
103 base: Amount::ZERO,
104 parts_per_million: 0,
105 }
106 }
107
108 pub fn base_fee(&self) -> Amount {
109 self.base
110 }
111
112 pub fn fee(&self, amount: Amount) -> Amount {
113 Amount::from_msats(self.fee_msats(amount.msats))
114 }
115
116 fn fee_msats(&self, msats: u64) -> u64 {
117 msats
118 .saturating_mul(self.parts_per_million)
119 .saturating_div(1_000_000)
120 .checked_add(self.base.msats)
121 .expect("The division creates sufficient headroom to add the base fee")
122 }
123}
124
125#[test]
126fn test_fee_consensus() {
127 let fee_consensus = FeeConsensus::new(1_000).expect("Relative fee is within range");
128
129 assert_eq!(
130 fee_consensus.fee(Amount::from_msats(999)),
131 Amount::from_msats(100)
132 );
133
134 assert_eq!(
135 fee_consensus.fee(Amount::from_sats(1)),
136 Amount::from_msats(100) + Amount::from_msats(1)
137 );
138
139 assert_eq!(
140 fee_consensus.fee(Amount::from_sats(1000)),
141 Amount::from_sats(1) + Amount::from_msats(100)
142 );
143
144 assert_eq!(
145 fee_consensus.fee(Amount::from_bitcoins(1)),
146 Amount::from_sats(100_000) + Amount::from_msats(100)
147 );
148
149 assert_eq!(
150 fee_consensus.fee(Amount::from_bitcoins(100_000)),
151 Amount::from_bitcoins(100) + Amount::from_msats(100)
152 );
153}