Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 66 additions & 60 deletions app/backend/src/common/soroban-errors/soroban-error.codes.ts
Original file line number Diff line number Diff line change
@@ -1,69 +1,75 @@
/**
* Stable API error codes for Soroban contract failures.
*
* These codes are part of the public API contract β€” clients can rely on them
* for deterministic error handling and UX messaging.
*
* Grouped by domain: Auth, Contract State, Balance, Admin, Version, Generic.
*/
export enum SorobanErrorCode {
// ── Auth ──────────────────────────────────────────────────────────────────
/** Caller is not authorised to perform this operation. */
UNAUTHORIZED = 'CONTRACT_UNAUTHORIZED',
/** Required auth entry is missing from the transaction. */
AUTH_MISSING = 'CONTRACT_AUTH_MISSING',
* Stable API error codes for Soroban contract failures.
*
* These codes are part of the public API contract β€” clients can rely on them
* for deterministic error handling and UX messaging.
*
* Grouped by domain: Auth, Contract State, Balance, Admin, Version, Generic.
*/
export enum SorobanErrorCode {
// ── Auth ──────────────────────────────────────────────────────────────────
/** Caller is not authorised to perform this operation. */
UNAUTHORIZED = 'CONTRACT_UNAUTHORIZED',
/** Required auth entry is missing from the transaction. */
AUTH_MISSING = 'CONTRACT_AUTH_MISSING',

// ── Contract state ────────────────────────────────────────────────────────
/** Contract is paused; all mutating operations are blocked. */
CONTRACT_PAUSED = 'CONTRACT_PAUSED',
/** Contract write operations are temporarily disabled by the server. */
CONTRACT_WRITES_DISABLED = 'CONTRACT_WRITES_DISABLED',
/** Escrow / resource entry not found in contract storage. */
ESCROW_NOT_FOUND = 'CONTRACT_ESCROW_NOT_FOUND',
/** Escrow has already been withdrawn or refunded. */
ESCROW_ALREADY_SETTLED = 'CONTRACT_ESCROW_ALREADY_SETTLED',
/** Escrow has not yet expired; refund is not allowed. */
ESCROW_NOT_EXPIRED = 'CONTRACT_ESCROW_NOT_EXPIRED',
/** Escrow has expired; withdrawal is no longer allowed. */
ESCROW_EXPIRED = 'CONTRACT_ESCROW_EXPIRED',
/** Required contract storage entry is missing (MissingValue). */
STORAGE_MISSING = 'CONTRACT_STORAGE_MISSING',
/** Ledger entry has expired and must be restored before use. */
RESTORE_REQUIRED = 'CONTRACT_RESTORE_REQUIRED',
// ── Contract state ────────────────────────────────────────────────────────
/** Contract is paused; all mutating operations are blocked. */
CONTRACT_PAUSED = 'CONTRACT_PAUSED',
/** Contract write operations are temporarily disabled by the server. */
CONTRACT_WRITES_DISABLED = 'CONTRACT_WRITES_DISABLED',
/** Escrow / resource entry not found in contract storage. */
ESCROW_NOT_FOUND = 'CONTRACT_ESCROW_NOT_FOUND',
/** Escrow has already been withdrawn or refunded. */
ESCROW_ALREADY_SETTLED = 'CONTRACT_ESCROW_ALREADY_SETTLED',
/** Escrow has not yet expired; refund is not allowed. */
ESCROW_NOT_EXPIRED = 'CONTRACT_ESCROW_NOT_EXPIRED',
/** Escrow has expired; withdrawal is no longer allowed. */
ESCROW_EXPIRED = 'CONTRACT_ESCROW_EXPIRED',
/** Required contract storage entry is missing (MissingValue). */
STORAGE_MISSING = 'CONTRACT_STORAGE_MISSING',
/** Ledger entry has expired and must be restored before use. */
RESTORE_REQUIRED = 'CONTRACT_RESTORE_REQUIRED',

// ── Balance ───────────────────────────────────────────────────────────────
/** Account or escrow has insufficient token balance. */
INSUFFICIENT_BALANCE = 'CONTRACT_INSUFFICIENT_BALANCE',
/** Amount provided is zero or negative. */
INVALID_AMOUNT = 'CONTRACT_INVALID_AMOUNT',
// ── Balance ───────────────────────────────────────────────────────────────
/** Account or escrow has insufficient token balance. */
INSUFFICIENT_BALANCE = 'CONTRACT_INSUFFICIENT_BALANCE',
/** Amount provided is zero or negative. */
INVALID_AMOUNT = 'CONTRACT_INVALID_AMOUNT',

// ── Version / upgrade ─────────────────────────────────────────────────────
/** Contract schema version is not supported by this client. */
VERSION_MISMATCH = 'CONTRACT_VERSION_MISMATCH',
/** WASM hash provided for upgrade is invalid. */
INVALID_WASM_HASH = 'CONTRACT_INVALID_WASM_HASH',
// ── Version / upgrade ─────────────────────────────────────────────────────
/** Contract schema version is not supported by this client. */
VERSION_MISMATCH = 'CONTRACT_VERSION_MISMATCH',
/** WASM hash provided for upgrade is invalid. */
INVALID_WASM_HASH = 'CONTRACT_INVALID_WASM_HASH',

// ── Admin ─────────────────────────────────────────────────────────────────
/** Caller is not the contract admin. */
NOT_ADMIN = 'CONTRACT_NOT_ADMIN',
/** Admin address provided is invalid. */
INVALID_ADMIN = 'CONTRACT_INVALID_ADMIN',
// ── Admin ─────────────────────────────────────────────────────────────────
/** Caller is not the contract admin. */
NOT_ADMIN = 'CONTRACT_NOT_ADMIN',
/** Admin address provided is invalid. */
INVALID_ADMIN = 'CONTRACT_INVALID_ADMIN',

// ── Input / params ────────────────────────────────────────────────────────
/** One or more input values are invalid for this contract call. */
INVALID_INPUT = 'CONTRACT_INVALID_INPUT',
/** Contract or account does not exist on the network. */
NOT_FOUND = 'CONTRACT_NOT_FOUND',
// ── Input / params ────────────────────────────────────────────────────────
/** One or more input values are invalid for this contract call. */
INVALID_INPUT = 'CONTRACT_INVALID_INPUT',
/** Contract or account does not exist on the network. */
NOT_FOUND = 'CONTRACT_NOT_FOUND',

// ── Resource limits ───────────────────────────────────────────────────────
/** Transaction exceeds Soroban compute budget. */
BUDGET_EXCEEDED = 'CONTRACT_BUDGET_EXCEEDED',
// ── Resource limits ───────────────────────────────────────────────────────
/** Transaction exceeds Soroban compute budget. */
BUDGET_EXCEEDED = 'CONTRACT_BUDGET_EXCEEDED',

// ── Generic fallback ──────────────────────────────────────────────────────
/** An unexpected contract error occurred. */
UNKNOWN = 'CONTRACT_UNKNOWN_ERROR',
// ── Generic fallback ──────────────────────────────────────────────────────
/** An unexpected contract error occurred. */
UNKNOWN = 'CONTRACT_UNKNOWN_ERROR',

// ── Indexer Lag Guard ─────────────────────────────────────────────────────
/** Indexer is lagging too far behind the network; risky operations are blocked. */
INDEXER_LAGGING = 'INDEXER_LAGGING',
}
// ── Indexer Lag Guard ─────────────────────────────────────────────────────
/** Indexer is lagging too far behind the network; risky operations are blocked. */
INDEXER_LAGGING = 'INDEXER_LAGGING',

// ── Refund specific ───────────────────────────────────────────────────────
/** Refund operation failed due to contract error. */
REFUND_FAILED = 'CONTRACT_REFUND_FAILED',
/** Refund already executed on-chain. */
REFUND_DUPLICATE = 'CONTRACT_REFUND_DUPLICATE',
}
12 changes: 12 additions & 0 deletions app/backend/src/common/soroban-errors/soroban-error.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ const ERROR_MAPPINGS: Array<{
message: 'The escrow has expired and can no longer be withdrawn.',
},

// ── Refund specific ───────────────────────────────────────────────────────
{
pattern: /refund.*failed|refund.*error/i,
code: SorobanErrorCode.REFUND_FAILED,
message: 'The refund operation failed. Please check the refund eligibility and try again.',
},
{
pattern: /refund.*duplicate|already.*refunded|refund.*exists/i,
code: SorobanErrorCode.REFUND_DUPLICATE,
message: 'This refund has already been processed on-chain.',
},

// ── Storage ───────────────────────────────────────────────────────────────
{
pattern: /restore.*required|entry.*expired.*restore/i,
Expand Down
1 change: 1 addition & 0 deletions app/backend/src/job-queue/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export { RecurringPaymentHandler } from './recurring-payment.handler';
export { ExportGenerationHandler } from './export-generation.handler';
export { ReconciliationHandler } from './reconciliation.handler';
export { StellarReconnectHandler } from './stellar-reconnect.handler';
export { RefundJobHandler, PermanentRefundError } from './refund-job.handler';
Loading
Loading