diff --git a/packages/adapters/database/src/db.ts b/packages/adapters/database/src/db.ts index f158c9c5..ce00f121 100644 --- a/packages/adapters/database/src/db.ts +++ b/packages/adapters/database/src/db.ts @@ -712,7 +712,7 @@ export async function getRebalanceOperations( offset?: number, filter?: { status?: RebalanceOperationStatus | RebalanceOperationStatus[]; - bridge?: string; + bridge?: string | string[]; chainId?: number; earmarkId?: string | null; invoiceId?: string; @@ -738,9 +738,14 @@ export async function getRebalanceOperations( paramCount++; } - if (filter.bridge !== undefined) { - conditions.push(`ro."bridge" = $${paramCount}`); - values.push(filter.bridge); + if (filter.bridge) { + if (Array.isArray(filter.bridge)) { + conditions.push(`ro.bridge = ANY($${paramCount})`); + values.push(filter.bridge); + } else { + conditions.push(`ro.bridge = $${paramCount}`); + values.push(filter.bridge); + } paramCount++; } diff --git a/packages/adapters/rebalance/test/adapters/ccip/ccip.spec.ts b/packages/adapters/rebalance/test/adapters/ccip/ccip.spec.ts index af12721f..f2afe781 100644 --- a/packages/adapters/rebalance/test/adapters/ccip/ccip.spec.ts +++ b/packages/adapters/rebalance/test/adapters/ccip/ccip.spec.ts @@ -544,6 +544,22 @@ describe('CCIPBridgeAdapter', () => { expect(mockGetExecutionReceipts).toHaveBeenCalled(); // SDK should be called as fallback }); + it('falls back to SDK when Atlas API returns non-200, non-404 status', async () => { + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 500, + statusText: 'Internal Server Error', + json: async () => ({}), + } as Response); + mockGetExecutionReceipts.mockImplementation(async function* () { + yield mockExecutionReceipt; + }); + + const status = await adapter.getTransferStatus('0xhash', 1, 42161); + expect(status.status).toBe('SUCCESS'); + expect(mockGetExecutionReceipts).toHaveBeenCalled(); // SDK should be called as fallback + }); + it('returns PENDING when no execution receipts found (SDK fallback)', async () => { mockGetExecutionReceipts.mockImplementation(async function* () { // Empty generator - no receipts diff --git a/packages/poller/src/rebalance/mantleEth.ts b/packages/poller/src/rebalance/mantleEth.ts index 9c65d58d..ea93e47b 100644 --- a/packages/poller/src/rebalance/mantleEth.ts +++ b/packages/poller/src/rebalance/mantleEth.ts @@ -923,6 +923,7 @@ export const executeMethCallbacks = async (context: ProcessingContext): Promise< // Get all pending operations from database const { operations } = await db.getRebalanceOperations(undefined, undefined, { status: [RebalanceOperationStatus.PENDING, RebalanceOperationStatus.AWAITING_CALLBACK], + bridge: [SupportedBridge.Mantle, `${SupportedBridge.Across}-mantle`], }); logger.debug(`Found ${operations.length} meth rebalance operations`, { @@ -987,6 +988,7 @@ export const executeMethCallbacks = async (context: ProcessingContext): Promise< logger.warn('Operation is not a mantle bridge', logContext); continue; } + const adapter = rebalance.getAdapter(bridgeType as SupportedBridge); // Get origin transaction hash from JSON field diff --git a/packages/poller/src/rebalance/tacUsdt.ts b/packages/poller/src/rebalance/tacUsdt.ts index a0345184..f4efa0c7 100644 --- a/packages/poller/src/rebalance/tacUsdt.ts +++ b/packages/poller/src/rebalance/tacUsdt.ts @@ -1699,15 +1699,11 @@ const executeTacCallbacks = async (context: ProcessingContext): Promise => const operationTtlMinutes = config.regularRebalanceOpTTLMinutes ?? DEFAULT_OPERATION_TTL_MINUTES; // Get all pending TAC operations - const { operations } = await db.getRebalanceOperations(undefined, undefined, { + const { operations: tacOperations } = await db.getRebalanceOperations(undefined, undefined, { status: [RebalanceOperationStatus.PENDING, RebalanceOperationStatus.AWAITING_CALLBACK], + bridge: [`${SupportedBridge.Stargate}-tac`, SupportedBridge.TacInner], }); - // Filter for TAC-related operations - const tacOperations = operations.filter( - (op) => op.bridge === 'stargate-tac' || op.bridge === SupportedBridge.TacInner, - ); - // SERIALIZATION CHECK: Only allow one Leg 2 (TacInner) operation in-flight at a time // This prevents mixing funds from multiple flows when they complete close together const pendingTacInnerOps = tacOperations.filter(