@anuragchvn-blip/mandatekit
Version:
Production-ready Web3 autopay SDK for crypto-based recurring payments using EIP-712 mandates
191 lines • 6.83 kB
JavaScript
/**
* Custom error classes for MandateKit SDK
* Provides descriptive, actionable error messages for common failure scenarios
* @module errors
*/
/**
* Base error class for all MandateKit errors
*/
export class MandateKitError extends Error {
constructor(message, code, details) {
super(message);
this.name = 'MandateKitError';
this.code = code;
this.details = details;
// Maintains proper stack trace for where error was thrown
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
}
}
}
/**
* Thrown when a signature is invalid or cannot be verified
*/
export class InvalidSignatureError extends MandateKitError {
constructor(message = 'Invalid signature: signature verification failed', details) {
super(message, 'INVALID_SIGNATURE', details);
this.name = 'InvalidSignatureError';
}
}
/**
* Thrown when a mandate has expired based on validBefore timestamp
*/
export class ExpiredMandateError extends MandateKitError {
constructor(validBefore, currentTime = Math.floor(Date.now() / 1000), details) {
const message = `Mandate expired: valid until ${new Date(validBefore * 1000).toISOString()}, current time is ${new Date(currentTime * 1000).toISOString()}`;
super(message, 'MANDATE_EXPIRED', { validBefore, currentTime, ...details });
this.name = 'ExpiredMandateError';
}
}
/**
* Thrown when attempting to use a mandate before its validAfter timestamp
*/
export class MandateNotYetValidError extends MandateKitError {
constructor(validAfter, currentTime = Math.floor(Date.now() / 1000), details) {
const message = `Mandate not yet valid: valid after ${new Date(validAfter * 1000).toISOString()}, current time is ${new Date(currentTime * 1000).toISOString()}`;
super(message, 'MANDATE_NOT_YET_VALID', { validAfter, currentTime, ...details });
this.name = 'MandateNotYetValidError';
}
}
/**
* Thrown when cadence rules are violated (e.g., executing too frequently)
*/
export class CadenceViolationError extends MandateKitError {
constructor(message, nextAllowedExecution, details) {
super(message, 'CADENCE_VIOLATION', { nextAllowedExecution, ...details });
this.name = 'CadenceViolationError';
}
}
/**
* Thrown when a nonce has already been used (replay protection)
*/
export class NonceAlreadyUsedError extends MandateKitError {
constructor(nonce, address, details) {
const message = `Nonce ${nonce.toString()} has already been used by address ${address}. Use a fresh nonce to prevent replay attacks.`;
super(message, 'NONCE_ALREADY_USED', { nonce: nonce.toString(), address, ...details });
this.name = 'NonceAlreadyUsedError';
}
}
/**
* Thrown when maximum payment count has been reached
*/
export class MaxPaymentsReachedError extends MandateKitError {
constructor(maxPayments, currentCount, details) {
const message = `Maximum payment count reached: ${currentCount} of ${maxPayments} payments have been executed`;
super(message, 'MAX_PAYMENTS_REACHED', { maxPayments, currentCount, ...details });
this.name = 'MaxPaymentsReachedError';
}
}
/**
* Thrown when mandate validation fails
*/
export class ValidationError extends MandateKitError {
constructor(message, field, details) {
super(`Validation error${field ? ` for field '${field}'` : ''}: ${message}`, 'VALIDATION_ERROR', { field, ...details });
this.name = 'ValidationError';
}
}
/**
* Thrown when a contract interaction fails
*/
export class ContractError extends MandateKitError {
constructor(message, contractAddress, details) {
super(`Contract error${contractAddress ? ` at ${contractAddress}` : ''}: ${message}`, 'CONTRACT_ERROR', { contractAddress, ...details });
this.name = 'ContractError';
}
}
/**
* Thrown when insufficient token balance or allowance
*/
export class InsufficientBalanceError extends MandateKitError {
constructor(required, available, tokenAddress, details) {
const message = `Insufficient balance: required ${required.toString()}, available ${available.toString()} for token ${tokenAddress}`;
super(message, 'INSUFFICIENT_BALANCE', {
required: required.toString(),
available: available.toString(),
tokenAddress,
...details,
});
this.name = 'InsufficientBalanceError';
}
}
/**
* Thrown when there's an issue with the relayer
*/
export class RelayerError extends MandateKitError {
constructor(message, details) {
super(`Relayer error: ${message}`, 'RELAYER_ERROR', details);
this.name = 'RelayerError';
}
}
/**
* Thrown when network or RPC issues occur
*/
export class NetworkError extends MandateKitError {
constructor(message, chainId, details) {
super(`Network error${chainId ? ` on chain ${chainId}` : ''}: ${message}`, 'NETWORK_ERROR', {
chainId,
...details,
});
this.name = 'NetworkError';
}
}
/**
* Thrown when trying to execute a payment too early
*/
export class ExecutionTooEarlyError extends MandateKitError {
constructor(nextExecutionTime, currentTime = Math.floor(Date.now() / 1000), details) {
const waitSeconds = nextExecutionTime - currentTime;
const message = `Execution too early: next payment scheduled for ${new Date(nextExecutionTime * 1000).toISOString()} (in ${waitSeconds} seconds)`;
super(message, 'EXECUTION_TOO_EARLY', {
nextExecutionTime,
currentTime,
waitSeconds,
...details,
});
this.name = 'ExecutionTooEarlyError';
}
}
/**
* Helper function to check if an error is a MandateKit error
*/
export function isMandateKitError(error) {
return error instanceof MandateKitError;
}
/**
* Helper function to get error code from any error
*/
export function getErrorCode(error) {
if (isMandateKitError(error)) {
return error.code;
}
if (error instanceof Error) {
return 'UNKNOWN_ERROR';
}
return 'UNEXPECTED_ERROR';
}
/**
* Helper function to format error for API responses
*/
export function formatErrorResponse(error) {
if (isMandateKitError(error)) {
return {
code: error.code,
message: error.message,
details: error.details,
};
}
if (error instanceof Error) {
return {
code: 'UNKNOWN_ERROR',
message: error.message,
details: { stack: error.stack },
};
}
return {
code: 'UNEXPECTED_ERROR',
message: 'An unexpected error occurred',
details: error,
};
}
//# sourceMappingURL=index.js.map