@0xmonaco/core 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -8
- package/dist/api/applications/api.d.ts +1 -2
- package/dist/api/applications/api.d.ts.map +1 -1
- package/dist/api/applications/api.js +1 -2
- package/dist/api/applications/api.js.map +1 -1
- package/dist/api/applications/index.d.ts +1 -2
- package/dist/api/applications/index.d.ts.map +1 -1
- package/dist/api/applications/index.js +1 -1
- package/dist/api/applications/index.js.map +1 -1
- package/dist/api/auth/api.d.ts +1 -1
- package/dist/api/auth/api.d.ts.map +1 -1
- package/dist/api/auth/api.js +2 -2
- package/dist/api/auth/api.js.map +1 -1
- package/dist/api/auth/index.d.ts +1 -2
- package/dist/api/auth/index.d.ts.map +1 -1
- package/dist/api/auth/index.js +1 -1
- package/dist/api/auth/index.js.map +1 -1
- package/dist/api/base.d.ts +26 -1
- package/dist/api/base.d.ts.map +1 -1
- package/dist/api/base.js +173 -43
- package/dist/api/base.js.map +1 -1
- package/dist/api/fees/api.d.ts +1 -1
- package/dist/api/fees/api.d.ts.map +1 -1
- package/dist/api/fees/api.js +4 -4
- package/dist/api/fees/api.js.map +1 -1
- package/dist/api/fees/index.d.ts +1 -1
- package/dist/api/fees/index.d.ts.map +1 -1
- package/dist/api/fees/index.js +1 -1
- package/dist/api/fees/index.js.map +1 -1
- package/dist/api/index.d.ts +10 -8
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +10 -8
- package/dist/api/index.js.map +1 -1
- package/dist/api/market/api.d.ts +1 -1
- package/dist/api/market/api.d.ts.map +1 -1
- package/dist/api/market/api.js +12 -3
- package/dist/api/market/api.js.map +1 -1
- package/dist/api/market/index.d.ts +1 -2
- package/dist/api/market/index.d.ts.map +1 -1
- package/dist/api/market/index.js +1 -1
- package/dist/api/market/index.js.map +1 -1
- package/dist/api/orderbook/api.d.ts +16 -0
- package/dist/api/orderbook/api.d.ts.map +1 -0
- package/dist/api/orderbook/api.js +38 -0
- package/dist/api/orderbook/api.js.map +1 -0
- package/dist/api/orderbook/index.d.ts +2 -0
- package/dist/api/orderbook/index.d.ts.map +1 -0
- package/dist/api/orderbook/index.js +2 -0
- package/dist/api/orderbook/index.js.map +1 -0
- package/dist/api/profile/api.d.ts +10 -11
- package/dist/api/profile/api.d.ts.map +1 -1
- package/dist/api/profile/api.js +17 -11
- package/dist/api/profile/api.js.map +1 -1
- package/dist/api/profile/index.d.ts +1 -1
- package/dist/api/profile/index.d.ts.map +1 -1
- package/dist/api/profile/index.js +1 -1
- package/dist/api/profile/index.js.map +1 -1
- package/dist/api/trades/api.d.ts +45 -0
- package/dist/api/trades/api.d.ts.map +1 -0
- package/dist/api/trades/api.js +43 -0
- package/dist/api/trades/api.js.map +1 -0
- package/dist/api/trades/index.d.ts +2 -0
- package/dist/api/trades/index.d.ts.map +1 -0
- package/dist/api/trades/index.js +2 -0
- package/dist/api/trades/index.js.map +1 -0
- package/dist/api/trading/api.d.ts +1 -2
- package/dist/api/trading/api.d.ts.map +1 -1
- package/dist/api/trading/api.js +10 -2
- package/dist/api/trading/api.js.map +1 -1
- package/dist/api/trading/index.d.ts +1 -2
- package/dist/api/trading/index.d.ts.map +1 -1
- package/dist/api/trading/index.js +1 -1
- package/dist/api/trading/index.js.map +1 -1
- package/dist/api/vault/api.d.ts +17 -19
- package/dist/api/vault/api.d.ts.map +1 -1
- package/dist/api/vault/api.js +58 -46
- package/dist/api/vault/api.js.map +1 -1
- package/dist/api/vault/index.d.ts +1 -2
- package/dist/api/vault/index.d.ts.map +1 -1
- package/dist/api/vault/index.js +1 -1
- package/dist/api/vault/index.js.map +1 -1
- package/dist/api/websocket/index.d.ts +3 -9
- package/dist/api/websocket/index.d.ts.map +1 -1
- package/dist/api/websocket/index.js +3 -9
- package/dist/api/websocket/index.js.map +1 -1
- package/dist/api/websocket/types.d.ts +34 -0
- package/dist/api/websocket/types.d.ts.map +1 -0
- package/dist/api/websocket/types.js +2 -0
- package/dist/api/websocket/types.js.map +1 -0
- package/dist/api/websocket/utils.d.ts +9 -0
- package/dist/api/websocket/utils.d.ts.map +1 -0
- package/dist/api/websocket/utils.js +23 -0
- package/dist/api/websocket/utils.js.map +1 -0
- package/dist/api/websocket/websocket.d.ts +6 -0
- package/dist/api/websocket/websocket.d.ts.map +1 -0
- package/dist/api/websocket/websocket.js +309 -0
- package/dist/api/websocket/websocket.js.map +1 -0
- package/dist/errors/errors.d.ts +382 -0
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/errors/errors.js +801 -0
- package/dist/errors/errors.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +5 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -22
- package/dist/index.js.map +1 -1
- package/dist/networks/index.d.ts +2 -0
- package/dist/networks/index.d.ts.map +1 -0
- package/dist/networks/index.js +2 -0
- package/dist/networks/index.js.map +1 -0
- package/dist/{networks.d.ts → networks/networks.d.ts} +1 -1
- package/dist/networks/networks.d.ts.map +1 -0
- package/dist/{networks.js → networks/networks.js} +4 -3
- package/dist/networks/networks.js.map +1 -0
- package/dist/sdk.d.ts +19 -27
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +77 -107
- package/dist/sdk.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +5 -7
- package/dist/api/websocket/base-ws-client.d.ts +0 -85
- package/dist/api/websocket/base-ws-client.d.ts.map +0 -1
- package/dist/api/websocket/base-ws-client.js +0 -256
- package/dist/api/websocket/base-ws-client.js.map +0 -1
- package/dist/api/websocket/clients/ohlcv-ws-client.d.ts +0 -57
- package/dist/api/websocket/clients/ohlcv-ws-client.d.ts.map +0 -1
- package/dist/api/websocket/clients/ohlcv-ws-client.js +0 -132
- package/dist/api/websocket/clients/ohlcv-ws-client.js.map +0 -1
- package/dist/api/websocket/clients/orderbook-ws-client.d.ts +0 -70
- package/dist/api/websocket/clients/orderbook-ws-client.d.ts.map +0 -1
- package/dist/api/websocket/clients/orderbook-ws-client.js +0 -197
- package/dist/api/websocket/clients/orderbook-ws-client.js.map +0 -1
- package/dist/api/websocket/clients/orders-ws-client.d.ts +0 -61
- package/dist/api/websocket/clients/orders-ws-client.d.ts.map +0 -1
- package/dist/api/websocket/clients/orders-ws-client.js +0 -150
- package/dist/api/websocket/clients/orders-ws-client.js.map +0 -1
- package/dist/errors.d.ts +0 -103
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -108
- package/dist/errors.js.map +0 -1
- package/dist/networks.d.ts.map +0 -1
- package/dist/networks.js.map +0 -1
|
@@ -0,0 +1,801 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Monaco SDK Error Types
|
|
3
|
+
*
|
|
4
|
+
* Standardized error classes for SDK operations with built-in sensitive data sanitization.
|
|
5
|
+
* All error classes inherit from MonacoCoreError and provide structured error information
|
|
6
|
+
* with automatic suggestions for common failure scenarios.
|
|
7
|
+
*
|
|
8
|
+
* @module errors
|
|
9
|
+
*/
|
|
10
|
+
import { StatusCodes } from "http-status-codes";
|
|
11
|
+
/**
|
|
12
|
+
* Sensitive field names that should be redacted in error logs.
|
|
13
|
+
*
|
|
14
|
+
* When errors are serialized (via toJSON()) and sent to external monitoring services
|
|
15
|
+
* like Sentry, Datadog, or CloudWatch, these fields will be replaced with "[REDACTED]"
|
|
16
|
+
* to prevent exposure of sensitive information.
|
|
17
|
+
*
|
|
18
|
+
* Categories:
|
|
19
|
+
* - Authentication & Authorization: tokens, API keys, secrets
|
|
20
|
+
* - User PII: emails, phone numbers, addresses
|
|
21
|
+
* - Security credentials: private keys, mnemonics, signatures
|
|
22
|
+
* - Session data: cookies, session IDs
|
|
23
|
+
*
|
|
24
|
+
* @constant
|
|
25
|
+
*/
|
|
26
|
+
const SENSITIVE_FIELDS = [
|
|
27
|
+
// Authentication & Authorization
|
|
28
|
+
"token",
|
|
29
|
+
"accessToken",
|
|
30
|
+
"access_token",
|
|
31
|
+
"refreshToken",
|
|
32
|
+
"refresh_token",
|
|
33
|
+
"authToken",
|
|
34
|
+
"auth_token",
|
|
35
|
+
"bearerToken",
|
|
36
|
+
"bearer_token",
|
|
37
|
+
"jwtToken",
|
|
38
|
+
"jwt_token",
|
|
39
|
+
"apiKey",
|
|
40
|
+
"api_key",
|
|
41
|
+
"apikey",
|
|
42
|
+
"clientSecret",
|
|
43
|
+
"client_secret",
|
|
44
|
+
"clientId",
|
|
45
|
+
"client_id",
|
|
46
|
+
"secret",
|
|
47
|
+
"password",
|
|
48
|
+
"authorization",
|
|
49
|
+
"bearer",
|
|
50
|
+
"auth",
|
|
51
|
+
"credentials",
|
|
52
|
+
"credential",
|
|
53
|
+
// User PII
|
|
54
|
+
"email",
|
|
55
|
+
"phone",
|
|
56
|
+
"phoneNumber",
|
|
57
|
+
"phone_number",
|
|
58
|
+
"ssn",
|
|
59
|
+
"socialSecurity",
|
|
60
|
+
"social_security",
|
|
61
|
+
"address",
|
|
62
|
+
"passport",
|
|
63
|
+
"passportNumber",
|
|
64
|
+
"passport_number",
|
|
65
|
+
"driversLicense",
|
|
66
|
+
"drivers_license",
|
|
67
|
+
// Financial
|
|
68
|
+
"cardNumber",
|
|
69
|
+
"card_number",
|
|
70
|
+
"creditCard",
|
|
71
|
+
"credit_card",
|
|
72
|
+
"cvv",
|
|
73
|
+
"pin",
|
|
74
|
+
// Security & Crypto
|
|
75
|
+
"signature",
|
|
76
|
+
"privateKey",
|
|
77
|
+
"private_key",
|
|
78
|
+
"publicKey",
|
|
79
|
+
"public_key",
|
|
80
|
+
"mnemonic",
|
|
81
|
+
"seed",
|
|
82
|
+
"salt",
|
|
83
|
+
"hash",
|
|
84
|
+
"certificate",
|
|
85
|
+
"cert",
|
|
86
|
+
"fingerprint",
|
|
87
|
+
// Session & Cookies
|
|
88
|
+
"cookie",
|
|
89
|
+
"session",
|
|
90
|
+
"sessionId",
|
|
91
|
+
"session_id",
|
|
92
|
+
"sessionToken",
|
|
93
|
+
"session_token",
|
|
94
|
+
// Network & Device
|
|
95
|
+
"ipAddress",
|
|
96
|
+
"ip_address",
|
|
97
|
+
"deviceId",
|
|
98
|
+
"device_id",
|
|
99
|
+
"userId",
|
|
100
|
+
"user_id",
|
|
101
|
+
"accountId",
|
|
102
|
+
"account_id",
|
|
103
|
+
];
|
|
104
|
+
/**
|
|
105
|
+
* Sanitize data by redacting sensitive fields and limiting size.
|
|
106
|
+
*
|
|
107
|
+
* Recursively processes data structures to protect sensitive information while
|
|
108
|
+
* preserving debugging utility. Used by error classes when serializing to JSON.
|
|
109
|
+
*
|
|
110
|
+
* **Protections applied:**
|
|
111
|
+
* - Redacts sensitive fields (tokens, passwords, PII, etc.)
|
|
112
|
+
* - Truncates long strings (500 chars for object values, 1000 for standalone)
|
|
113
|
+
* - Limits array size (10 items max, then "... N more items")
|
|
114
|
+
* - Prevents infinite recursion (max depth: 5)
|
|
115
|
+
*
|
|
116
|
+
* **Examples:**
|
|
117
|
+
* ```typescript
|
|
118
|
+
* sanitizeData({ token: "secret", name: "John" })
|
|
119
|
+
* // → { token: "[REDACTED]", name: "John" }
|
|
120
|
+
*
|
|
121
|
+
* sanitizeData(["a".repeat(1000)])
|
|
122
|
+
* // → ["aaa... [truncated]"]
|
|
123
|
+
*
|
|
124
|
+
* sanitizeData({ nested: { deep: { ... } } }, 2)
|
|
125
|
+
* // → { nested: { deep: "[Max depth reached]" } }
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* @param data - Data to sanitize (any type)
|
|
129
|
+
* @param maxDepth - Maximum recursion depth to prevent infinite loops (default: 5)
|
|
130
|
+
* @param currentDepth - Internal parameter tracking current recursion level
|
|
131
|
+
* @returns Sanitized data safe for logging to external services
|
|
132
|
+
*/
|
|
133
|
+
function sanitizeData(data, maxDepth = 5, currentDepth = 0) {
|
|
134
|
+
// Prevent infinite recursion
|
|
135
|
+
if (currentDepth >= maxDepth) {
|
|
136
|
+
return "[Max depth reached]";
|
|
137
|
+
}
|
|
138
|
+
// Handle null/undefined
|
|
139
|
+
if (data === null || data === undefined) {
|
|
140
|
+
return data;
|
|
141
|
+
}
|
|
142
|
+
// Handle arrays
|
|
143
|
+
if (Array.isArray(data)) {
|
|
144
|
+
// Limit array size to prevent huge logs
|
|
145
|
+
const limit = 10;
|
|
146
|
+
const sanitized = data.slice(0, limit).map((item) => sanitizeData(item, maxDepth, currentDepth + 1));
|
|
147
|
+
if (data.length > limit) {
|
|
148
|
+
sanitized.push(`[... ${data.length - limit} more items]`);
|
|
149
|
+
}
|
|
150
|
+
return sanitized;
|
|
151
|
+
}
|
|
152
|
+
// Handle objects
|
|
153
|
+
if (typeof data === "object") {
|
|
154
|
+
const sanitized = {};
|
|
155
|
+
for (const [key, value] of Object.entries(data)) {
|
|
156
|
+
const lowerKey = key.toLowerCase();
|
|
157
|
+
// Check if field is sensitive
|
|
158
|
+
const isSensitive = SENSITIVE_FIELDS.some((field) => lowerKey.includes(field.toLowerCase()));
|
|
159
|
+
if (isSensitive) {
|
|
160
|
+
sanitized[key] = "[REDACTED]";
|
|
161
|
+
}
|
|
162
|
+
else if (typeof value === "string" && value.length > 500) {
|
|
163
|
+
// Truncate long strings to prevent huge logs
|
|
164
|
+
sanitized[key] = value.substring(0, 500) + "... [truncated]";
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
sanitized[key] = sanitizeData(value, maxDepth, currentDepth + 1);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return sanitized;
|
|
171
|
+
}
|
|
172
|
+
// Handle strings
|
|
173
|
+
if (typeof data === "string") {
|
|
174
|
+
// Truncate long strings
|
|
175
|
+
if (data.length > 1000) {
|
|
176
|
+
return data.substring(0, 1000) + "... [truncated]";
|
|
177
|
+
}
|
|
178
|
+
return data;
|
|
179
|
+
}
|
|
180
|
+
// Primitives (numbers, booleans) pass through
|
|
181
|
+
return data;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Monaco Core SDK error codes.
|
|
185
|
+
*
|
|
186
|
+
* Categorized error codes for better error handling and debugging.
|
|
187
|
+
* Each error class uses one of these codes to identify the error type.
|
|
188
|
+
*
|
|
189
|
+
* **Categories:**
|
|
190
|
+
*
|
|
191
|
+
* **Initialization Errors** (Configuration and setup):
|
|
192
|
+
* - `INITIALIZATION_ERROR`: General initialization failure
|
|
193
|
+
* - `INVALID_CONFIG`: Invalid SDK configuration (missing/wrong parameters)
|
|
194
|
+
* - `INVALID_STATE`: Invalid SDK state (operation called at wrong time)
|
|
195
|
+
* - `UNSUPPORTED_NETWORK`: Network not supported by SDK
|
|
196
|
+
*
|
|
197
|
+
* **API Errors** (External communication):
|
|
198
|
+
* - `API_ERROR`: API request failed (HTTP errors, network issues)
|
|
199
|
+
* - `CONTRACT_ERROR`: Smart contract interaction failure
|
|
200
|
+
* - `TRANSACTION_ERROR`: Blockchain transaction failure
|
|
201
|
+
*
|
|
202
|
+
* **Order Errors** (Trading operations):
|
|
203
|
+
* - `ORDER_ERROR`: General order operation failure
|
|
204
|
+
* - `INVALID_ORDER`: Order validation failure (invalid parameters)
|
|
205
|
+
* - `ORDER_NOT_FOUND`: Order does not exist
|
|
206
|
+
* - `INSUFFICIENT_BALANCE`: Insufficient token balance for operation
|
|
207
|
+
*
|
|
208
|
+
* **Event Errors** (WebSocket and subscriptions):
|
|
209
|
+
* - `EVENT_ERROR`: General event handling failure
|
|
210
|
+
* - `SUBSCRIPTION_ERROR`: Event subscription failure
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* try {
|
|
215
|
+
* await sdk.someOperation();
|
|
216
|
+
* } catch (error) {
|
|
217
|
+
* if (error.code === ERROR_CODES.INVALID_CONFIG) {
|
|
218
|
+
* // Handle configuration error
|
|
219
|
+
* } else if (error.code === ERROR_CODES.API_ERROR) {
|
|
220
|
+
* // Handle API error
|
|
221
|
+
* }
|
|
222
|
+
* }
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* @constant
|
|
226
|
+
*/
|
|
227
|
+
export const ERROR_CODES = {
|
|
228
|
+
/** Initialization errors */
|
|
229
|
+
INITIALIZATION_ERROR: "INITIALIZATION_ERROR",
|
|
230
|
+
INVALID_CONFIG: "INVALID_CONFIG",
|
|
231
|
+
INVALID_STATE: "INVALID_STATE",
|
|
232
|
+
UNSUPPORTED_NETWORK: "UNSUPPORTED_NETWORK",
|
|
233
|
+
/** API errors */
|
|
234
|
+
API_ERROR: "API_ERROR",
|
|
235
|
+
CONTRACT_ERROR: "CONTRACT_ERROR",
|
|
236
|
+
TRANSACTION_ERROR: "TRANSACTION_ERROR",
|
|
237
|
+
/** Order errors */
|
|
238
|
+
ORDER_ERROR: "ORDER_ERROR",
|
|
239
|
+
INVALID_ORDER: "INVALID_ORDER",
|
|
240
|
+
ORDER_NOT_FOUND: "ORDER_NOT_FOUND",
|
|
241
|
+
INSUFFICIENT_BALANCE: "INSUFFICIENT_BALANCE",
|
|
242
|
+
/** Event errors */
|
|
243
|
+
EVENT_ERROR: "EVENT_ERROR",
|
|
244
|
+
SUBSCRIPTION_ERROR: "SUBSCRIPTION_ERROR",
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Base class for all Monaco SDK errors.
|
|
248
|
+
*
|
|
249
|
+
* Provides common error functionality including:
|
|
250
|
+
* - Structured error codes for programmatic handling
|
|
251
|
+
* - Automatic recovery suggestions based on error context
|
|
252
|
+
* - Retryability indication for automatic retry logic
|
|
253
|
+
* - Timestamps for error tracking
|
|
254
|
+
* - JSON serialization for logging to external services
|
|
255
|
+
* - Cause chain support for error wrapping
|
|
256
|
+
*
|
|
257
|
+
* All SDK errors inherit from this class and provide specific error details.
|
|
258
|
+
*
|
|
259
|
+
* **Common Properties:**
|
|
260
|
+
* - `code`: MonacoErrorCode - Categorized error identifier
|
|
261
|
+
* - `message`: string - Human-readable error description
|
|
262
|
+
* - `suggestion`: string | undefined - Actionable recovery steps
|
|
263
|
+
* - `retryable`: boolean - Whether the operation can be retried
|
|
264
|
+
* - `timestamp`: number - Unix timestamp when error occurred
|
|
265
|
+
* - `cause`: unknown - Original error that caused this error (if wrapped)
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```typescript
|
|
269
|
+
* try {
|
|
270
|
+
* await sdk.someOperation();
|
|
271
|
+
* } catch (error) {
|
|
272
|
+
* if (error instanceof MonacoCoreError) {
|
|
273
|
+
* console.log(`Error: ${error.message}`);
|
|
274
|
+
* console.log(`Code: ${error.code}`);
|
|
275
|
+
* console.log(`Suggestion: ${error.suggestion}`);
|
|
276
|
+
* console.log(`Can retry: ${error.retryable}`);
|
|
277
|
+
*
|
|
278
|
+
* // Send to monitoring service
|
|
279
|
+
* logger.error(error.toJSON());
|
|
280
|
+
* }
|
|
281
|
+
* }
|
|
282
|
+
* ```
|
|
283
|
+
*
|
|
284
|
+
* @abstract
|
|
285
|
+
*/
|
|
286
|
+
export class MonacoCoreError extends Error {
|
|
287
|
+
constructor(message, options) {
|
|
288
|
+
super(message);
|
|
289
|
+
this.retryable = false;
|
|
290
|
+
this.name = this.constructor.name;
|
|
291
|
+
this.timestamp = Date.now();
|
|
292
|
+
if (options?.cause) {
|
|
293
|
+
this.cause = options.cause;
|
|
294
|
+
}
|
|
295
|
+
if (options?.suggestion) {
|
|
296
|
+
this.suggestion = options.suggestion;
|
|
297
|
+
}
|
|
298
|
+
if (options?.retryable !== undefined) {
|
|
299
|
+
this.retryable = options.retryable;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Serialize error to JSON for logging/reporting
|
|
304
|
+
*/
|
|
305
|
+
toJSON() {
|
|
306
|
+
return {
|
|
307
|
+
name: this.name,
|
|
308
|
+
code: this.code,
|
|
309
|
+
message: this.message,
|
|
310
|
+
suggestion: this.suggestion,
|
|
311
|
+
retryable: this.retryable,
|
|
312
|
+
timestamp: this.timestamp,
|
|
313
|
+
cause: this.cause instanceof Error ? this.cause.message : this.cause,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Error thrown when SDK is initialized or configured incorrectly.
|
|
319
|
+
*
|
|
320
|
+
* Indicates invalid or missing configuration parameters that prevent
|
|
321
|
+
* the SDK from initializing or operating correctly. Includes automatic
|
|
322
|
+
* suggestions for common configuration fields.
|
|
323
|
+
*
|
|
324
|
+
* **Additional Properties:**
|
|
325
|
+
* - `field`: string | undefined - The configuration field that's invalid
|
|
326
|
+
* - `value`: unknown - The invalid value provided (sanitized in toJSON)
|
|
327
|
+
*
|
|
328
|
+
* **Common Causes:**
|
|
329
|
+
* - Missing required parameters (walletClient, seiRpcUrl, wsUrl)
|
|
330
|
+
* - Invalid URL formats
|
|
331
|
+
* - Unsupported network values
|
|
332
|
+
* - Wallet client chain mismatch
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```typescript
|
|
336
|
+
* // Missing required field
|
|
337
|
+
* throw new InvalidConfigError(
|
|
338
|
+
* "Wallet client is required",
|
|
339
|
+
* "walletClient"
|
|
340
|
+
* );
|
|
341
|
+
*
|
|
342
|
+
* // Invalid value
|
|
343
|
+
* throw new InvalidConfigError(
|
|
344
|
+
* "Invalid URL format",
|
|
345
|
+
* "seiRpcUrl",
|
|
346
|
+
* "not-a-url"
|
|
347
|
+
* );
|
|
348
|
+
*
|
|
349
|
+
* // With cause
|
|
350
|
+
* try {
|
|
351
|
+
* new URL(config.wsUrl);
|
|
352
|
+
* } catch (error) {
|
|
353
|
+
* throw new InvalidConfigError(
|
|
354
|
+
* "wsUrl must be a valid URL",
|
|
355
|
+
* "wsUrl",
|
|
356
|
+
* config.wsUrl,
|
|
357
|
+
* error
|
|
358
|
+
* );
|
|
359
|
+
* }
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
export class InvalidConfigError extends MonacoCoreError {
|
|
363
|
+
constructor(message, field, value, cause) {
|
|
364
|
+
const suggestion = field
|
|
365
|
+
? `Check the '${field}' configuration parameter. ${getSuggestionForConfigField(field)}`
|
|
366
|
+
: "Review your SDK configuration and ensure all required fields are provided correctly.";
|
|
367
|
+
super(message, { cause, suggestion, retryable: false });
|
|
368
|
+
this.code = "INVALID_CONFIG";
|
|
369
|
+
this.field = field;
|
|
370
|
+
this.value = value;
|
|
371
|
+
}
|
|
372
|
+
toJSON() {
|
|
373
|
+
// Sanitize value based on field name - if the field is sensitive, redact the value
|
|
374
|
+
let sanitizedValue;
|
|
375
|
+
if (this.field) {
|
|
376
|
+
const lowerField = this.field.toLowerCase();
|
|
377
|
+
const isSensitive = SENSITIVE_FIELDS.some((sensitive) => lowerField.includes(sensitive.toLowerCase()));
|
|
378
|
+
if (isSensitive) {
|
|
379
|
+
sanitizedValue = "[REDACTED]";
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
// Still sanitize the value in case it's an object with sensitive fields
|
|
383
|
+
sanitizedValue = sanitizeData(this.value);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
sanitizedValue = sanitizeData(this.value);
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
...super.toJSON(),
|
|
391
|
+
field: this.field,
|
|
392
|
+
value: sanitizedValue,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Get field-specific suggestions for common configuration parameters.
|
|
398
|
+
*
|
|
399
|
+
* Provides actionable guidance for fixing invalid configuration values.
|
|
400
|
+
* Used by InvalidConfigError to generate context-aware suggestions.
|
|
401
|
+
*
|
|
402
|
+
* **Supported Fields:**
|
|
403
|
+
* - `walletClient`: Wallet creation and account configuration
|
|
404
|
+
* - `seiRpcUrl`: RPC endpoint URLs for testnet/mainnet
|
|
405
|
+
* - `wsUrl`: WebSocket endpoint URLs
|
|
406
|
+
* - `network`: Valid network presets and custom URLs
|
|
407
|
+
* - `*` (default): Generic configuration documentation link
|
|
408
|
+
*
|
|
409
|
+
* @param field - Configuration field name (case-insensitive)
|
|
410
|
+
* @returns Specific suggestion string for the field
|
|
411
|
+
* @internal
|
|
412
|
+
*/
|
|
413
|
+
function getSuggestionForConfigField(field) {
|
|
414
|
+
switch (field.toLowerCase()) {
|
|
415
|
+
case "walletclient":
|
|
416
|
+
return "Ensure you're creating the wallet client with a valid account and chain configuration.";
|
|
417
|
+
case "seirpcurl":
|
|
418
|
+
return "Use 'https://evm-rpc-testnet.sei-apis.com' for testnet or 'https://evm-rpc.sei-apis.com' for mainnet.";
|
|
419
|
+
case "wsurl":
|
|
420
|
+
return "Use 'wss://development.apimonaco.xyz/ws' for testnet or 'wss://api.monaco.xyz/ws' for mainnet.";
|
|
421
|
+
case "network":
|
|
422
|
+
return "Valid networks are: 'mainnet', 'testnet', 'local', 'staging', or a custom API URL.";
|
|
423
|
+
default:
|
|
424
|
+
return "Refer to the SDK documentation for correct configuration format.";
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Error thrown when an operation is called in an invalid SDK state.
|
|
429
|
+
*
|
|
430
|
+
* Indicates that a method was called at the wrong time or when prerequisites
|
|
431
|
+
* weren't met. Includes state transition information when available.
|
|
432
|
+
*
|
|
433
|
+
* **Additional Properties:**
|
|
434
|
+
* - `currentState`: string | undefined - The current state of the SDK
|
|
435
|
+
* - `expectedState`: string | undefined - The state required for this operation
|
|
436
|
+
*
|
|
437
|
+
* **Common Causes:**
|
|
438
|
+
* - Calling authenticated methods before login
|
|
439
|
+
* - Calling methods after logout/disconnect
|
|
440
|
+
* - Operation sequence violations
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```typescript
|
|
444
|
+
* // With state information
|
|
445
|
+
* throw new InvalidStateError(
|
|
446
|
+
* "Cannot place orders while disconnected",
|
|
447
|
+
* "disconnected",
|
|
448
|
+
* "connected"
|
|
449
|
+
* );
|
|
450
|
+
* // Suggestion: "Current state is 'disconnected', Expected state is 'connected'. Ensure operations are performed in the correct order."
|
|
451
|
+
*
|
|
452
|
+
* // Without state information
|
|
453
|
+
* throw new InvalidStateError(
|
|
454
|
+
* "Prerequisites not met"
|
|
455
|
+
* );
|
|
456
|
+
* // Suggestion: "Check that prerequisites are met before calling this method."
|
|
457
|
+
* ```
|
|
458
|
+
*/
|
|
459
|
+
export class InvalidStateError extends MonacoCoreError {
|
|
460
|
+
constructor(message, currentState, expectedState, cause) {
|
|
461
|
+
const suggestion = expectedState
|
|
462
|
+
? `${currentState ? `Current state is '${currentState}', ` : ""}Expected state is '${expectedState}'. Ensure operations are performed in the correct order.`
|
|
463
|
+
: "Check that prerequisites are met before calling this method.";
|
|
464
|
+
super(message, { cause, suggestion, retryable: false });
|
|
465
|
+
this.code = "INVALID_STATE";
|
|
466
|
+
this.currentState = currentState;
|
|
467
|
+
this.expectedState = expectedState;
|
|
468
|
+
}
|
|
469
|
+
toJSON() {
|
|
470
|
+
return {
|
|
471
|
+
...super.toJSON(),
|
|
472
|
+
currentState: this.currentState,
|
|
473
|
+
expectedState: this.expectedState,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Error thrown when an API request fails.
|
|
479
|
+
*
|
|
480
|
+
* Represents failures in HTTP/API communication including network errors,
|
|
481
|
+
* server errors, validation failures, and rate limiting. Automatically
|
|
482
|
+
* determines retry-ability and provides context-aware recovery suggestions.
|
|
483
|
+
*
|
|
484
|
+
* **Additional Properties:**
|
|
485
|
+
* - `endpoint`: string | undefined - The API endpoint that failed
|
|
486
|
+
* - `statusCode`: number | undefined - HTTP status code (undefined for network errors)
|
|
487
|
+
* - `responseBody`: unknown - Response body from the API (sanitized in toJSON)
|
|
488
|
+
* - `requestBody`: unknown - Request body sent to the API (sanitized in toJSON)
|
|
489
|
+
* - `requestId`: string | undefined - Request ID from X-Request-ID header
|
|
490
|
+
* - `retryAfter`: number | undefined - Retry-After header value in seconds
|
|
491
|
+
*
|
|
492
|
+
* **Common Status Codes:**
|
|
493
|
+
* - `undefined`: Network error (connection failed, timeout, DNS error)
|
|
494
|
+
* - `400`: Bad request (validation failed, invalid parameters)
|
|
495
|
+
* - `401`: Unauthorized (missing or expired token)
|
|
496
|
+
* - `403`: Forbidden (insufficient permissions)
|
|
497
|
+
* - `404`: Not found (resource doesn't exist)
|
|
498
|
+
* - `429`: Rate limit exceeded
|
|
499
|
+
* - `500+`: Server error
|
|
500
|
+
*
|
|
501
|
+
* **Retryability:**
|
|
502
|
+
* - ✅ Retryable: Network errors, 429, 500+, 409
|
|
503
|
+
* - ❌ Not retryable: 400, 401, 403, 404, and most client errors
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```typescript
|
|
507
|
+
* // Network error (no response)
|
|
508
|
+
* throw new APIError("Network request failed", {
|
|
509
|
+
* endpoint: "/api/orders",
|
|
510
|
+
* cause: new Error("ECONNREFUSED")
|
|
511
|
+
* });
|
|
512
|
+
*
|
|
513
|
+
* // API validation error
|
|
514
|
+
* throw new APIError("Invalid order parameters", {
|
|
515
|
+
* endpoint: "/api/orders",
|
|
516
|
+
* statusCode: 400,
|
|
517
|
+
* responseBody: { error: "Price must be positive" },
|
|
518
|
+
* requestBody: { price: -10 }
|
|
519
|
+
* });
|
|
520
|
+
*
|
|
521
|
+
* // Rate limit with retry-after
|
|
522
|
+
* throw new APIError("Rate limit exceeded", {
|
|
523
|
+
* endpoint: "/api/orders",
|
|
524
|
+
* statusCode: 429,
|
|
525
|
+
* requestId: "req_abc123",
|
|
526
|
+
* retryAfter: 60
|
|
527
|
+
* });
|
|
528
|
+
*
|
|
529
|
+
* // Check if retryable
|
|
530
|
+
* try {
|
|
531
|
+
* await sdk.someOperation();
|
|
532
|
+
* } catch (error) {
|
|
533
|
+
* if (error instanceof APIError && error.retryable) {
|
|
534
|
+
* // Implement retry logic
|
|
535
|
+
* await delay(error.retryAfter || 5);
|
|
536
|
+
* await sdk.someOperation();
|
|
537
|
+
* }
|
|
538
|
+
* }
|
|
539
|
+
* ```
|
|
540
|
+
*/
|
|
541
|
+
export class APIError extends MonacoCoreError {
|
|
542
|
+
constructor(message, options) {
|
|
543
|
+
// Determine suggestion and retryability based on status code
|
|
544
|
+
const { suggestion, retryable } = getErrorSuggestion(options?.statusCode, message, options?.responseBody);
|
|
545
|
+
super(message, { cause: options?.cause, suggestion, retryable });
|
|
546
|
+
this.code = "API_ERROR";
|
|
547
|
+
this.endpoint = options?.endpoint;
|
|
548
|
+
this.statusCode = options?.statusCode;
|
|
549
|
+
this.responseBody = options?.responseBody;
|
|
550
|
+
this.requestBody = options?.requestBody;
|
|
551
|
+
this.requestId = options?.requestId;
|
|
552
|
+
this.retryAfter = options?.retryAfter;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Override toJSON to include API-specific fields with sanitization
|
|
556
|
+
*
|
|
557
|
+
* Sanitizes requestBody and responseBody to prevent sensitive data exposure
|
|
558
|
+
* when errors are logged to external monitoring services.
|
|
559
|
+
*/
|
|
560
|
+
toJSON() {
|
|
561
|
+
return {
|
|
562
|
+
...super.toJSON(),
|
|
563
|
+
endpoint: this.endpoint,
|
|
564
|
+
statusCode: this.statusCode,
|
|
565
|
+
responseBody: sanitizeData(this.responseBody),
|
|
566
|
+
requestBody: sanitizeData(this.requestBody),
|
|
567
|
+
requestId: this.requestId,
|
|
568
|
+
retryAfter: this.retryAfter,
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Generate helpful error suggestions and determine retryability based on HTTP status codes.
|
|
574
|
+
*
|
|
575
|
+
* Analyzes API errors to provide actionable recovery suggestions and indicate whether
|
|
576
|
+
* the operation can be safely retried. Used automatically by APIError constructor.
|
|
577
|
+
*
|
|
578
|
+
* **Status Code Precedence** (checked in this order):
|
|
579
|
+
* 1. No status code (network errors) → retryable
|
|
580
|
+
* 2. 401 Unauthorized → check for token expiration, not retryable
|
|
581
|
+
* 3. 403 Forbidden → permission issue, not retryable
|
|
582
|
+
* 4. 404 Not Found → resource missing, not retryable
|
|
583
|
+
* 5. 409 Conflict → resource conflict, retryable
|
|
584
|
+
* 6. 400 Bad Request → check for specific issues (balance, validation), not retryable
|
|
585
|
+
* 7. 429 Too Many Requests → rate limit, retryable with backoff
|
|
586
|
+
* 8. 500-599 Server Errors → retryable (explicit range check)
|
|
587
|
+
* 9. Default → not retryable
|
|
588
|
+
*
|
|
589
|
+
* **Examples:**
|
|
590
|
+
* ```typescript
|
|
591
|
+
* getErrorSuggestion(401, "Token expired")
|
|
592
|
+
* // → {
|
|
593
|
+
* // suggestion: "Access token has expired. Call sdk.refreshAuth()...",
|
|
594
|
+
* // retryable: false
|
|
595
|
+
* // }
|
|
596
|
+
*
|
|
597
|
+
* getErrorSuggestion(429, "Rate limit", { retry_after: 60 })
|
|
598
|
+
* // → {
|
|
599
|
+
* // suggestion: "Rate limit exceeded. Wait 60 seconds before retrying...",
|
|
600
|
+
* // retryable: true
|
|
601
|
+
* // }
|
|
602
|
+
*
|
|
603
|
+
* getErrorSuggestion(undefined, "Network failed")
|
|
604
|
+
* // → {
|
|
605
|
+
* // suggestion: "Network request failed. Check your internet connection...",
|
|
606
|
+
* // retryable: true
|
|
607
|
+
* // }
|
|
608
|
+
* ```
|
|
609
|
+
*
|
|
610
|
+
* @param statusCode - HTTP status code from the failed request (undefined for network errors)
|
|
611
|
+
* @param message - Error message from the API or network layer
|
|
612
|
+
* @param responseBody - Response body from the API (may contain retry_after, etc.)
|
|
613
|
+
* @returns Object with suggestion string and retryable boolean
|
|
614
|
+
* @internal
|
|
615
|
+
*/
|
|
616
|
+
function getErrorSuggestion(statusCode, message, responseBody) {
|
|
617
|
+
// Network/timeout errors - always retryable
|
|
618
|
+
if (!statusCode) {
|
|
619
|
+
return {
|
|
620
|
+
suggestion: "Network request failed. Check your internet connection and try again.",
|
|
621
|
+
retryable: true,
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
// Authentication errors (401 Unauthorized)
|
|
625
|
+
if (statusCode === StatusCodes.UNAUTHORIZED) {
|
|
626
|
+
if (message?.toLowerCase().includes("expired")) {
|
|
627
|
+
return {
|
|
628
|
+
suggestion: "Access token has expired. Call sdk.refreshAuth() to get a new token, or call sdk.login() to re-authenticate.",
|
|
629
|
+
retryable: false,
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
return {
|
|
633
|
+
suggestion: "Authentication required. Call sdk.login(clientId) to authenticate before making this request.",
|
|
634
|
+
retryable: false,
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
// Forbidden (403)
|
|
638
|
+
if (statusCode === StatusCodes.FORBIDDEN) {
|
|
639
|
+
return {
|
|
640
|
+
suggestion: "Access denied. Ensure your application has the required permissions and your client ID is valid.",
|
|
641
|
+
retryable: false,
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
// Not found (404)
|
|
645
|
+
if (statusCode === StatusCodes.NOT_FOUND) {
|
|
646
|
+
return {
|
|
647
|
+
suggestion: "Resource not found. Check that the ID or identifier is correct and the resource exists.",
|
|
648
|
+
retryable: false,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
// Conflict (409) - check BEFORE 500+ to avoid being shadowed
|
|
652
|
+
if (statusCode === StatusCodes.CONFLICT) {
|
|
653
|
+
return {
|
|
654
|
+
suggestion: "Resource conflict. The resource may have been modified. Refresh and try again.",
|
|
655
|
+
retryable: true,
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
// Validation errors (400 Bad Request)
|
|
659
|
+
if (statusCode === StatusCodes.BAD_REQUEST) {
|
|
660
|
+
if (message?.toLowerCase().includes("insufficient balance")) {
|
|
661
|
+
return {
|
|
662
|
+
suggestion: "Insufficient balance. Deposit more funds using sdk.vault.deposit() or reduce the order size.",
|
|
663
|
+
retryable: false,
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
if (message?.toLowerCase().includes("invalid")) {
|
|
667
|
+
return {
|
|
668
|
+
suggestion: "Invalid request parameters. Check the API documentation for correct parameter format and values.",
|
|
669
|
+
retryable: false,
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
return {
|
|
673
|
+
suggestion: "Bad request. Verify that all required parameters are provided and correctly formatted.",
|
|
674
|
+
retryable: false,
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
// Rate limiting (429 Too Many Requests)
|
|
678
|
+
if (statusCode === StatusCodes.TOO_MANY_REQUESTS) {
|
|
679
|
+
let retryText;
|
|
680
|
+
if (typeof responseBody === "object" && responseBody !== null && "retry_after" in responseBody && responseBody.retry_after) {
|
|
681
|
+
const retryAfterValue = responseBody.retry_after;
|
|
682
|
+
retryText = ` Wait ${String(retryAfterValue)} seconds before retrying.`;
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
retryText = " Wait a moment before retrying.";
|
|
686
|
+
}
|
|
687
|
+
return {
|
|
688
|
+
suggestion: `Rate limit exceeded.${retryText} Consider implementing exponential backoff for retries.`,
|
|
689
|
+
retryable: true,
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
// Server errors (500-599) - retryable
|
|
693
|
+
// Use explicit range check to avoid shadowing other status codes
|
|
694
|
+
if (statusCode >= StatusCodes.INTERNAL_SERVER_ERROR && statusCode < 600) {
|
|
695
|
+
return {
|
|
696
|
+
suggestion: "Server error occurred. This is likely a temporary issue. Try again in a few moments.",
|
|
697
|
+
retryable: true,
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
// Default - not retryable
|
|
701
|
+
return {
|
|
702
|
+
suggestion: undefined,
|
|
703
|
+
retryable: false,
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Error thrown when a smart contract interaction fails.
|
|
708
|
+
*
|
|
709
|
+
* Represents failures in blockchain contract interactions including transaction
|
|
710
|
+
* reverts, gas estimation failures, and contract execution errors. Includes
|
|
711
|
+
* revert reasons and transaction hashes when available for debugging.
|
|
712
|
+
*
|
|
713
|
+
* **Additional Properties:**
|
|
714
|
+
* - `revertReason`: string | undefined - The reason the contract reverted
|
|
715
|
+
* - `transactionHash`: string | undefined - Transaction hash (if transaction was submitted)
|
|
716
|
+
* - `contractAddress`: string | undefined - Address of the contract that failed
|
|
717
|
+
*
|
|
718
|
+
* **Common Causes:**
|
|
719
|
+
* - Contract revert (require/assert failed)
|
|
720
|
+
* - Gas estimation failure (transaction would fail)
|
|
721
|
+
* - Insufficient gas provided
|
|
722
|
+
* - Contract state restrictions (e.g., paused, unauthorized)
|
|
723
|
+
* - Transaction reverted after submission
|
|
724
|
+
*
|
|
725
|
+
* @example
|
|
726
|
+
* ```typescript
|
|
727
|
+
* // Contract revert during simulation
|
|
728
|
+
* throw new ContractError(
|
|
729
|
+
* "Insufficient balance for withdrawal",
|
|
730
|
+
* {
|
|
731
|
+
* revertReason: "Insufficient balance",
|
|
732
|
+
* contractAddress: "0x123...",
|
|
733
|
+
* }
|
|
734
|
+
* );
|
|
735
|
+
*
|
|
736
|
+
* // Transaction reverted on-chain
|
|
737
|
+
* throw new ContractError(
|
|
738
|
+
* "Transaction reverted",
|
|
739
|
+
* {
|
|
740
|
+
* transactionHash: "0xabc...",
|
|
741
|
+
* revertReason: "Slippage tolerance exceeded",
|
|
742
|
+
* contractAddress: "0x456...",
|
|
743
|
+
* }
|
|
744
|
+
* );
|
|
745
|
+
*
|
|
746
|
+
* // Gas estimation failure
|
|
747
|
+
* try {
|
|
748
|
+
* await contract.estimateGas.someMethod(...args);
|
|
749
|
+
* } catch (error) {
|
|
750
|
+
* throw new ContractError(
|
|
751
|
+
* "Gas estimation failed",
|
|
752
|
+
* {
|
|
753
|
+
* revertReason: error.reason,
|
|
754
|
+
* contractAddress: contract.address,
|
|
755
|
+
* cause: error,
|
|
756
|
+
* }
|
|
757
|
+
* );
|
|
758
|
+
* }
|
|
759
|
+
* ```
|
|
760
|
+
*/
|
|
761
|
+
export class ContractError extends MonacoCoreError {
|
|
762
|
+
constructor(message, options) {
|
|
763
|
+
const suggestion = getContractErrorSuggestion(options?.revertReason);
|
|
764
|
+
super(message, { cause: options?.cause, suggestion, retryable: false });
|
|
765
|
+
this.code = "CONTRACT_ERROR";
|
|
766
|
+
this.revertReason = options?.revertReason;
|
|
767
|
+
this.transactionHash = options?.transactionHash;
|
|
768
|
+
this.contractAddress = options?.contractAddress;
|
|
769
|
+
}
|
|
770
|
+
toJSON() {
|
|
771
|
+
return {
|
|
772
|
+
...super.toJSON(),
|
|
773
|
+
revertReason: this.revertReason,
|
|
774
|
+
transactionHash: this.transactionHash,
|
|
775
|
+
contractAddress: this.contractAddress,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Get suggestions for common contract errors
|
|
781
|
+
*/
|
|
782
|
+
function getContractErrorSuggestion(revertReason) {
|
|
783
|
+
if (!revertReason) {
|
|
784
|
+
return "Smart contract execution failed. Check transaction parameters and try again.";
|
|
785
|
+
}
|
|
786
|
+
const reason = revertReason.toLowerCase();
|
|
787
|
+
if (reason.includes("insufficient allowance")) {
|
|
788
|
+
return "Token allowance is insufficient. Call sdk.vault.approve() to increase the token allowance for the vault contract.";
|
|
789
|
+
}
|
|
790
|
+
if (reason.includes("insufficient balance")) {
|
|
791
|
+
return "Wallet balance is insufficient for this transaction. Ensure you have enough tokens and native currency for gas fees.";
|
|
792
|
+
}
|
|
793
|
+
if (reason.includes("nonce")) {
|
|
794
|
+
return "Transaction nonce error. This may be due to a pending transaction. Wait for pending transactions to complete or reset your account nonce.";
|
|
795
|
+
}
|
|
796
|
+
if (reason.includes("gas")) {
|
|
797
|
+
return "Transaction ran out of gas. Try increasing the gas limit for this transaction.";
|
|
798
|
+
}
|
|
799
|
+
return undefined;
|
|
800
|
+
}
|
|
801
|
+
//# sourceMappingURL=errors.js.map
|