11use std:: { error, fmt} ;
22
3+ use crate :: error_codes:: {
4+ NOT_ENOUGH_MONEY , ORIGINAL_PSBT_REJECTED , UNAVAILABLE , VERSION_UNSUPPORTED ,
5+ } ;
36#[ cfg( feature = "v1" ) ]
47use crate :: receive:: v1;
58#[ cfg( feature = "v2" ) ]
@@ -25,16 +28,41 @@ pub enum Error {
2528 Implementation ( Box < dyn error:: Error + Send + Sync > ) ,
2629}
2730
28- impl Error {
29- pub fn to_json ( & self ) -> String {
31+ /// A trait for errors that can be serialized to JSON in a standardized format.
32+ ///
33+ /// The JSON output follows the structure:
34+ /// ```json
35+ /// {
36+ /// "errorCode": "specific-error-code",
37+ /// "message": "Human readable error message"
38+ /// }
39+ /// ```
40+ pub trait JsonError {
41+ /// Converts the error into a JSON string representation.
42+ fn to_json ( & self ) -> String ;
43+ }
44+
45+ impl JsonError for Error {
46+ fn to_json ( & self ) -> String {
3047 match self {
31- Self :: Validation ( e) => e. to_string ( ) ,
32- Self :: Implementation ( _) =>
33- "{{ \" errorCode\" : \" unavailable\" , \" message\" : \" Receiver error\" }}" . to_string ( ) ,
48+ Self :: Validation ( e) => e. to_json ( ) ,
49+ Self :: Implementation ( _) => serialize_json_error ( UNAVAILABLE , "Receiver error" ) ,
3450 }
3551 }
3652}
3753
54+ pub ( crate ) fn serialize_json_error ( code : & str , message : impl fmt:: Display ) -> String {
55+ format ! ( r#"{{ "errorCode": "{}", "message": "{}" }}"# , code, message)
56+ }
57+
58+ pub ( crate ) fn serialize_json_plus_fields (
59+ code : & str ,
60+ message : impl fmt:: Display ,
61+ additional_fields : & str ,
62+ ) -> String {
63+ format ! ( r#"{{ "errorCode": "{}", "message": "{}", {} }}"# , code, message, additional_fields)
64+ }
65+
3866impl fmt:: Display for Error {
3967 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
4068 match & self {
@@ -85,6 +113,18 @@ impl From<v2::InternalSessionError> for ValidationError {
85113 fn from ( e : v2:: InternalSessionError ) -> Self { ValidationError :: V2 ( e. into ( ) ) }
86114}
87115
116+ impl JsonError for ValidationError {
117+ fn to_json ( & self ) -> String {
118+ match self {
119+ ValidationError :: Payload ( e) => e. to_json ( ) ,
120+ #[ cfg( feature = "v1" ) ]
121+ ValidationError :: V1 ( e) => e. to_json ( ) ,
122+ #[ cfg( feature = "v2" ) ]
123+ ValidationError :: V2 ( e) => e. to_json ( ) ,
124+ }
125+ }
126+ }
127+
88128impl fmt:: Display for ValidationError {
89129 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
90130 match self {
@@ -164,65 +204,62 @@ pub(crate) enum InternalPayloadError {
164204 FeeTooHigh ( bitcoin:: FeeRate , bitcoin:: FeeRate ) ,
165205}
166206
167- impl fmt :: Display for PayloadError {
168- fn fmt ( & self , f : & mut fmt :: Formatter ) -> fmt :: Result {
207+ impl JsonError for PayloadError {
208+ fn to_json ( & self ) -> String {
169209 use InternalPayloadError :: * ;
170210
171- fn write_error (
172- f : & mut fmt:: Formatter ,
173- code : & str ,
174- message : impl fmt:: Display ,
175- ) -> fmt:: Result {
176- write ! ( f, r#"{{ "errorCode": "{}", "message": "{}" }}"# , code, message)
177- }
178-
179211 match & self . 0 {
180- Utf8 ( e ) => write_error ( f , "original-psbt-rejected" , e ) ,
181- ParsePsbt ( e ) => write_error ( f , "original-psbt-rejected" , e ) ,
212+ Utf8 ( _ ) => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
213+ ParsePsbt ( _ ) => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
182214 SenderParams ( e) => match e {
183215 super :: optional_parameters:: Error :: UnknownVersion { supported_versions } => {
184- write ! (
185- f,
186- r#"{{
187- "errorCode": "version-unsupported",
188- "supported": "{}",
189- "message": "This version of payjoin is not supported."
190- }}"# ,
191- serde_json:: to_string( supported_versions) . map_err( |_| fmt:: Error ) ?
216+ let supported_versions_json =
217+ serde_json:: to_string ( supported_versions) . unwrap_or_default ( ) ;
218+ serialize_json_plus_fields (
219+ VERSION_UNSUPPORTED ,
220+ "This version of payjoin is not supported." ,
221+ & format ! ( r#""supported": {}"# , supported_versions_json) ,
192222 )
193223 }
194- _ => write_error ( f , "sender-params-error" , e ) ,
224+ _ => serialize_json_error ( "sender-params-error" , self ) ,
195225 } ,
196- InconsistentPsbt ( e) => write_error ( f, "original-psbt-rejected" , e) ,
197- PrevTxOut ( e) =>
198- write_error ( f, "original-psbt-rejected" , format ! ( "PrevTxOut Error: {}" , e) ) ,
199- MissingPayment => write_error ( f, "original-psbt-rejected" , "Missing payment." ) ,
200- OriginalPsbtNotBroadcastable => write_error (
201- f,
202- "original-psbt-rejected" ,
203- "Can't broadcast. PSBT rejected by mempool." ,
204- ) ,
205- InputOwned ( _) =>
206- write_error ( f, "original-psbt-rejected" , "The receiver rejected the original PSBT." ) ,
207- InputWeight ( e) =>
208- write_error ( f, "original-psbt-rejected" , format ! ( "InputWeight Error: {}" , e) ) ,
209- InputSeen ( _) =>
210- write_error ( f, "original-psbt-rejected" , "The receiver rejected the original PSBT." ) ,
211- PsbtBelowFeeRate ( original_psbt_fee_rate, receiver_min_fee_rate) => write_error (
226+ InconsistentPsbt ( _) => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
227+ PrevTxOut ( _) => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
228+ MissingPayment => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
229+ OriginalPsbtNotBroadcastable => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
230+ InputOwned ( _) => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
231+ InputWeight ( _) => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
232+ InputSeen ( _) => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
233+ PsbtBelowFeeRate ( _, _) => serialize_json_error ( ORIGINAL_PSBT_REJECTED , self ) ,
234+ FeeTooHigh ( _, _) => serialize_json_error ( NOT_ENOUGH_MONEY , self ) ,
235+ }
236+ }
237+ }
238+
239+ impl fmt:: Display for PayloadError {
240+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
241+ use InternalPayloadError :: * ;
242+
243+ match & self . 0 {
244+ Utf8 ( e) => write ! ( f, "{}" , e) ,
245+ ParsePsbt ( e) => write ! ( f, "{}" , e) ,
246+ SenderParams ( e) => write ! ( f, "{}" , e) ,
247+ InconsistentPsbt ( e) => write ! ( f, "{}" , e) ,
248+ PrevTxOut ( e) => write ! ( f, "PrevTxOut Error: {}" , e) ,
249+ MissingPayment => write ! ( f, "Missing payment." ) ,
250+ OriginalPsbtNotBroadcastable => write ! ( f, "Can't broadcast. PSBT rejected by mempool." ) ,
251+ InputOwned ( _) => write ! ( f, "The receiver rejected the original PSBT." ) ,
252+ InputWeight ( e) => write ! ( f, "InputWeight Error: {}" , e) ,
253+ InputSeen ( _) => write ! ( f, "The receiver rejected the original PSBT." ) ,
254+ PsbtBelowFeeRate ( original_psbt_fee_rate, receiver_min_fee_rate) => write ! (
212255 f,
213- "original-psbt-rejected" ,
214- format ! (
215- "Original PSBT fee rate too low: {} < {}." ,
216- original_psbt_fee_rate, receiver_min_fee_rate
217- ) ,
256+ "Original PSBT fee rate too low: {} < {}." ,
257+ original_psbt_fee_rate, receiver_min_fee_rate
218258 ) ,
219- FeeTooHigh ( proposed_fee_rate, max_fee_rate) => write_error (
259+ FeeTooHigh ( proposed_fee_rate, max_fee_rate) => write ! (
220260 f,
221- "original-psbt-rejected" ,
222- format ! (
223- "Effective receiver feerate exceeds maximum allowed feerate: {} > {}" ,
224- proposed_fee_rate, max_fee_rate
225- ) ,
261+ "Effective receiver feerate exceeds maximum allowed feerate: {} > {}" ,
262+ proposed_fee_rate, max_fee_rate
226263 ) ,
227264 }
228265 }
0 commit comments