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

payjoin / rust-payjoin / 15323824025

29 May 2025 12:27PM UTC coverage: 84.292% (-0.3%) from 84.553%
15323824025

Pull #703

github

web-flow
Merge 5537853fe into 16f0c20fa
Pull Request #703: Refactor config to use derive macros over builder

116 of 130 new or added lines in 3 files covered. (89.23%)

1 existing line in 1 file now uncovered.

6402 of 7595 relevant lines covered (84.29%)

609.76 hits per line

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

75.0
/payjoin-cli/src/cli/mod.rs
1
use std::path::PathBuf;
2

3
use clap::{value_parser, Parser, Subcommand};
4
use payjoin::bitcoin::amount::ParseAmountError;
5
use payjoin::bitcoin::{Amount, FeeRate};
6
use serde::Deserialize;
7
use url::Url;
8

9
#[derive(Debug, Clone, Deserialize, Parser)]
24✔
10
pub struct Flags {
11
    #[arg(long = "bip77", help = "Use BIP77 (v2) protocol (default)", action = clap::ArgAction::SetTrue)]
12
    pub bip77: Option<bool>,
8✔
13
    #[arg(long = "bip78", help = "Use BIP78 (v1) protocol", action = clap::ArgAction::SetTrue)]
14
    pub bip78: Option<bool>,
8✔
15
}
16

17
#[derive(Debug, Parser)]
44✔
18
#[command(
19
    version = env!("CARGO_PKG_VERSION"),
20
    about = "Payjoin - bitcoin scaling, savings, and privacy by default",
21
    long_about = None,
22
    subcommand_required = true
23
)]
24
pub struct Cli {
25
    #[command(flatten)]
26
    pub flags: Flags,
27

28
    #[command(subcommand)]
29
    pub command: Commands,
30

31
    #[arg(long, short = 'd', help = "Sets a custom database path")]
32
    pub db_path: Option<PathBuf>,
8✔
33

34
    #[arg(long = "max-fee-rate", short = 'f', help = "The maximum fee rate to accept in sat/vB")]
NEW
35
    pub max_fee_rate: Option<FeeRate>,
×
36

37
    #[arg(
38
        long,
39
        short = 'r',
40
        num_args(1),
41
        help = "The URL of the Bitcoin RPC host, e.g. regtest default is http://localhost:18443"
42
    )]
43
    pub rpchost: Option<Url>,
8✔
44

45
    #[arg(
46
        long = "cookie-file",
47
        short = 'c',
48
        num_args(1),
49
        help = "Path to the cookie file of the bitcoin node"
50
    )]
51
    pub cookie_file: Option<PathBuf>,
8✔
52

53
    #[arg(long = "rpcuser", num_args(1), help = "The username for the bitcoin node")]
NEW
54
    pub rpcuser: Option<String>,
×
55

56
    #[arg(long = "rpcpassword", num_args(1), help = "The password for the bitcoin node")]
NEW
57
    pub rpcpassword: Option<String>,
×
58

59
    #[cfg(feature = "v1")]
60
    #[arg(long = "port", help = "The local port to listen on")]
NEW
61
    pub port: Option<u16>,
×
62

63
    #[cfg(feature = "v1")]
64
    #[arg(long = "pj-endpoint", help = "The `pj=` endpoint to receive the payjoin request", value_parser = value_parser!(Url))]
NEW
65
    pub pj_endpoint: Option<Url>,
×
66

67
    #[cfg(feature = "v2")]
68
    #[arg(long = "ohttp-relays", help = "One or more ohttp relay URLs, comma-separated", value_parser = value_parser!(Url))]
69
    pub ohttp_relays: Option<Vec<Url>>,
4✔
70

71
    #[cfg(feature = "v2")]
72
    #[arg(long = "ohttp-keys", help = "The ohttp key config file path", value_parser = value_parser!(PathBuf))]
NEW
73
    pub ohttp_keys: Option<PathBuf>,
×
74

75
    #[cfg(feature = "v2")]
76
    #[arg(long = "pj-directory", help = "The directory to store payjoin requests", value_parser = value_parser!(Url))]
NEW
77
    pub pj_directory: Option<Url>,
×
78
}
79

80
#[derive(Subcommand, Debug)]
17✔
81
pub enum Commands {
82
    /// Send a payjoin payment
83
    Send {
84
        /// The `bitcoin:...` payjoin uri to send to
85
        #[arg(required = true)]
86
        bip21: String,
4✔
87

88
        /// Fee rate in sat/vB
89
        #[arg(short, long = "fee-rate", value_parser = parse_fee_rate_in_sat_per_vb)]
90
        fee_rate: Option<FeeRate>,
4✔
91
    },
92
    /// Receive a payjoin payment
93
    Receive {
94
        /// The amount to receive in satoshis
95
        #[arg(required = true, value_parser = parse_amount_in_sat)]
96
        amount: Amount,
3✔
97

98
        /// The maximum effective fee rate the receiver is willing to pay (in sat/vB)
99
        #[arg(short, long = "max-fee-rate", value_parser = parse_fee_rate_in_sat_per_vb)]
NEW
100
        max_fee_rate: Option<FeeRate>,
×
101

102
        #[cfg(feature = "v1")]
103
        /// The local port to listen on
104
        #[arg(short, long = "port")]
105
        port: Option<u16>,
2✔
106

107
        #[cfg(feature = "v1")]
108
        /// The `pj=` endpoint to receive the payjoin request
109
        #[arg(long = "pj-endpoint", value_parser = value_parser!(Url))]
110
        pj_endpoint: Option<Url>,
2✔
111

112
        #[cfg(feature = "v2")]
113
        /// The directory to store payjoin requests
114
        #[arg(long = "pj-directory", value_parser = value_parser!(Url))]
115
        pj_directory: Option<Url>,
1✔
116

117
        #[cfg(feature = "v2")]
118
        /// The path to the ohttp keys file
119
        #[arg(long = "ohttp-keys", value_parser = value_parser!(PathBuf))]
120
        ohttp_keys: Option<PathBuf>,
1✔
121
    },
122
    /// Resume pending payjoins (BIP77/v2 only)
123
    #[cfg(feature = "v2")]
124
    Resume,
125
}
126

127
pub fn parse_amount_in_sat(s: &str) -> Result<Amount, ParseAmountError> {
3✔
128
    Amount::from_str_in(s, payjoin::bitcoin::Denomination::Satoshi)
3✔
129
}
3✔
130

131
pub fn parse_fee_rate_in_sat_per_vb(s: &str) -> Result<FeeRate, std::num::ParseFloatError> {
4✔
132
    let fee_rate_sat_per_vb: f32 = s.parse()?;
4✔
133
    let fee_rate_sat_per_kwu = fee_rate_sat_per_vb * 250.0_f32;
4✔
134
    Ok(FeeRate::from_sat_per_kwu(fee_rate_sat_per_kwu.ceil() as u64))
4✔
135
}
4✔
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