Skip to content

fix(sdk-coin-xlm): accept alphanumeric Stellar asset codes in StellarToken - #10109

Merged
nayandas190 merged 1 commit into
masterfrom
nayanjyotidas/coins-2284-fix-stellar-asset-code-validation-blocking-usdm1-withdrawals
Oct 31, 2026
Merged

nayandas190 merged 1 commit into
masterfrom
nayanjyotidas/coins-2284-fix-stellar-asset-code-validation-blocking-usdm1-withdrawals

Conversation

@nayandas190

@nayandas190 nayandas190 commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes COINS-2284.

StellarToken rejected every Stellar token whose asset code contains a digit, so MI Financial Services DAO LLC could not withdraw xlm:USDM1 from its Go account: uploading the unsigned transaction to OVC failed in explainTransaction.

Error invoking remote method 'bitgo:explainTransaction':
Error: Transaction explanation failed for xlm wallet 5da508a23f4e93ee067ab60998fe1faa:
invalid token: xlm:USDM1-GDM5QWWXCMDTQMZAKMYTCI52LA7FWBHAZMU5NJLMIFHDJISJRP2ZWPKC

Root cause

modules/sdk-coin-xlm/src/stellarToken.ts validated the token in its constructor with:

static readonly tokenPattern: RegExp = /[A-Z]{1,12}-G[A-Z0-9]{55}/;

Two defects:

  1. The asset code class is [A-Z], which excludes digits. Stellar asset codes are alphaNum4/alphaNum12, so digits are legal — USDM1 and USDT0 both failed the match. Any call that instantiates the token (explainTransaction, signTransaction, bitgo.coin('xlm:USDM1-…')) threw BitGoJsError: invalid token: ….
  2. The pattern was unanchored, so it matched a substring of the token rather than the whole thing. That is why xlm:gBENJI-… and txlm:yGHS-… passed despite their lowercase codes — the regex matched BENJI-G… / GHS-G…. It also allowed trailing garbage after the issuer.

Fix

static readonly tokenPattern: RegExp = /^[a-zA-Z0-9]{1,12}-G[A-Z0-9]{55}$/;

Anchored, and [a-zA-Z0-9] for the asset code, which matches the on-chain rule: stellar-core validates codes with isAsciiAlphaNumeric (a-z, A-Z, 0-9) in isAssetValid, and the AssetCode4/AssetCode12 XDR types are documented as "alphanumeric characters". Lowercase is legal and already onboarded (xlm:gBENJI-…, txlm:yGHS-…), so the code class must not be uppercase-only.

Anchoring is safe for every token currently in @bitgo/statics: with the corrected code class, all 35 registered XLM tokens match the anchored pattern.

Tests

Added describe('StellarToken:') to modules/sdk-coin-xlm/test/unit/xlm.ts:

  • every token in @bitgo/statics registers and instantiates (covers USDM1/USDT0 and any future alphanumeric code);
  • a digit-bearing asset code instantiates with the expected code/issuer;
  • a non-alphanumeric asset code is rejected;
  • an asset code longer than 12 characters is rejected.

Verification on this branch:

$ cd modules/sdk-coin-xlm && npx mocha --reporter spec --grep "StellarToken"
  4 passing

$ npx mocha
  135 passing

Before the stellarToken.ts change, 3 of the 4 new tests fail with the exact error from the ticket (BitGoJsError: invalid token: xlm:USDM1-GDM5QWWXCMDTQMZAKMYTCI52LA7FWBHAZMU5NJLMIFHDJISJRP2ZWPKC), confirming the regression is reproduced and fixed. eslint, prettier --check and tsc --build report no errors in this module.

Follow-up (not in this PR)

To unblock the client:

  1. merge this PR to master;
  2. run the Publish @bitgo-beta workflow (workflow_dispatch on master), which re-scopes and publishes @bitgo-beta/sdk-coin-xlm@2.0.5-beta.<next>;
  3. bump @bitgo-beta/sdk-coin-xlm in offline-vault-console and cut an OVC release.

No @bitgo-beta/statics bump is needed: the token has been in statics since COIN-7264 and is already present in OVC v4.11.67. The blocker was the SDK's token validation, not missing token metadata — which is why a statics bump alone would not have fixed this.

No wallet-platform bump is needed either: wallet-platform validates Stellar tokens against its own config pattern, which is already anchored and alphanumeric (wallet-platform/config/env/defaults.ts:1563 → /^[A-Za-z0-9]{1,12}-G[A-Z0-9]{55}$/), and it never instantiates the SDK's StellarToken (it only imports Utils from @bitgo-beta/sdk-coin-xlm). A repo-wide search of bitgo-microservices finds no copy of the old uppercase-only pattern.

@linear-code

linear-code Bot commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

COINS-2284

@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Compatibility checks are failing on Node.js 27-nightly (experimental, non-blocking). This does not block merge, but it signals an incompatibility to fix before this release becomes supported.

View run

…Token

StellarToken.tokenPattern only allowed uppercase letters in the asset code, so
any token whose code contains a digit (e.g. xlm:USDM1, xlm:USDT0) failed to
instantiate and threw `invalid token: ...`. That blocked explainTransaction and
signTransaction in OVC for those tokens, leaving clients unable to move funds.
The pattern was also unanchored, so it silently matched codes it should have
rejected.

Stellar asset codes are alphanumeric (a-z, A-Z, 0-9) and 1-12 characters long:
see stellar-core `isAsciiAlphaNumeric`/`isAssetValid` and the AssetCode4 and
AssetCode12 XDR definitions. Lowercase is legal and already onboarded
(xlm:gBENJI-...), so the code class must not be uppercase-only.

Anchor the pattern and accept [a-zA-Z0-9] in the asset code.

Ticket: COINS-2284
@nayandas190
nayandas190 force-pushed the nayanjyotidas/coins-2284-fix-stellar-asset-code-validation-blocking-usdm1-withdrawals branch from a790b07 to e2ef458 Compare October 31, 2026 13:52
@nayandas190
nayandas190 marked this pull request as ready for review October 31, 2026 14:20
@nayandas190
nayandas190 requested a review from a team as a code owner October 31, 2026 14:20

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@nayandas190

Copy link
Copy Markdown
Contributor Author

@claude please review this pr.

@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @nayandas190's task in 23s —— View job


Review of #10109: accept alphanumeric Stellar asset codes

Verdict: looks good to merge. I found no blocking issues.

  • Read the diff
  • Checked how tokenPattern is used (StellarToken constructor, Xlm)
  • Reviewed the tests

Fix (modules/sdk-coin-xlm/src/stellarToken.ts)

  • The new pattern /^[a-zA-Z0-9]{1,12}-G[A-Z0-9]{55}$/ fixes the digit rejection (USDM1, USDT0). It matches Stellar's alphanumeric asset code rules (1–12 characters).
  • Anchoring is correct. The constructor validates only the part after the xlm: split, so ^…$ applies to CODE-ISSUER and not the prefix. The unanchored regex let trailing garbage through and accepted lowercase codes only by matching a substring.
  • Only StellarToken uses tokenPattern. The other file that matched my search is sdk-coin-algo, which defines its own pattern. So nothing else is affected.
  • The change is safe for existing tokens. The PR reports that all 35 statics tokens match, and the new registration test checks this.

Tests (modules/sdk-coin-xlm/test/unit/xlm.ts)

  • The cases cover the regression (digits), the registration of every statics token, a non-alphanumeric code and a code over 12 characters. The negative tests assert on /invalid token:/, so they fail for the right reason.
  • I did not run the tests myself. I'm relying on the results in the PR description.

Minor suggestions (non-blocking)

  1. Issuer length. There is no negative test for a malformed issuer (wrong length, or trailing characters after it). A trailing-garbage case such as …ZWPKCX would cover the anchoring the PR text calls out.
  2. Stellar's code length rule. Stellar's AssetCode4/AssetCode12 types are strictly 1–4 or 5–12 characters, which {1,12} already covers. Nothing to change.
  3. Test hygiene. register(tokenSdk) in the first test builds a fresh SDK instance and registers all coins, which is fine. If register throws on re-registration, a shared bitgo instance would have failed, but a fresh one avoids that.

CI

The Node 27-nightly failure is marked experimental and non-blocking. It looks unrelated to this change.

Follow-up

As the PR notes, the client stays blocked until @bitgo/sdk-coin-xlm is published and @bitgo-beta/sdk-coin-xlm is bumped in offline-vault-console.

@nayandas190
nayandas190 merged commit d90530c into master Oct 31, 2026
27 checks passed
@nayandas190
nayandas190 deleted the nayanjyotidas/coins-2284-fix-stellar-asset-code-validation-blocking-usdm1-withdrawals branch October 31, 2026 14:44
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.

2 participants