sdk-triggerx 0.1.17 → 0.1.19

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.
@@ -9,6 +9,8 @@ const ethers_1 = require("ethers");
9
9
  exports.SAFE_ABI = [
10
10
  // module checks
11
11
  "function isModuleEnabled(address module) view returns (bool)",
12
+ // module management
13
+ "function enableModule(address module)",
12
14
  // EIP-712 domain separator for Safe
13
15
  "function domainSeparator() view returns (bytes32)",
14
16
  // Safe nonce
@@ -18,6 +20,8 @@ exports.SAFE_ABI = [
18
20
  // Owners and threshold, to validate single signer safes
19
21
  "function getOwners() view returns (address[])",
20
22
  "function getThreshold() view returns (uint256)",
23
+ // Add getTransactionHash for onchain hash calculation
24
+ "function getTransactionHash(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce) view returns (bytes32)"
21
25
  ];
22
26
  // Safe EIP-712 typehash for transactions
23
27
  exports.SAFE_TX_TYPEHASH = ethers_1.ethers.id("SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 _nonce)");
@@ -52,38 +56,54 @@ async function enableSafeModule(safeAddress, signer, moduleAddress) {
52
56
  const safeProxy = new ethers_1.ethers.Contract(safeAddress, exports.SAFE_ABI, provider);
53
57
  // If already enabled, exit early
54
58
  const already = await safeProxy.isModuleEnabled(moduleAddress);
55
- if (already)
59
+ if (already) {
60
+ console.log('Module is already enabled');
56
61
  return;
62
+ }
63
+ // First, let's try the direct approach for single-owner Safes
64
+ try {
65
+ console.log('Attempting direct enableModule call...');
66
+ const safeWithSigner = new ethers_1.ethers.Contract(safeAddress, exports.SAFE_ABI, signer);
67
+ const tx = await safeWithSigner.enableModule(moduleAddress);
68
+ await tx.wait();
69
+ console.log('Module enabled via direct call');
70
+ return;
71
+ }
72
+ catch (error) {
73
+ console.log('Direct call failed, trying execTransaction approach...');
74
+ }
75
+ // If direct call fails, use execTransaction with proper signature
57
76
  const safeNonce = await safeProxy.nonce();
58
77
  const iface = new ethers_1.ethers.Interface(exports.SAFE_ABI);
59
78
  const data = iface.encodeFunctionData('enableModule', [moduleAddress]);
60
79
  const to = safeAddress;
61
- const value = 0n;
80
+ const value = 0;
62
81
  const operation = 0; // CALL
63
- const safeTxGas = 0n;
64
- const baseGas = 0n;
65
- const gasPrice = 0n;
82
+ const safeTxGas = 0;
83
+ const baseGas = 0;
84
+ const gasPrice = 0;
66
85
  const gasToken = ethers_1.ethers.ZeroAddress;
67
86
  const refundReceiver = ethers_1.ethers.ZeroAddress;
68
- // Calculate Safe transaction hash per EIP-712
69
- const safeTxHash = ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode([
70
- 'bytes32', 'address', 'uint256', 'bytes32', 'uint8',
71
- 'uint256', 'uint256', 'uint256', 'address', 'address', 'uint256'
72
- ], [
73
- exports.SAFE_TX_TYPEHASH, to, value, ethers_1.ethers.keccak256(data), operation,
74
- safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, safeNonce
75
- ]));
76
- const domainSeparator = await safeProxy.domainSeparator();
77
- const txHash = ethers_1.ethers.keccak256(ethers_1.ethers.solidityPacked(['bytes1', 'bytes1', 'bytes32', 'bytes32'], ['0x19', '0x01', domainSeparator, safeTxHash]));
78
- const rawSignature = await signer.signMessage(ethers_1.ethers.getBytes(txHash));
79
- const sig = ethers_1.ethers.Signature.from(rawSignature);
80
- const adjustedV = sig.v + 4; // EthSign type
81
- const signature = ethers_1.ethers.concat([sig.r, sig.s, ethers_1.ethers.toBeHex(adjustedV, 1)]);
82
- const safeWithSigner = new ethers_1.ethers.Contract(safeAddress, exports.SAFE_ABI, signer);
83
- const tx = await safeWithSigner.execTransaction(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, signature);
87
+ // Use contract to compute tx hash to avoid mismatch
88
+ const safeTxHash = await safeProxy.getTransactionHash(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, safeNonce);
89
+ // Sign the transaction hash using the connected wallet (personal_sign)
90
+ // For Gnosis Safe, personal_sign signatures must have v adjusted by +4 to mark EthSign
91
+ const rawSignature = await signer.signMessage(ethers_1.ethers.getBytes(safeTxHash));
92
+ const sigObj = ethers_1.ethers.Signature.from(rawSignature);
93
+ const adjustedV = sigObj.v + 4;
94
+ const signature = ethers_1.ethers.concat([
95
+ sigObj.r,
96
+ sigObj.s,
97
+ ethers_1.ethers.toBeHex(adjustedV, 1),
98
+ ]);
99
+ // Execute the transaction through Safe's execTransaction
100
+ const safeProxyWithSigner = new ethers_1.ethers.Contract(safeAddress, exports.SAFE_ABI, signer);
101
+ const tx = await safeProxyWithSigner.execTransaction(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, signature);
84
102
  await tx.wait();
85
- const check = await safeProxy.isModuleEnabled(moduleAddress);
86
- if (!check) {
87
- throw new Error('Module verification failed');
103
+ // Verify module is enabled
104
+ const isNowEnabled = await safeProxy.isModuleEnabled(moduleAddress);
105
+ if (!isNowEnabled) {
106
+ throw new Error("Module verification failed");
88
107
  }
108
+ console.log('Module enabled successfully via execTransaction');
89
109
  }
package/dist/types.d.ts CHANGED
@@ -8,6 +8,21 @@ export interface ApiResponse<T> {
8
8
  data: T;
9
9
  error?: string;
10
10
  }
11
+ export type HttpStatusCode = 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511;
12
+ export type ApiErrorCode = 'BAD_REQUEST' | 'UNAUTHORIZED' | 'PAYMENT_REQUIRED' | 'FORBIDDEN' | 'NOT_FOUND' | 'METHOD_NOT_ALLOWED' | 'NOT_ACCEPTABLE' | 'PROXY_AUTHENTICATION_REQUIRED' | 'REQUEST_TIMEOUT' | 'CONFLICT' | 'GONE' | 'LENGTH_REQUIRED' | 'PRECONDITION_FAILED' | 'PAYLOAD_TOO_LARGE' | 'URI_TOO_LONG' | 'UNSUPPORTED_MEDIA_TYPE' | 'RANGE_NOT_SATISFIABLE' | 'EXPECTATION_FAILED' | 'IM_A_TEAPOT' | 'MISDIRECTED_REQUEST' | 'UNPROCESSABLE_ENTITY' | 'LOCKED' | 'FAILED_DEPENDENCY' | 'TOO_EARLY' | 'UPGRADE_REQUIRED' | 'PRECONDITION_REQUIRED' | 'TOO_MANY_REQUESTS' | 'REQUEST_HEADER_FIELDS_TOO_LARGE' | 'UNAVAILABLE_FOR_LEGAL_REASONS' | 'INTERNAL_SERVER_ERROR' | 'NOT_IMPLEMENTED' | 'BAD_GATEWAY' | 'SERVICE_UNAVAILABLE' | 'GATEWAY_TIMEOUT' | 'HTTP_VERSION_NOT_SUPPORTED' | 'VARIANT_ALSO_NEGOTIATES' | 'INSUFFICIENT_STORAGE' | 'LOOP_DETECTED' | 'NOT_EXTENDED' | 'NETWORK_AUTHENTICATION_REQUIRED' | 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'AUTHENTICATION_ERROR' | 'CONTRACT_ERROR' | 'BALANCE_ERROR' | 'CONFIGURATION_ERROR' | 'RATE_LIMIT_EXCEEDED' | 'INSUFFICIENT_FUNDS' | 'INVALID_SIGNATURE' | 'TRANSACTION_FAILED' | 'CONTRACT_REVERT' | 'GAS_ESTIMATION_FAILED' | 'NONCE_TOO_LOW' | 'NONCE_TOO_HIGH' | 'REPLACEMENT_UNDERPRICED' | 'UNKNOWN_ERROR';
13
+ export interface ErrorResponse {
14
+ success: false;
15
+ error: string;
16
+ errorCode: ApiErrorCode;
17
+ httpStatusCode?: HttpStatusCode;
18
+ errorType: 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'AUTHENTICATION_ERROR' | 'CONTRACT_ERROR' | 'API_ERROR' | 'BALANCE_ERROR' | 'CONFIGURATION_ERROR' | 'UNKNOWN_ERROR';
19
+ details?: any;
20
+ }
21
+ export interface SuccessResponse<T> {
22
+ success: true;
23
+ data: T;
24
+ }
25
+ export type ApiResult<T> = SuccessResponse<T> | ErrorResponse;
11
26
  export declare enum JobType {
12
27
  Time = "time",
13
28
  Event = "event",
@@ -37,15 +52,19 @@ export interface TimeBasedJobInput {
37
52
  specificSchedule?: string;
38
53
  timezone: string;
39
54
  chainId: string;
40
- targetContractAddress: string;
41
- targetFunction: string;
42
- abi: string;
55
+ targetContractAddress?: string;
56
+ targetFunction?: string;
57
+ abi?: string;
43
58
  isImua?: boolean;
44
59
  arguments?: string[];
45
60
  dynamicArgumentsScriptUrl?: string;
46
61
  autotopupTG?: boolean;
47
62
  walletMode?: WalletMode;
48
- safeAddress?: string;
63
+ /**
64
+ * The Safe address to use when walletMode is 'safe'.
65
+ * Required if walletMode is 'safe'.
66
+ */
67
+ safeAddress: string;
49
68
  }
50
69
  export interface EventBasedJobInput {
51
70
  jobTitle: string;
@@ -56,15 +75,19 @@ export interface EventBasedJobInput {
56
75
  timezone: string;
57
76
  recurring?: boolean;
58
77
  chainId: string;
59
- targetContractAddress: string;
60
- targetFunction: string;
61
- abi: string;
78
+ targetContractAddress?: string;
79
+ targetFunction?: string;
80
+ abi?: string;
62
81
  isImua?: boolean;
63
82
  arguments?: string[];
64
83
  dynamicArgumentsScriptUrl?: string;
65
84
  autotopupTG?: boolean;
66
85
  walletMode?: WalletMode;
67
- safeAddress?: string;
86
+ /**
87
+ * The Safe address to use when walletMode is 'safe'.
88
+ * Required if walletMode is 'safe'.
89
+ */
90
+ safeAddress: string;
68
91
  }
69
92
  export interface ConditionBasedJobInput {
70
93
  jobTitle: string;
@@ -77,15 +100,19 @@ export interface ConditionBasedJobInput {
77
100
  timezone: string;
78
101
  recurring?: boolean;
79
102
  chainId: string;
80
- targetContractAddress: string;
81
- targetFunction: string;
82
- abi: string;
103
+ targetContractAddress?: string;
104
+ targetFunction?: string;
105
+ abi?: string;
83
106
  isImua?: boolean;
84
107
  arguments?: string[];
85
108
  dynamicArgumentsScriptUrl?: string;
86
109
  autotopupTG?: boolean;
87
110
  walletMode?: WalletMode;
88
- safeAddress?: string;
111
+ /**
112
+ * The Safe address to use when walletMode is 'safe'.
113
+ * Required if walletMode is 'safe'.
114
+ */
115
+ safeAddress: string;
89
116
  }
90
117
  export interface CreateJobData {
91
118
  job_id: string;
@@ -125,6 +152,10 @@ export interface JobResponse {
125
152
  success: boolean;
126
153
  data?: any;
127
154
  error?: string;
155
+ errorCode?: ApiErrorCode;
156
+ httpStatusCode?: HttpStatusCode;
157
+ errorType?: 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'AUTHENTICATION_ERROR' | 'CONTRACT_ERROR' | 'API_ERROR' | 'BALANCE_ERROR' | 'CONFIGURATION_ERROR' | 'UNKNOWN_ERROR';
158
+ details?: any;
128
159
  }
129
160
  export interface JobDataAPI {
130
161
  job_id: string;
@@ -216,6 +247,10 @@ export interface ConditionJobData {
216
247
  export interface JobResponseUser {
217
248
  success: boolean;
218
249
  error?: string;
250
+ errorCode?: ApiErrorCode;
251
+ httpStatusCode?: HttpStatusCode;
252
+ errorType?: 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'AUTHENTICATION_ERROR' | 'CONTRACT_ERROR' | 'API_ERROR' | 'BALANCE_ERROR' | 'CONFIGURATION_ERROR' | 'UNKNOWN_ERROR';
253
+ details?: any;
219
254
  jobs?: JobResponseAPI;
220
255
  }
221
256
  export interface JobResponseAPI {
@@ -1,8 +1,43 @@
1
+ import { ApiErrorCode, HttpStatusCode } from '../types';
1
2
  export declare class TriggerXError extends Error {
2
- constructor(message: string);
3
+ readonly errorCode: ApiErrorCode;
4
+ readonly httpStatusCode?: HttpStatusCode;
5
+ readonly errorType: 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'AUTHENTICATION_ERROR' | 'CONTRACT_ERROR' | 'API_ERROR' | 'BALANCE_ERROR' | 'CONFIGURATION_ERROR' | 'UNKNOWN_ERROR';
6
+ readonly details?: any;
7
+ constructor(message: string, errorCode: ApiErrorCode, errorType: 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'AUTHENTICATION_ERROR' | 'CONTRACT_ERROR' | 'API_ERROR' | 'BALANCE_ERROR' | 'CONFIGURATION_ERROR' | 'UNKNOWN_ERROR', details?: any, httpStatusCode?: HttpStatusCode);
3
8
  }
9
+ export declare const HTTP_STATUS_TO_ERROR_CODE: Record<HttpStatusCode, ApiErrorCode>;
10
+ export declare const ERROR_PATTERN_TO_CODE: Record<string, ApiErrorCode>;
4
11
  export declare function wrapError(error: unknown): TriggerXError;
5
- export declare class ValidationError extends Error {
6
- field: string;
7
- constructor(field: string, message: string);
12
+ export declare function extractHttpStatusCode(error: any): HttpStatusCode | undefined;
13
+ export declare function determineErrorCode(error: any, httpStatusCode?: HttpStatusCode): ApiErrorCode;
14
+ export declare class ValidationError extends TriggerXError {
15
+ readonly field: string;
16
+ constructor(field: string, message: string, details?: any, httpStatusCode?: HttpStatusCode);
8
17
  }
18
+ export declare class NetworkError extends TriggerXError {
19
+ constructor(message: string, details?: any, httpStatusCode?: HttpStatusCode);
20
+ }
21
+ export declare class AuthenticationError extends TriggerXError {
22
+ constructor(message: string, details?: any, httpStatusCode?: HttpStatusCode);
23
+ }
24
+ export declare class ContractError extends TriggerXError {
25
+ constructor(message: string, details?: any, httpStatusCode?: HttpStatusCode);
26
+ }
27
+ export declare class ApiError extends TriggerXError {
28
+ constructor(message: string, details?: any, httpStatusCode?: HttpStatusCode);
29
+ }
30
+ export declare class BalanceError extends TriggerXError {
31
+ constructor(message: string, details?: any, httpStatusCode?: HttpStatusCode);
32
+ }
33
+ export declare class ConfigurationError extends TriggerXError {
34
+ constructor(message: string, details?: any, httpStatusCode?: HttpStatusCode);
35
+ }
36
+ export declare function createErrorResponse(error: TriggerXError | Error | unknown, fallbackMessage?: string): {
37
+ success: false;
38
+ error: string;
39
+ errorCode: ApiErrorCode;
40
+ httpStatusCode?: HttpStatusCode;
41
+ errorType: 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'AUTHENTICATION_ERROR' | 'CONTRACT_ERROR' | 'API_ERROR' | 'BALANCE_ERROR' | 'CONFIGURATION_ERROR' | 'UNKNOWN_ERROR';
42
+ details?: any;
43
+ };
@@ -1,25 +1,240 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ValidationError = exports.TriggerXError = void 0;
3
+ exports.ConfigurationError = exports.BalanceError = exports.ApiError = exports.ContractError = exports.AuthenticationError = exports.NetworkError = exports.ValidationError = exports.ERROR_PATTERN_TO_CODE = exports.HTTP_STATUS_TO_ERROR_CODE = exports.TriggerXError = void 0;
4
4
  exports.wrapError = wrapError;
5
+ exports.extractHttpStatusCode = extractHttpStatusCode;
6
+ exports.determineErrorCode = determineErrorCode;
7
+ exports.createErrorResponse = createErrorResponse;
5
8
  class TriggerXError extends Error {
6
- constructor(message) {
9
+ constructor(message, errorCode, errorType, details, httpStatusCode) {
7
10
  super(message);
8
11
  this.name = 'TriggerXError';
12
+ this.errorCode = errorCode;
13
+ this.errorType = errorType;
14
+ this.details = details;
15
+ this.httpStatusCode = httpStatusCode;
9
16
  }
10
17
  }
11
18
  exports.TriggerXError = TriggerXError;
19
+ // HTTP Status Code to Error Code Mapping
20
+ exports.HTTP_STATUS_TO_ERROR_CODE = {
21
+ // 4xx Client Errors
22
+ 400: 'BAD_REQUEST',
23
+ 401: 'UNAUTHORIZED',
24
+ 402: 'PAYMENT_REQUIRED',
25
+ 403: 'FORBIDDEN',
26
+ 404: 'NOT_FOUND',
27
+ 405: 'METHOD_NOT_ALLOWED',
28
+ 406: 'NOT_ACCEPTABLE',
29
+ 407: 'PROXY_AUTHENTICATION_REQUIRED',
30
+ 408: 'REQUEST_TIMEOUT',
31
+ 409: 'CONFLICT',
32
+ 410: 'GONE',
33
+ 411: 'LENGTH_REQUIRED',
34
+ 412: 'PRECONDITION_FAILED',
35
+ 413: 'PAYLOAD_TOO_LARGE',
36
+ 414: 'URI_TOO_LONG',
37
+ 415: 'UNSUPPORTED_MEDIA_TYPE',
38
+ 416: 'RANGE_NOT_SATISFIABLE',
39
+ 417: 'EXPECTATION_FAILED',
40
+ 418: 'IM_A_TEAPOT',
41
+ 421: 'MISDIRECTED_REQUEST',
42
+ 422: 'UNPROCESSABLE_ENTITY',
43
+ 423: 'LOCKED',
44
+ 424: 'FAILED_DEPENDENCY',
45
+ 425: 'TOO_EARLY',
46
+ 426: 'UPGRADE_REQUIRED',
47
+ 428: 'PRECONDITION_REQUIRED',
48
+ 429: 'TOO_MANY_REQUESTS',
49
+ 431: 'REQUEST_HEADER_FIELDS_TOO_LARGE',
50
+ 451: 'UNAVAILABLE_FOR_LEGAL_REASONS',
51
+ // 5xx Server Errors
52
+ 500: 'INTERNAL_SERVER_ERROR',
53
+ 501: 'NOT_IMPLEMENTED',
54
+ 502: 'BAD_GATEWAY',
55
+ 503: 'SERVICE_UNAVAILABLE',
56
+ 504: 'GATEWAY_TIMEOUT',
57
+ 505: 'HTTP_VERSION_NOT_SUPPORTED',
58
+ 506: 'VARIANT_ALSO_NEGOTIATES',
59
+ 507: 'INSUFFICIENT_STORAGE',
60
+ 508: 'LOOP_DETECTED',
61
+ 510: 'NOT_EXTENDED',
62
+ 511: 'NETWORK_AUTHENTICATION_REQUIRED'
63
+ };
64
+ // Error message patterns to error code mapping
65
+ exports.ERROR_PATTERN_TO_CODE = {
66
+ 'network': 'NETWORK_ERROR',
67
+ 'timeout': 'REQUEST_TIMEOUT',
68
+ 'connection': 'NETWORK_ERROR',
69
+ 'unauthorized': 'UNAUTHORIZED',
70
+ 'forbidden': 'FORBIDDEN',
71
+ 'not found': 'NOT_FOUND',
72
+ 'bad request': 'BAD_REQUEST',
73
+ 'validation': 'VALIDATION_ERROR',
74
+ 'invalid': 'VALIDATION_ERROR',
75
+ 'missing': 'VALIDATION_ERROR',
76
+ 'required': 'VALIDATION_ERROR',
77
+ 'insufficient': 'INSUFFICIENT_FUNDS',
78
+ 'balance': 'BALANCE_ERROR',
79
+ 'contract': 'CONTRACT_ERROR',
80
+ 'transaction': 'TRANSACTION_FAILED',
81
+ 'gas': 'GAS_ESTIMATION_FAILED',
82
+ 'nonce': 'NONCE_TOO_LOW',
83
+ 'revert': 'CONTRACT_REVERT',
84
+ 'rate limit': 'RATE_LIMIT_EXCEEDED',
85
+ 'too many': 'TOO_MANY_REQUESTS',
86
+ 'server error': 'INTERNAL_SERVER_ERROR',
87
+ 'service unavailable': 'SERVICE_UNAVAILABLE',
88
+ 'bad gateway': 'BAD_GATEWAY',
89
+ 'gateway timeout': 'GATEWAY_TIMEOUT'
90
+ };
12
91
  function wrapError(error) {
92
+ if (error instanceof TriggerXError) {
93
+ return error;
94
+ }
13
95
  if (error instanceof Error) {
14
- return new TriggerXError(error.message);
96
+ return new TriggerXError(error.message, 'UNKNOWN_ERROR', 'UNKNOWN_ERROR');
15
97
  }
16
- return new TriggerXError('Unknown error');
98
+ return new TriggerXError('Unknown error', 'UNKNOWN_ERROR', 'UNKNOWN_ERROR');
17
99
  }
18
- class ValidationError extends Error {
19
- constructor(field, message) {
20
- super(message);
100
+ // Helper function to extract HTTP status code from error
101
+ function extractHttpStatusCode(error) {
102
+ if (error?.response?.status) {
103
+ return error.response.status;
104
+ }
105
+ if (error?.status) {
106
+ return error.status;
107
+ }
108
+ if (error?.code && typeof error.code === 'number') {
109
+ return error.code;
110
+ }
111
+ return undefined;
112
+ }
113
+ // Helper function to determine error code from error message and status
114
+ function determineErrorCode(error, httpStatusCode) {
115
+ // First check if we have an HTTP status code
116
+ if (httpStatusCode && exports.HTTP_STATUS_TO_ERROR_CODE[httpStatusCode]) {
117
+ return exports.HTTP_STATUS_TO_ERROR_CODE[httpStatusCode];
118
+ }
119
+ // Extract status code from error if not provided
120
+ const statusCode = httpStatusCode || extractHttpStatusCode(error);
121
+ if (statusCode && exports.HTTP_STATUS_TO_ERROR_CODE[statusCode]) {
122
+ return exports.HTTP_STATUS_TO_ERROR_CODE[statusCode];
123
+ }
124
+ // Check error message patterns
125
+ const message = error?.message?.toLowerCase() || '';
126
+ for (const [pattern, code] of Object.entries(exports.ERROR_PATTERN_TO_CODE)) {
127
+ if (message.includes(pattern)) {
128
+ return code;
129
+ }
130
+ }
131
+ return 'UNKNOWN_ERROR';
132
+ }
133
+ class ValidationError extends TriggerXError {
134
+ constructor(field, message, details, httpStatusCode) {
135
+ super(message, 'VALIDATION_ERROR', 'VALIDATION_ERROR', details, httpStatusCode);
21
136
  this.name = 'ValidationError';
22
137
  this.field = field;
23
138
  }
24
139
  }
25
140
  exports.ValidationError = ValidationError;
141
+ class NetworkError extends TriggerXError {
142
+ constructor(message, details, httpStatusCode) {
143
+ super(message, 'NETWORK_ERROR', 'NETWORK_ERROR', details, httpStatusCode);
144
+ this.name = 'NetworkError';
145
+ }
146
+ }
147
+ exports.NetworkError = NetworkError;
148
+ class AuthenticationError extends TriggerXError {
149
+ constructor(message, details, httpStatusCode) {
150
+ super(message, 'AUTHENTICATION_ERROR', 'AUTHENTICATION_ERROR', details, httpStatusCode);
151
+ this.name = 'AuthenticationError';
152
+ }
153
+ }
154
+ exports.AuthenticationError = AuthenticationError;
155
+ class ContractError extends TriggerXError {
156
+ constructor(message, details, httpStatusCode) {
157
+ super(message, 'CONTRACT_ERROR', 'CONTRACT_ERROR', details, httpStatusCode);
158
+ this.name = 'ContractError';
159
+ }
160
+ }
161
+ exports.ContractError = ContractError;
162
+ class ApiError extends TriggerXError {
163
+ constructor(message, details, httpStatusCode) {
164
+ super(message, 'INTERNAL_SERVER_ERROR', 'API_ERROR', details, httpStatusCode);
165
+ this.name = 'ApiError';
166
+ }
167
+ }
168
+ exports.ApiError = ApiError;
169
+ class BalanceError extends TriggerXError {
170
+ constructor(message, details, httpStatusCode) {
171
+ super(message, 'BALANCE_ERROR', 'BALANCE_ERROR', details, httpStatusCode);
172
+ this.name = 'BalanceError';
173
+ }
174
+ }
175
+ exports.BalanceError = BalanceError;
176
+ class ConfigurationError extends TriggerXError {
177
+ constructor(message, details, httpStatusCode) {
178
+ super(message, 'CONFIGURATION_ERROR', 'CONFIGURATION_ERROR', details, httpStatusCode);
179
+ this.name = 'ConfigurationError';
180
+ }
181
+ }
182
+ exports.ConfigurationError = ConfigurationError;
183
+ // Helper function to create error response
184
+ function createErrorResponse(error, fallbackMessage = 'An unexpected error occurred') {
185
+ if (error instanceof TriggerXError) {
186
+ return {
187
+ success: false,
188
+ error: error.message,
189
+ errorCode: error.errorCode,
190
+ httpStatusCode: error.httpStatusCode,
191
+ errorType: error.errorType,
192
+ details: error.details
193
+ };
194
+ }
195
+ if (error instanceof Error) {
196
+ const httpStatusCode = extractHttpStatusCode(error);
197
+ const errorCode = determineErrorCode(error, httpStatusCode);
198
+ const errorType = getErrorTypeFromCode(errorCode);
199
+ return {
200
+ success: false,
201
+ error: error.message,
202
+ errorCode,
203
+ httpStatusCode,
204
+ errorType,
205
+ details: { originalError: error.name }
206
+ };
207
+ }
208
+ return {
209
+ success: false,
210
+ error: fallbackMessage,
211
+ errorCode: 'UNKNOWN_ERROR',
212
+ errorType: 'UNKNOWN_ERROR',
213
+ details: { originalError: String(error) }
214
+ };
215
+ }
216
+ // Helper function to determine error type from error code
217
+ function getErrorTypeFromCode(errorCode) {
218
+ if (errorCode === 'VALIDATION_ERROR' || errorCode === 'BAD_REQUEST' || errorCode === 'UNPROCESSABLE_ENTITY') {
219
+ return 'VALIDATION_ERROR';
220
+ }
221
+ if (errorCode === 'NETWORK_ERROR' || errorCode === 'REQUEST_TIMEOUT' || errorCode === 'SERVICE_UNAVAILABLE' || errorCode === 'BAD_GATEWAY' || errorCode === 'GATEWAY_TIMEOUT') {
222
+ return 'NETWORK_ERROR';
223
+ }
224
+ if (errorCode === 'AUTHENTICATION_ERROR' || errorCode === 'UNAUTHORIZED' || errorCode === 'FORBIDDEN' || errorCode === 'PROXY_AUTHENTICATION_REQUIRED') {
225
+ return 'AUTHENTICATION_ERROR';
226
+ }
227
+ if (errorCode === 'CONTRACT_ERROR' || errorCode === 'TRANSACTION_FAILED' || errorCode === 'CONTRACT_REVERT' || errorCode === 'GAS_ESTIMATION_FAILED' || errorCode === 'NONCE_TOO_LOW' || errorCode === 'NONCE_TOO_HIGH' || errorCode === 'REPLACEMENT_UNDERPRICED') {
228
+ return 'CONTRACT_ERROR';
229
+ }
230
+ if (errorCode === 'BALANCE_ERROR' || errorCode === 'INSUFFICIENT_FUNDS') {
231
+ return 'BALANCE_ERROR';
232
+ }
233
+ if (errorCode === 'CONFIGURATION_ERROR') {
234
+ return 'CONFIGURATION_ERROR';
235
+ }
236
+ if (errorCode.includes('API') || errorCode === 'INTERNAL_SERVER_ERROR' || errorCode === 'NOT_IMPLEMENTED' || errorCode === 'NOT_FOUND' || errorCode === 'METHOD_NOT_ALLOWED' || errorCode === 'CONFLICT' || errorCode === 'TOO_MANY_REQUESTS' || errorCode === 'RATE_LIMIT_EXCEEDED') {
237
+ return 'API_ERROR';
238
+ }
239
+ return 'UNKNOWN_ERROR';
240
+ }
@@ -103,7 +103,9 @@ function validateTimeBasedJobInput(input, argType) {
103
103
  else {
104
104
  throw new errors_1.ValidationError('scheduleType', 'scheduleType must be one of interval | cron | specific.');
105
105
  }
106
- validateContractBasics(input.targetContractAddress, input.abi, input.targetFunction, 'contract');
106
+ if (input.walletMode !== 'safe') {
107
+ validateContractBasics(input.targetContractAddress, input.abi, input.targetFunction, 'contract');
108
+ }
107
109
  // Arg type checks
108
110
  const isDynamic = argType === 'dynamic' || argType === 2;
109
111
  if (isDynamic) {
@@ -112,7 +114,9 @@ function validateTimeBasedJobInput(input, argType) {
112
114
  }
113
115
  }
114
116
  else {
115
- validateStaticArguments(input.abi, input.targetFunction, input.arguments, 'contract');
117
+ if (input.walletMode !== 'safe') {
118
+ validateStaticArguments(input.abi, input.targetFunction, input.arguments, 'contract');
119
+ }
116
120
  }
117
121
  }
118
122
  function validateEventBasedJobInput(input, argType) {
@@ -132,7 +136,9 @@ function validateEventBasedJobInput(input, argType) {
132
136
  throw new errors_1.ValidationError('triggerChainId', 'Trigger chain ID is required.');
133
137
  }
134
138
  validateContractBasics(input.triggerContractAddress, input.abi, input.triggerEvent, 'eventContract');
135
- validateContractBasics(input.targetContractAddress, input.abi, input.targetFunction, 'contract');
139
+ if (input.walletMode !== 'safe') {
140
+ validateContractBasics(input.targetContractAddress, input.abi, input.targetFunction, 'contract');
141
+ }
136
142
  const isDynamic = argType === 'dynamic' || argType === 2;
137
143
  if (isDynamic) {
138
144
  if (!isNonEmptyString(input.dynamicArgumentsScriptUrl) || !isValidUrl(input.dynamicArgumentsScriptUrl)) {
@@ -140,7 +146,9 @@ function validateEventBasedJobInput(input, argType) {
140
146
  }
141
147
  }
142
148
  else {
143
- validateStaticArguments(input.abi, input.targetFunction, input.arguments, 'contract');
149
+ if (input.walletMode !== 'safe') {
150
+ validateStaticArguments(input.abi, input.targetFunction, input.arguments, 'contract');
151
+ }
144
152
  }
145
153
  }
146
154
  function validateConditionBasedJobInput(input, argType) {
@@ -176,7 +184,9 @@ function validateConditionBasedJobInput(input, argType) {
176
184
  throw new errors_1.ValidationError('contractLimits', 'Value is required.');
177
185
  }
178
186
  }
179
- validateContractBasics(input.targetContractAddress, input.abi, input.targetFunction, 'contract');
187
+ if (input.walletMode !== 'safe') {
188
+ validateContractBasics(input.targetContractAddress, input.abi, input.targetFunction, 'contract');
189
+ }
180
190
  const isDynamic = argType === 'dynamic' || argType === 2;
181
191
  if (isDynamic) {
182
192
  if (!isNonEmptyString(input.dynamicArgumentsScriptUrl) || !isValidUrl(input.dynamicArgumentsScriptUrl)) {
@@ -184,7 +194,9 @@ function validateConditionBasedJobInput(input, argType) {
184
194
  }
185
195
  }
186
196
  else {
187
- validateStaticArguments(input.abi, input.targetFunction, input.arguments, 'contract');
197
+ if (input.walletMode !== 'safe') {
198
+ validateStaticArguments(input.abi, input.targetFunction, input.arguments, 'contract');
199
+ }
188
200
  }
189
201
  }
190
202
  function validateJobInput(jobInput, argType) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdk-triggerx",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "SDK for interacting with the TriggerX backend and smart contracts.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,8 +38,8 @@
38
38
  "@typescript-eslint/parser": "^8.38.0",
39
39
  "dotenv": "^17.2.1",
40
40
  "eslint": "^9.32.0",
41
- "jest": "^30.0.5",
42
- "ts-jest": "^29.4.0",
41
+ "jest": "^30.2.0",
42
+ "ts-jest": "^29.4.5",
43
43
  "typescript": "^5.8.3"
44
44
  }
45
45
  }