Skip to content

feat: add deterministic Stellar address validation module - #363

Merged
Lakes41 merged 2 commits into
Adamantine-guild:mainfrom
angelraph:feat/stellar-address-validator
Aug 26, 2026
Merged

feat: add deterministic Stellar address validation module#363
Lakes41 merged 2 commits into
Adamantine-guild:mainfrom
angelraph:feat/stellar-address-validator

Conversation

@angelraph

Copy link
Copy Markdown
Contributor

Description

Adds @guildpass/stellar-utils, a reusable, deterministic Stellar StrKey address validation module. It has no dependency on a Stellar SDK, Prisma, Redis, or Fastify, so it can be safely consumed at any boundary (wallet linking, membership operations, contract integrations) without duplicating validation logic across route handlers or services.

Validation is implemented from first principles: RFC4648 base32 decoding (with canonical-encoding checks — invalid alphabet, non-zero padding bits, non-minimal length) and CRC16/XMODEM checksum verification, per the Stellar StrKey spec (https://developers.stellar.org/docs/encyclopedia/base32).

Linked Issue

Closes #344

Type of Change

  • ✨ New feature / endpoint

Changes Made

  • packages/stellar-utils/src/index.tsvalidateStellarAddress, isStellarAddress, assertStellarAddress, InvalidStellarAddressError, and the StellarAddressValidationResult typed union.
  • packages/stellar-utils/src/index.test.ts — 14 unit tests covering valid/invalid checksum, truncated/padded input, random strings, casing, unsupported StrKey types, empty/whitespace input, whitespace trimming, non-string input of many types, determinism, and the assertion API.
  • packages/stellar-utils/package.json, tsconfig.json — package scaffolding, matching the conventions of packages/rate-limit.

Design notes

  • Only G... ed25519 public account addresses are accepted. Other well-formed StrKey types (M muxed account, S seed, T pre-auth tx, X sha256 hash, P signed payload, C contract, L liquidity pool, B claimable balance) are recognised by their version byte and rejected explicitly via UNSUPPORTED_ADDRESS_TYPE, rather than falling through as generically malformed or being silently accepted.
  • Only leading/trailing whitespace is trimmed (documented in the JSDoc on validateStellarAddress); casing and internal content are never normalised — a lowercase or mixed-case address is rejected rather than silently coerced, since StrKey is case-sensitive by spec.
  • validateStellarAddress never throws for ordinary invalid input (verified against null, undefined, numbers, booleans, objects, arrays, symbols, functions, and Date instances). assertStellarAddress is provided separately for call sites that want throw-based control flow.
  • No database, Redis, or Fastify dependency; no wallet persistence, membership, or API route changes are included.

Test Evidence

pnpm --filter @guildpass/stellar-utils test

 ✓ src/index.test.ts (14 tests) 19ms

 Test Files  1 passed (1)
      Tests  14 passed (14)

Repo-wide, from a clean install:

pnpm typecheck   # passes (all workspace packages, including apps/api)
pnpm build       # passes
pnpm test        # passes (stellar-utils: 14/14, plus all pre-existing package tests green)

General Checklist

  • I have read CONTRIBUTING.md
  • This PR is linked to an open issue
  • pnpm typecheck passes
  • pnpm test passes — all tests green
  • Prisma schema changes include a migration file — N/A, no schema changes
  • New API endpoints are documented in OpenAPI — N/A, no new endpoints; this module is intentionally independent of HTTP routes
  • No secrets, keys, or wallet addresses introduced — test fixtures are synthetically generated in-test (deterministic byte arrays encoded via a local StrKey encoder), not real Stellar keys
  • .env.example updated if new env variables were added — N/A, no new env variables
  • Documentation updated if new behaviour was introduced — behaviour is documented via JSDoc on the exported API

Additional Notes

apps/api's tsc typecheck requires pnpm --filter @guildpass/api prisma:generate to have been run first (to generate the Prisma client types) — this is a pre-existing local-setup step unrelated to this change, confirmed present on main before this branch's changes.

angelraph and others added 2 commits August 25, 2026 17:37
Adds @guildpass/stellar-utils, a framework-free module that validates
Stellar StrKey addresses via native RFC4648 base32 decoding and CRC16/XMODEM
checksum verification (no Stellar SDK, database, or Fastify dependency).

Only ed25519 public account addresses (G...) are treated as valid; other
well-formed StrKey types (M, S, T, X, P, C, L, B) are rejected explicitly as
UNSUPPORTED_ADDRESS_TYPE instead of silently accepted. validateStellarAddress
never throws; isStellarAddress and assertStellarAddress are provided as
convenience wrappers.

Closes Adamantine-guild#344

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Resolves the pnpm-lock.yaml conflict from main's permission-expression and
webhook-verification packages by regenerating the lockfile via pnpm install.
@Lakes41
Lakes41 merged commit 9d29561 into Adamantine-guild:main Aug 26, 2026
2 checks passed
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.

Build a deterministic Stellar address validation module for GuildPass Core

2 participants