1
1
import { FastifyInstance } from "fastify" ;
2
2
import { ReasonPhrases , StatusCodes } from "http-status-codes" ;
3
+ import { ZodError } from "zod" ;
3
4
import { env } from "../../utils/env" ;
4
5
import { logger } from "../../utils/logger" ;
5
6
@@ -20,6 +21,46 @@ export const createCustomError = (
20
21
code,
21
22
} ) ;
22
23
24
+ const ETHERS_ERROR_CODES = [
25
+ "UNKNOWN_ERROR" ,
26
+ "NOT_IMPLEMENTED" ,
27
+ "UNSUPPORTED_OPERATION" ,
28
+ "NETWORK_ERROR" ,
29
+ "SERVER_ERROR" ,
30
+ "TIMEOUT" ,
31
+ "BAD_DATA" ,
32
+ "CANCELLED" ,
33
+ "BUFFER_OVERRUN" ,
34
+ "NUMERIC_FAULT" ,
35
+ "INVALID_ARGUMENT" ,
36
+ "MISSING_ARGUMENT" ,
37
+ "UNEXPECTED_ARGUMENT" ,
38
+ "VALUE_MISMATCH" ,
39
+ "CALL_EXCEPTION" ,
40
+ "INSUFFICIENT_FUNDS" ,
41
+ "NONCE_EXPIRED" ,
42
+ "REPLACEMENT_UNDERPRICED" ,
43
+ "TRANSACTION_REPLACED" ,
44
+ "UNCONFIGURED_NAME" ,
45
+ "OFFCHAIN_FAULT" ,
46
+ "ACTION_REJECTED" ,
47
+ ] ;
48
+
49
+ const isZodError = ( err : unknown ) : boolean => {
50
+ return Boolean (
51
+ err && ( err instanceof ZodError || ( err as ZodError ) . name === "ZodError" ) ,
52
+ ) ;
53
+ } ;
54
+
55
+ const isEthersError = ( error : any ) : boolean => {
56
+ return (
57
+ error &&
58
+ typeof error === "object" &&
59
+ "code" in error &&
60
+ ETHERS_ERROR_CODES . includes ( error . code )
61
+ ) ;
62
+ } ;
63
+
23
64
export const createCustomDateTimestampError = ( key : string ) : CustomError => {
24
65
return createCustomError (
25
66
`Invalid ${ key } Value. Needs to new Date() / new Date().toISOstring() / new Date().getTime() / Unix Epoch` ,
@@ -32,68 +73,84 @@ const flipObject = (data: any) =>
32
73
Object . fromEntries ( Object . entries ( data ) . map ( ( [ key , value ] ) => [ value , key ] ) ) ;
33
74
34
75
export const withErrorHandler = async ( server : FastifyInstance ) => {
35
- server . setErrorHandler ( ( error : Error | CustomError , request , reply ) => {
36
- logger ( {
37
- service : "server" ,
38
- level : "error" ,
39
- message : `Encountered server error` ,
40
- error,
41
- } ) ;
42
-
43
- // v4 : Contract Prepare Error Handler
44
- if ( error . message . includes ( "code=INVALID_ARGUMENT" ) ) {
45
- return reply . status ( StatusCodes . BAD_REQUEST ) . send ( {
46
- error : {
47
- code : "BAD_REQUEST" ,
48
- message : "INVALID_ARGUMENT" ,
49
- reason : error . message ,
50
- statusCode : 400 ,
51
- stack : env . NODE_ENV !== "production" ? error . stack : undefined ,
52
- } ,
76
+ server . setErrorHandler (
77
+ ( error : Error | CustomError | ZodError , request , reply ) => {
78
+ logger ( {
79
+ service : "server" ,
80
+ level : "error" ,
81
+ message : `Encountered server error` ,
82
+ error,
53
83
} ) ;
54
- }
55
84
56
- // v4: Zod Typings Errors
57
- if ( error . message . toLowerCase ( ) . includes ( "invalid input" ) ) {
58
- return reply . status ( StatusCodes . BAD_REQUEST ) . send ( {
59
- error : {
60
- code : "BAD_REQUEST" ,
61
- message : "Invalid input" ,
62
- reason : JSON . parse ( error . message ) ,
63
- statusCode : 400 ,
64
- stack : env . NODE_ENV !== "production" ? error . stack : undefined ,
65
- } ,
66
- } ) ;
67
- }
85
+ // Ethers Error Codes
86
+ if ( isEthersError ( error ) ) {
87
+ return reply . status ( StatusCodes . BAD_REQUEST ) . send ( {
88
+ error : {
89
+ code : "BAD_REQUEST" ,
90
+ message : ( error as any ) . code ,
91
+ reason : error . message ,
92
+ statusCode : 400 ,
93
+ stack : env . NODE_ENV !== "production" ? error . stack : undefined ,
94
+ } ,
95
+ } ) ;
96
+ }
97
+
98
+ // Zod Typings Errors
99
+ if ( isZodError ( error ) ) {
100
+ const _error = error as ZodError ;
101
+ let parsedMessage : any [ ] = [ ] ;
68
102
69
- // Handle Custom Errors
70
- if ( "statusCode" in error && "code" in error ) {
71
- // Transform unexpected errors into a standard payload
72
- const statusCode = error . statusCode ?? StatusCodes . INTERNAL_SERVER_ERROR ;
73
- const code =
74
- error . code ??
75
- flipObject ( StatusCodes ) [ statusCode ] ??
76
- StatusCodes . INTERNAL_SERVER_ERROR ;
103
+ try {
104
+ parsedMessage = JSON . parse ( _error . message ) ;
105
+ } catch ( e ) {
106
+ console . error ( "Failed to parse error message:" , e ) ;
107
+ }
108
+ const errorObject =
109
+ Array . isArray ( parsedMessage ) && parsedMessage . length > 0
110
+ ? parsedMessage [ 0 ]
111
+ : { } ;
77
112
78
- const message = error . message ?? ReasonPhrases . INTERNAL_SERVER_ERROR ;
79
- return reply . status ( statusCode ) . send ( {
113
+ return reply . status ( StatusCodes . BAD_REQUEST ) . send ( {
114
+ error : {
115
+ code : "BAD_REQUEST" ,
116
+ message : errorObject . message ?? "Invalid Request" ,
117
+ reason : errorObject ?? undefined ,
118
+ statusCode : 400 ,
119
+ stack : env . NODE_ENV !== "production" ? _error . stack : undefined ,
120
+ } ,
121
+ } ) ;
122
+ }
123
+
124
+ // Handle Custom Errors
125
+ if ( "statusCode" in error && "code" in error ) {
126
+ // Transform unexpected errors into a standard payload
127
+ const statusCode =
128
+ error . statusCode ?? StatusCodes . INTERNAL_SERVER_ERROR ;
129
+ const code =
130
+ error . code ??
131
+ flipObject ( StatusCodes ) [ statusCode ] ??
132
+ StatusCodes . INTERNAL_SERVER_ERROR ;
133
+
134
+ const message = error . message ?? ReasonPhrases . INTERNAL_SERVER_ERROR ;
135
+ return reply . status ( statusCode ) . send ( {
136
+ error : {
137
+ code,
138
+ message,
139
+ statusCode,
140
+ stack : env . NODE_ENV !== "production" ? error . stack : undefined ,
141
+ } ,
142
+ } ) ;
143
+ }
144
+
145
+ // Handle non-custom errors
146
+ return reply . status ( StatusCodes . INTERNAL_SERVER_ERROR ) . send ( {
80
147
error : {
81
- code ,
82
- message ,
83
- statusCode ,
148
+ statusCode : 500 ,
149
+ code : "INTERNAL_SERVER_ERROR" ,
150
+ message : error . message || ReasonPhrases . INTERNAL_SERVER_ERROR ,
84
151
stack : env . NODE_ENV !== "production" ? error . stack : undefined ,
85
152
} ,
86
153
} ) ;
87
- }
88
-
89
- // Handle non-custom errors
90
- return reply . status ( StatusCodes . INTERNAL_SERVER_ERROR ) . send ( {
91
- error : {
92
- statusCode : 500 ,
93
- code : "INTERNAL_SERVER_ERROR" ,
94
- message : error . message || ReasonPhrases . INTERNAL_SERVER_ERROR ,
95
- stack : env . NODE_ENV !== "production" ? error . stack : undefined ,
96
- } ,
97
- } ) ;
98
- } ) ;
154
+ } ,
155
+ ) ;
99
156
} ;
0 commit comments