From 253247d8d241cb78d8cea3ea8120b77ee4abd7a1 Mon Sep 17 00:00:00 2001 From: Gianfranco Date: Tue, 27 Jan 2026 13:09:07 -0300 Subject: [PATCH 1/2] make checkBridgeStatus never reject --- .../squid-router-pay-phase-handler.ts | 99 +++++++++---------- 1 file changed, 46 insertions(+), 53 deletions(-) diff --git a/apps/api/src/api/services/phases/handlers/squid-router-pay-phase-handler.ts b/apps/api/src/api/services/phases/handlers/squid-router-pay-phase-handler.ts index c2d865a0f..895ebb984 100644 --- a/apps/api/src/api/services/phases/handlers/squid-router-pay-phase-handler.ts +++ b/apps/api/src/api/services/phases/handlers/squid-router-pay-phase-handler.ts @@ -197,74 +197,67 @@ export class SquidRouterPayPhaseHandler extends BasePhaseHandler { * @param txHash The swap (bridgeCall) transaction hash */ private async checkBridgeStatus(state: RampState, swapHash: string, quote: QuoteTicket): Promise { - try { - let isExecuted = false; - let payTxHash: string | undefined = state.state.squidRouterPayTxHash; // in case of recovery, we may have already paid. - // initial delay to allow for API indexing. - await new Promise(resolve => setTimeout(resolve, SQUIDROUTER_INITIAL_DELAY_MS)); - while (!isExecuted) { + let isExecuted = false; + let payTxHash: string | undefined = state.state.squidRouterPayTxHash; + + // Initial delay to allow for API indexing. + await new Promise(resolve => setTimeout(resolve, SQUIDROUTER_INITIAL_DELAY_MS)); + + while (!isExecuted) { + try { const squidRouterStatus = await this.getSquidrouterStatus(swapHash, state, quote); - if (squidRouterStatus.status === "success") { - isExecuted = true; + if (squidRouterStatus?.status === "success") { logger.info(`SquidRouterPayPhaseHandler: Transaction ${swapHash} successfully executed on Squidrouter.`); + isExecuted = true; break; } - if (!squidRouterStatus) { - logger.warn(`SquidRouterPayPhaseHandler: No squidRouter status found for swap hash ${swapHash}.`); - throw this.createRecoverableError("No squidRouter status found for swap hash."); - } - - // If route is on the same chain, we must skip the Axelar check. - if (!squidRouterStatus.isGMPTransaction) { - await new Promise(resolve => setTimeout(resolve, AXELAR_POLLING_INTERVAL_MS)); - } const axelarScanStatus = await getStatusAxelarScan(swapHash); - //no status found is considered a recoverable error. if (!axelarScanStatus) { - logger.warn(`SquidRouterPayPhaseHandler: No status found for swap hash ${swapHash}.`); - throw this.createRecoverableError("No status found for swap hash."); - } - if (axelarScanStatus.status === "executed" || axelarScanStatus.status === "express_executed") { - isExecuted = true; + logger.info( + `SquidRouterPayPhaseHandler: Status not found yet for hash ${swapHash}. Retrying in ${AXELAR_POLLING_INTERVAL_MS}ms...` + ); + } else if (axelarScanStatus.status === "executed" || axelarScanStatus.status === "express_executed") { logger.info(`SquidRouterPayPhaseHandler: Transaction ${swapHash} successfully executed on Axelar.`); + isExecuted = true; break; - } - - if (!payTxHash) { - const nativeToFundRaw = this.calculateGasFeeInUnits(axelarScanStatus.fees, DEFAULT_SQUIDROUTER_GAS_ESTIMATE); - const logIndex = Number(axelarScanStatus.id.split("_")[2]); - - payTxHash = await this.executeFundTransaction(nativeToFundRaw, swapHash as `0x${string}`, logIndex, state, quote); - - const isPolygon = quote.inputCurrency !== FiatToken.BRL; - const subsidyToken = isPolygon ? SubsidyToken.MATIC : SubsidyToken.GLMR; - const subsidyAmount = nativeToDecimal(nativeToFundRaw, 18).toNumber(); // Both MATIC and GLMR have 18 decimals - const payerAccount = isPolygon - ? this.polygonWalletClient.account?.address - : this.moonbeamWalletClient.account?.address; + } else { + // Status found but not finished (e.g., 'pending', 'called'). + // Check if we need to fund the gas service. + if (!payTxHash) { + logger.info(`SquidRouterPayPhaseHandler: Bridge transaction detected. Proceeding to fund gas.`); + const nativeToFundRaw = this.calculateGasFeeInUnits(axelarScanStatus.fees, DEFAULT_SQUIDROUTER_GAS_ESTIMATE); + const logIndex = Number(axelarScanStatus.id.split("_")[2]); + + payTxHash = await this.executeFundTransaction(nativeToFundRaw, swapHash as `0x${string}`, logIndex, state, quote); + + const isPolygon = quote.inputCurrency !== FiatToken.BRL; + const subsidyToken = isPolygon ? SubsidyToken.MATIC : SubsidyToken.GLMR; + const subsidyAmount = nativeToDecimal(nativeToFundRaw, 18).toNumber(); + const payerAccount = isPolygon + ? this.polygonWalletClient.account?.address + : this.moonbeamWalletClient.account?.address; + + if (payerAccount) { + await this.createSubsidy(state, subsidyAmount, subsidyToken, payerAccount, payTxHash); + } - if (payerAccount) { - await this.createSubsidy(state, subsidyAmount, subsidyToken, payerAccount, payTxHash); + await state.update({ + state: { + ...state.state, + squidRouterPayTxHash: payTxHash + } + }); } - - await state.update({ - state: { - ...state.state, - squidRouterPayTxHash: payTxHash - } - }); } - - await new Promise(resolve => setTimeout(resolve, AXELAR_POLLING_INTERVAL_MS)); + } catch (error) { + logger.warn(`SquidRouterPayPhaseHandler: Error during bridge status poll for ${swapHash}:`, error); } - } catch (error) { - if (error && error instanceof PhaseError && error.isRecoverable) { - throw error; - } - throw new Error(`SquidRouterPayPhaseHandler: Error waiting checking for Axelar bridge transaction: ${error}`); + + // Wait before the next iteration + await new Promise(resolve => setTimeout(resolve, AXELAR_POLLING_INTERVAL_MS)); } } From 64f05dfa9dbd2363d96b12b2f764d7cc6487d4b7 Mon Sep 17 00:00:00 2001 From: Gianfranco Date: Tue, 27 Jan 2026 13:17:17 -0300 Subject: [PATCH 2/2] correct axelar skip check if same chain --- .../squid-router-pay-phase-handler.ts | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/apps/api/src/api/services/phases/handlers/squid-router-pay-phase-handler.ts b/apps/api/src/api/services/phases/handlers/squid-router-pay-phase-handler.ts index 895ebb984..4f06d46a3 100644 --- a/apps/api/src/api/services/phases/handlers/squid-router-pay-phase-handler.ts +++ b/apps/api/src/api/services/phases/handlers/squid-router-pay-phase-handler.ts @@ -200,34 +200,34 @@ export class SquidRouterPayPhaseHandler extends BasePhaseHandler { let isExecuted = false; let payTxHash: string | undefined = state.state.squidRouterPayTxHash; - // Initial delay to allow for API indexing. await new Promise(resolve => setTimeout(resolve, SQUIDROUTER_INITIAL_DELAY_MS)); while (!isExecuted) { try { const squidRouterStatus = await this.getSquidrouterStatus(swapHash, state, quote); - if (squidRouterStatus?.status === "success") { + if (!squidRouterStatus) { + logger.warn(`SquidRouterPayPhaseHandler: No squidRouter status found for swap hash ${swapHash}.`); + } else if (squidRouterStatus.status === "success") { logger.info(`SquidRouterPayPhaseHandler: Transaction ${swapHash} successfully executed on Squidrouter.`); isExecuted = true; break; } - const axelarScanStatus = await getStatusAxelarScan(swapHash); + const isGmp = squidRouterStatus ? squidRouterStatus.isGMPTransaction : true; + + if (isGmp) { + const axelarScanStatus = await getStatusAxelarScan(swapHash); + + if (!axelarScanStatus) { + logger.info(`SquidRouterPayPhaseHandler: Axelar status not found yet for hash ${swapHash}.`); + } else if (axelarScanStatus.status === "executed" || axelarScanStatus.status === "express_executed") { + logger.info(`SquidRouterPayPhaseHandler: Transaction ${swapHash} successfully executed on Axelar.`); + isExecuted = true; + break; + } else if (!payTxHash) { + logger.info(`SquidRouterPayPhaseHandler: Bridge transaction detected on Axelar. Proceeding to fund gas.`); - if (!axelarScanStatus) { - logger.info( - `SquidRouterPayPhaseHandler: Status not found yet for hash ${swapHash}. Retrying in ${AXELAR_POLLING_INTERVAL_MS}ms...` - ); - } else if (axelarScanStatus.status === "executed" || axelarScanStatus.status === "express_executed") { - logger.info(`SquidRouterPayPhaseHandler: Transaction ${swapHash} successfully executed on Axelar.`); - isExecuted = true; - break; - } else { - // Status found but not finished (e.g., 'pending', 'called'). - // Check if we need to fund the gas service. - if (!payTxHash) { - logger.info(`SquidRouterPayPhaseHandler: Bridge transaction detected. Proceeding to fund gas.`); const nativeToFundRaw = this.calculateGasFeeInUnits(axelarScanStatus.fees, DEFAULT_SQUIDROUTER_GAS_ESTIMATE); const logIndex = Number(axelarScanStatus.id.split("_")[2]); @@ -245,18 +245,16 @@ export class SquidRouterPayPhaseHandler extends BasePhaseHandler { } await state.update({ - state: { - ...state.state, - squidRouterPayTxHash: payTxHash - } + state: { ...state.state, squidRouterPayTxHash: payTxHash } }); } + } else { + logger.info(`SquidRouterPayPhaseHandler: Same-chain transaction detected. Skipping Axelar check.`); } } catch (error) { - logger.warn(`SquidRouterPayPhaseHandler: Error during bridge status poll for ${swapHash}:`, error); + logger.error(`SquidRouterPayPhaseHandler: Error in bridge status loop for ${swapHash}:`, error); } - // Wait before the next iteration await new Promise(resolve => setTimeout(resolve, AXELAR_POLLING_INTERVAL_MS)); } }