• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

payjoin / rust-payjoin / 13914669090

18 Mar 2025 03:20AM UTC coverage: 80.649% (+0.2%) from 80.411%
13914669090

Pull #546

github

web-flow
Merge 1bebd6aae into bb47c8469
Pull Request #546: fix: corrected the pjos parameter

120 of 133 new or added lines in 11 files covered. (90.23%)

2 existing lines in 2 files now uncovered.

4918 of 6098 relevant lines covered (80.65%)

757.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.61
/payjoin/src/receive/optional_parameters.rs
1
use std::borrow::Borrow;
2
use std::fmt;
3

4
use bitcoin::FeeRate;
5
use log::warn;
6

7
use crate::output_substitution::OutputSubstitution;
8

9
#[derive(Debug, Clone)]
10
pub(crate) struct Params {
11
    // version
12
    pub v: usize,
13
    // disableoutputsubstitution
14
    pub output_substitution: OutputSubstitution,
15
    // maxadditionalfeecontribution, additionalfeeoutputindex
16
    pub additional_fee_contribution: Option<(bitcoin::Amount, usize)>,
17
    // minfeerate
18
    pub min_fee_rate: FeeRate,
19
    #[cfg(feature = "_multiparty")]
20
    /// Opt in to optimistic psbt merge
21
    pub optimistic_merge: bool,
22
}
23

24
impl Default for Params {
25
    fn default() -> Self {
29✔
26
        Params {
29✔
27
            v: 1,
29✔
28
            output_substitution: OutputSubstitution::Enabled,
29✔
29
            additional_fee_contribution: None,
29✔
30
            min_fee_rate: FeeRate::BROADCAST_MIN,
29✔
31
            #[cfg(feature = "_multiparty")]
29✔
32
            optimistic_merge: false,
29✔
33
        }
29✔
34
    }
29✔
35
}
36

37
impl Params {
38
    pub fn from_query_pairs<K, V, I>(
25✔
39
        pairs: I,
25✔
40
        supported_versions: &'static [usize],
25✔
41
    ) -> Result<Self, Error>
25✔
42
    where
25✔
43
        I: Iterator<Item = (K, V)>,
25✔
44
        K: Borrow<str> + Into<String>,
25✔
45
        V: Borrow<str> + Into<String>,
25✔
46
    {
25✔
47
        let mut params = Params::default();
25✔
48

25✔
49
        let mut additional_fee_output_index = None;
25✔
50
        let mut max_additional_fee_contribution = None;
25✔
51

52
        for (key, v) in pairs {
102✔
53
            match (key.borrow(), v.borrow()) {
77✔
54
                ("v", version) =>
77✔
55
                    params.v = match version.parse::<usize>() {
20✔
56
                        Ok(version) if supported_versions.contains(&version) => version,
20✔
57
                        _ => return Err(Error::UnknownVersion { supported_versions }),
×
58
                    },
59
                ("additionalfeeoutputindex", index) =>
57✔
60
                    additional_fee_output_index = match index.parse::<usize>() {
16✔
61
                        Ok(index) => Some(index),
16✔
62
                        Err(_error) => {
×
63
                            warn!(
×
64
                                "bad `additionalfeeoutputindex` query value '{}': {}",
×
65
                                index, _error
66
                            );
67
                            None
×
68
                        }
69
                    },
70
                ("maxadditionalfeecontribution", fee) =>
41✔
71
                    max_additional_fee_contribution =
16✔
72
                        match bitcoin::Amount::from_str_in(fee, bitcoin::Denomination::Satoshi) {
16✔
73
                            Ok(contribution) => Some(contribution),
16✔
74
                            Err(_error) => {
×
75
                                warn!(
×
76
                                    "bad `maxadditionalfeecontribution` query value '{}': {}",
×
77
                                    fee, _error
78
                                );
79
                                None
×
80
                            }
81
                        },
82
                ("minfeerate", fee_rate) =>
25✔
83
                    params.min_fee_rate = match fee_rate.parse::<f32>() {
13✔
84
                        Ok(fee_rate_sat_per_vb) => {
13✔
85
                            // TODO Parse with serde when rust-bitcoin supports it
13✔
86
                            let fee_rate_sat_per_kwu = fee_rate_sat_per_vb * 250.0_f32;
13✔
87
                            // since it's a minimum, we want to round up
13✔
88
                            FeeRate::from_sat_per_kwu(fee_rate_sat_per_kwu.ceil() as u64)
13✔
89
                        }
90
                        Err(_) => return Err(Error::FeeRate),
×
91
                    },
92
                ("disableoutputsubstitution", v) =>
12✔
93
                    params.output_substitution = if v == "true" {
4✔
94
                        OutputSubstitution::Disabled
4✔
95
                    } else {
NEW
96
                        OutputSubstitution::Enabled
×
97
                    },
98
                #[cfg(feature = "_multiparty")]
99
                ("optimisticmerge", v) => params.optimistic_merge = v == "true",
8✔
100
                _ => (),
×
101
            }
102
        }
103

104
        match (max_additional_fee_contribution, additional_fee_output_index) {
25✔
105
            (Some(amount), Some(index)) =>
16✔
106
                params.additional_fee_contribution = Some((amount, index)),
16✔
107
            (Some(_), None) | (None, Some(_)) => {
108
                warn!("only one additional-fee parameter specified: {:?}", params);
×
109
            }
110
            _ => (),
9✔
111
        }
112

113
        log::debug!("parsed optional parameters: {:?}", params);
25✔
114
        Ok(params)
25✔
115
    }
25✔
116
}
117

118
#[derive(Debug)]
119
pub(crate) enum Error {
120
    UnknownVersion { supported_versions: &'static [usize] },
121
    FeeRate,
122
}
123

124
impl fmt::Display for Error {
125
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
×
126
        match self {
×
127
            Error::UnknownVersion { .. } => write!(f, "unknown version"),
×
128
            Error::FeeRate => write!(f, "could not parse feerate"),
×
129
        }
130
    }
×
131
}
132

133
impl std::error::Error for Error {
134
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
×
135
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc