breez_sdk_liquid/payjoin/
network_fee.rs

1pub const MIN_FEE_RATE: f64 = 0.1;
2
3pub const WEIGHT_FIXED: usize = 222;
4pub const WEIGHT_VIN_SINGLE_SIG_NATIVE: usize = 275;
5pub const WEIGHT_VIN_SINGLE_SIG_NESTED: usize = 367;
6pub const WEIGHT_VOUT_NESTED: usize = 270;
7
8pub fn weight_to_vsize(weight: usize) -> usize {
9    (weight + 3) / 4
10}
11
12pub fn vsize_to_fee(vsize: usize, fee_rate: f64) -> u64 {
13    (vsize as f64 * fee_rate).ceil() as u64
14}
15
16pub fn weight_to_fee(weight: usize, fee_rate: f64) -> u64 {
17    vsize_to_fee(weight_to_vsize(weight), fee_rate)
18}
19
20#[derive(Copy, Clone, Default)]
21pub struct TxFee {
22    pub server_inputs: usize,
23    pub user_inputs: usize,
24    pub outputs: usize,
25}
26
27impl TxFee {
28    pub fn tx_weight(&self) -> usize {
29        let TxFee {
30            server_inputs,
31            user_inputs,
32            outputs,
33        } = self;
34        WEIGHT_FIXED
35            + WEIGHT_VIN_SINGLE_SIG_NATIVE * server_inputs
36            + WEIGHT_VIN_SINGLE_SIG_NESTED * user_inputs
37            + WEIGHT_VOUT_NESTED * outputs
38    }
39
40    pub fn fee(&self) -> u64 {
41        weight_to_fee(self.tx_weight(), MIN_FEE_RATE)
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    #[cfg(all(target_family = "wasm", target_os = "unknown"))]
50    wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
51
52    #[sdk_macros::test_all]
53    fn test_weight_to_vsize() {
54        assert_eq!(weight_to_vsize(4), 1);
55        assert_eq!(weight_to_vsize(5), 2);
56        assert_eq!(weight_to_vsize(7), 2);
57        assert_eq!(weight_to_vsize(8), 2);
58        assert_eq!(weight_to_vsize(9), 3);
59        assert_eq!(weight_to_vsize(1000), 250);
60    }
61
62    #[sdk_macros::test_all]
63    fn test_vsize_to_fee() {
64        assert_eq!(vsize_to_fee(100, 1.0), 100);
65        assert_eq!(vsize_to_fee(100, 0.5), 50);
66        assert_eq!(vsize_to_fee(100, 0.1), 10);
67        assert_eq!(vsize_to_fee(100, 0.11), 11);
68        assert_eq!(vsize_to_fee(100, 0.15), 15);
69        assert_eq!(vsize_to_fee(100, 0.151), 16);
70    }
71
72    #[sdk_macros::test_all]
73    fn test_weight_to_fee() {
74        assert_eq!(weight_to_fee(400, 1.0), 100);
75        assert_eq!(weight_to_fee(400, 0.5), 50);
76        assert_eq!(weight_to_fee(401, 1.0), 101);
77        assert_eq!(weight_to_fee(399, 1.0), 100);
78    }
79
80    #[sdk_macros::test_all]
81    fn test_tx_fee_calculation() {
82        let fee = TxFee {
83            server_inputs: 1,
84            user_inputs: 1,
85            outputs: 2,
86        };
87
88        assert_eq!(
89            fee.tx_weight(),
90            WEIGHT_FIXED
91                + WEIGHT_VIN_SINGLE_SIG_NATIVE
92                + WEIGHT_VIN_SINGLE_SIG_NESTED
93                + 2 * WEIGHT_VOUT_NESTED
94        );
95
96        let empty_fee = TxFee::default();
97        assert_eq!(empty_fee.tx_weight(), WEIGHT_FIXED);
98        assert_eq!(empty_fee.fee(), weight_to_fee(WEIGHT_FIXED, MIN_FEE_RATE));
99
100        let complex_fee = TxFee {
101            server_inputs: 3,
102            user_inputs: 2,
103            outputs: 4,
104        };
105        assert_eq!(
106            complex_fee.tx_weight(),
107            WEIGHT_FIXED
108                + 3 * WEIGHT_VIN_SINGLE_SIG_NATIVE
109                + 2 * WEIGHT_VIN_SINGLE_SIG_NESTED
110                + 4 * WEIGHT_VOUT_NESTED
111        );
112    }
113}