Skip to content

The GraphQL pair matcher throws the issuer away #357

Closed

Description

@Miracle656

Background

src/api/graphql.ts:

function findPair(assetA: string, assetB: string) {
  const normalize = (a: string) => a.toLowerCase() === 'native' ? 'XLM' : a.split(':')[0].toUpperCase()
  ...
}

a.split(':')[0] keeps the asset code and discards the issuer. On
Stellar an asset is a code and an issuer — USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN
and a USDC issued by anyone else are different assets that trade at different
prices. With the issuer dropped, every asset called USDC is the same asset to
this resolver.

This exact bug was fixed on the REST side and the fix is on main as
41b1f62, "fix: do not answer a price request about a different asset", with
src/__tests__/pairIssuerMatch.test.ts covering it. The GraphQL surface was
never changed, so a GraphQL caller can still be answered about a different asset
than the one they asked for.

Read the REST fix first. This is the same change in a second place, not a new
design problem.

What to build

  • Match on code and issuer when the caller supplies a qualified asset.
  • A bare code with no issuer should behave the way REST decided it behaves —
    read src/api/rest.ts and match it rather than inventing a second rule.
  • native must keep resolving to XLM.
  • A request naming an issuer we do not track must not fall back to a pair with
    the same code and a different issuer. Answering about the wrong asset is worse
    than answering "not found".

Acceptance criteria

  • A qualified asset only matches a pair with the same code and issuer
  • A test asserts two assets sharing a code and differing in issuer do not match each other
  • native still resolves to XLM
  • An unknown issuer produces no match rather than a same-code match
  • The behaviour for a bare, unqualified code matches the REST surface and a test says so

Drips Wave · Complexity: Intermediate · 150 points


Repo: Divinity-Labs/Lens. Node + TypeScript, Fastify, mercurius for
GraphQL at POST /graphql, Prisma on Postgres, Redis, Prometheus.

Run the tests: npm test. The tests are vitest, not jest. Running jest
here reports "66 suites, 0 tests" and means nothing. A single file is
npx vitest run src/__tests__/graphqlSubscription.test.ts.

Load test (prices) is already failing on main and has been for some
time. It is not your PR. Everything else should be green.

Read src/__tests__/graphqlSubscription.test.ts before you start. It is the
house pattern for testing this surface and it is good — it drives a real
subscription through a real server and asserts on what a client receives.

This service prices real assets on Stellar mainnet. A wrong number is worse
than a missing one, because the caller cannot tell.

Never elide an address, a contract id or a key in code, comments or test
fixtures. A previous batch shortened a contract id in an issue and five
contributors invented plausible-looking ids to fill the gap. Write it in full or
not at all.


Required: Before submitting, join the contributor Telegram so your work can be tracked and counted toward the Stellar Wave: https://t.me/+fxHXq8f1SwlkZDBk

Activity

  1. flare-999 commented on Oct 16, 2026

    @flare-999
    Contributor

    @flare-999 has applied to work on this issue as part of the Stellar Wave Program's 10th wave.

    Hi, I'll like to work on this issues, I'll provide the best technical skills from experience, please assign it to me

    ℹ️ Repo Maintainers: To accept this application, review their application or assign @flare-999 to this issue.

  2. nonchalanttee22-lgtm commented on Oct 16, 2026

    @nonchalanttee22-lgtm
    Contributor

    @nonchalanttee22-lgtm has applied to work on this issue as part of the Stellar Wave Program's 10th wave.

    I'll step in and fix the GraphQL pair matcher asset-issuer bug in Lens (#357)! Porting the asset matching rules from src/api/rest.ts to src/api/graphql.ts ensures GraphQL callers never receive prices for a different asset with the same code.
    Execution Plan
    Port REST Matching Logic (src/api/graphql.ts):
    Refactor findPair to preserve asset issuers for qualified assets (CODE:ISSUER).
    Match bare codes to REST behavior (src/api/rest.ts), ensure native maps to XLM, and guarantee unknown issuers return "not found" instead of fallback matching.
    Test Suite (src/tests/graphqlPairIssuerMatch.test.ts):
    Write Vitest integration tests following the graphqlSubscription.test.ts pattern, asserting that assets sharing codes but differing in issuers do not cross-match.
    Verification:
    Run npx vitest run to ensure all tests pass cleanly.
    Assign this issue to me, and I'll submit a clean PR!

    ℹ️ Repo Maintainers: To accept this application, review their application or assign @nonchalanttee22-lgtm to this issue.

  3. drips-wave commented on Oct 16, 2026

    @drips-wave

    Congratulations, @nonchalanttee22-lgtm! 🎉 Your application was accepted by the repo's maintainers, and the issue is due on October 22, 2026.

    🧑‍💻 @nonchalanttee22-lgtm: Please resolve the issue such that the repo's maintainers have enough time to review your contribution before the due date. You'll earn Points for completing the issue on-time, which will make you eligible for a share of the Stellar Wave Program's reward pool.

    Warning

    When opening a PR, please link it to this issue to ensure it gets tracked accurately. Points are awarded when this issue is marked as completed by the maintainer.

    🤠 Repo maintainers: Please keep an eye on the contributor's progress and review their work before the due date. You can manage this issue, including adjusting its complexity and points, here.

    🌊 Happy Wave 🌊

  4. Miracle656 commented on Oct 17, 2026

    @Miracle656
    CollaboratorAuthor

    Context for whoever takes this: #380 just merged and added input validation plus distinct INVALID_INPUT / PAIR_NOT_FOUND errors to getPrice, along with a schema docstring stating that the outcomes are kept distinct.

    findPair is unchanged, so the issuer is still discarded. That makes this issue slightly sharper than when I wrote it: a caller who supplies the correct issuer now gets a validated, well-formed, confident answer about a possibly different asset.

    So when you fix the matching, please also update the getPrice docstring #380 added — it describes three outcomes as distinct, and that is only true once the issuer is honoured.

    The REST fix to copy is 41b1f62 on main, with src/__tests__/pairIssuerMatch.test.ts beside it.

  5. drips-wave commented on Oct 25, 2026

    @drips-wave

    This issue has been completed by @nonchalanttee22-lgtm as part of the Stellar Wave Program's 10th Wave 🥳

    😎 @nonchalanttee22-lgtm: You earned 150 Points for completing this issue! Once the Wave's rewards are finalized, you'll be eligible for a percentage of the Wave's reward pool based on the percentage of total points you've earned. Learn more here. You can also Leave a review to share your experience working on this issue.

    🧑‍💻 Repo maintainers: How'd the contributor do? Leave a review to share your experience working with them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions