Skip to content

Recover failed Axelar confirms from the funding account when the relayer fails - #1407

Merged
ebma merged 5 commits into
stagingfrom
feat/axelar-own-confirm-signer
Oct 7, 2026
Merged

ebma merged 5 commits into
stagingfrom
feat/axelar-own-confirm-signer

Conversation

@ebma

@ebma ebma commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Stacked on #1406 (its 3 commits appear here until it merges). Merge #1406 first.

Why

recoverAxelarStuckConfirm depends on Axelar's public signing relayer. The relayer keeps signing ConfirmGatewayTx one account sequence behind the chain: 53011 vs 53012 in September, and 53019 vs 53020 on 2026-10-06. Every broadcast is rejected with code 32, and the Axelarscan "confirm" button fails the same way.

ConfirmGatewayTxsRequest is ROLE_UNRESTRICTED in axelar-core v1.5.3, so any funded Axelar account can restart the poll. On 2026-10-06, a confirm sent from our own Axelar account recovered 0x9813…8ff7: Axelar tx EAA8FE9D…87E3, after which the call was approved and executed. This PR makes the backend do that by itself.

What changes

  • maybeRecoverStuckConfirm tries the relayer first, as before. If the relayer fails (except on abort), the same attempt falls back to confirmGatewayTxFromFundingAccount.
  • confirmGatewayTxFromFundingAccount (squid-router-swap/axelar-confirm.ts) signs with EVM_FUNDING_PRIVATE_KEY. That secp256k1 key also controls an axelar1… account. The function:
    • simulates and pays 1.5× the simulated gas at 0.007 uaxl (about 0.027 AXL);
    • refuses to broadcast if the account can't pay, with an error naming the axelar1… address to fund, which shows up in the stuck-GMP Slack alert;
    • re-checks the abort before broadcasting;
    • serializes signing within each process;
    • waits for the tx to be included and treats a non-zero code as a failure.
  • The existing 10-minute axelarConfirmRecoveryAt cooldown covers both attempts, so spending is capped at one confirm per stuck ramp per cooldown.
  • The Axelar message is hand-encoded (3 protobuf fields). Only @cosmjs/proto-signing, @cosmjs/stargate and cosmjs-types are added, in apps/api only.
  • The manual script from the first revision of this PR is removed.
  • The security spec's confirm-poll row describes the fallback, its key use and its blast radius.

Before deploying

Send a few AXL, on the native Axelar network, to the funding key's axelar1… address. It differs from the EVM address 0xEC733…33e2. If it's unfunded, the first fallback attempt fails and the alert names the address.

Tests

  • Encoder: byte-identical to the message in mainnet tx A2D28977…41B6 (code 0).
  • Real CosmJS signing under Bun: decoding the signed tx gives back the message, sequence and a 64-byte signature.
  • confirmGatewayTxFromFundingAccount with a mocked client:
    • correct sender, message and fee (27,096 uaxl, matching the real recovery);
    • refuses when the balance is short by 1 uaxl;
    • rejects on code 32;
    • does nothing when aborted.
  • Executor:
    • relayer success → no fallback;
    • relayer code 32 → funding-account confirm under the same cooldown;
    • both failures are reported;
    • no fallback once aborted.
      The two new executor tests fail without the change.
  • bun test squid axelar (api): 40 pass, 0 fail, 2 skipped; tsc clean.

ebma added 2 commits October 6, 2026 18:32
Axelar's public signing relayer keeps signing ConfirmGatewayTx with a stale account sequence (Sep 1-2, Sep 29, Oct 6), so every recovery broadcast is rejected with code 32. ConfirmGatewayTxsRequest is permissionless, so a small AXL-funded account of ours can restart the poll without waiting on Axelar support.
@netlify

netlify Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for vortexfi canceled.

Name Link
🔨 Latest commit 2212a26
🔍 Latest deploy log https://app.netlify.com/projects/vortexfi/deploys/6ac6059615bfc3000859cb9b

@netlify

netlify Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for vortex-sandbox ready!

Name Link
🔨 Latest commit 2212a26
🔍 Latest deploy log https://app.netlify.com/projects/vortex-sandbox/deploys/6ac605963ed71900083b191f
😎 Deploy Preview https://deploy-preview-1407--vortex-sandbox.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for vrtx-dashboard canceled.

Name Link
🔨 Latest commit 2212a26
🔍 Latest deploy log https://app.netlify.com/projects/vrtx-dashboard/deploys/6ac6059731030600087a8b2f

ebma added 2 commits October 7, 2026 09:57
…he relayer fails

Axelar's signing relayer signed with a stale sequence again on 2026-10-06, so the automatic recovery could not restart the failed poll; a manual confirm from our own Axelar account recovered it. The backend now does that itself with the EVM funding key, which also controls an axelar1 account. The relayer stays first so environments without AXL keep today's behavior, and the manual script is gone.
@ebma ebma changed the title Confirm stuck Axelar transfers from our own Axelar account Recover failed Axelar confirms from the funding account when the relayer fails Oct 7, 2026
@ebma
ebma merged commit a9aa046 into staging Oct 7, 2026
5 of 6 checks passed
@ebma
ebma deleted the feat/axelar-own-confirm-signer branch October 7, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant