silent_payments_send/
error.rs1use silent_payments_core::error::{CryptoError, InputError};
8use thiserror::Error;
9
10#[derive(Debug, Error)]
12pub enum SendError {
13 #[error("BIP 352 requires SIGHASH_ALL, got {actual}")]
16 SighashNotAll { actual: String },
17
18 #[error("cannot create SP payment with zero inputs")]
20 NoOutpoints,
21
22 #[error(transparent)]
24 NoEligibleInputs(#[from] InputError),
25
26 #[error("eligible input public keys sum to the point at infinity")]
29 InputKeysSumToInfinity,
30
31 #[error(transparent)]
33 Crypto(#[from] CryptoError),
34}
35
36impl From<bdk_sp::send::error::SpSendError> for SendError {
37 fn from(err: bdk_sp::send::error::SpSendError) -> Self {
38 SendError::Crypto(CryptoError::Secp256k1(err.to_string()))
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn sighash_not_all_displays_meaningful_message() {
48 let err = SendError::SighashNotAll {
49 actual: "SIGHASH_NONE".to_string(),
50 };
51 let msg = err.to_string();
52 assert!(
53 msg.contains("SIGHASH_ALL"),
54 "should mention SIGHASH_ALL: {msg}"
55 );
56 assert!(
57 msg.contains("SIGHASH_NONE"),
58 "should mention actual type: {msg}"
59 );
60 }
61
62 #[test]
63 fn no_outpoints_displays_message() {
64 let err = SendError::NoOutpoints;
65 let msg = err.to_string();
66 assert!(
67 msg.contains("zero inputs"),
68 "should mention zero inputs: {msg}"
69 );
70 }
71
72 #[test]
73 fn no_eligible_inputs_wraps_input_error() {
74 let err = SendError::from(InputError::NoEligibleInputs);
75 let msg = err.to_string();
76 assert!(
77 msg.contains("no eligible"),
78 "should mention no eligible: {msg}"
79 );
80 }
81
82 #[test]
83 fn input_keys_sum_to_infinity_displays() {
84 let err = SendError::InputKeysSumToInfinity;
85 let msg = err.to_string();
86 assert!(
87 msg.contains("point at infinity"),
88 "should mention infinity: {msg}"
89 );
90 }
91
92 #[test]
93 fn crypto_error_wraps_transparently() {
94 let err = SendError::from(CryptoError::PointAtInfinity);
95 let msg = err.to_string();
96 assert!(
97 msg.contains("point at infinity"),
98 "should propagate message: {msg}"
99 );
100 }
101
102 #[test]
103 fn bdk_sp_error_converts_to_send_error() {
104 let bdk_err = bdk_sp::send::error::SpSendError::MissingInputsForSharedSecretDerivation;
105 let send_err = SendError::from(bdk_err);
106 assert!(
107 matches!(send_err, SendError::Crypto(_)),
108 "should map to Crypto variant"
109 );
110 }
111}