Skip to content

feat: add SDK transaction memo validation utility (#240) - #304

Merged
El-swaggerito merged 1 commit into
Axionvera:mainfrom
XxHugheadxX:feat/memo-validation
Jul 27, 2026
Merged

feat: add SDK transaction memo validation utility (#240)#304
El-swaggerito merged 1 commit into
Axionvera:mainfrom
XxHugheadxX:feat/memo-validation

Conversation

@XxHugheadxX

Copy link
Copy Markdown
Contributor

Closes #240

Summary

Adds typed memo validation across the payment and transaction helpers, covering
all five Stellar memo types instead of text only.

What already existed

validateMemo was added in #62 and is already wired into sendXLM, sendAsset,
previewPayment, validateSendXLMParams and the offline preparation helpers. It
is unchanged by this PR, along with its tests — this work builds on top of it
rather than replacing it.

What it did not cover is memo type. It validated the 28-byte text limit and
nothing else.

The gap

The SDK could already read memo types back from Horizon —
TransactionSummary.memoType (src/types/transaction.ts:46) and memo_type
(:97) — but it could only write text. All three build sites hardcoded
StellarSDK.Memo.text(memo) (src/payments/index.ts:70,358,
src/transactions/offline-preparation.ts:419), and the input types were
memo?: string with no type field.

So a consumer could read a payment carrying memo_type: 'id' and be unable to
construct a reply with the same memo.

It also mis-reported failures. A 64-character hex intended as MEMO_HASH was
measured as text, failed the byte check, and surfaced as "Memo text exceeds
28-byte limit" — describing the wrong rule. That is the "unsupported formats"
case in the issue.

Changes

  • src/utils/memo.ts (new) — validateMemoInput, safeValidateMemo,
    normalizeMemo, buildMemo, plus the MEMO_* limit constants. Validates
    none, text (28 bytes), id (unsigned 64-bit), hash and return
    (64 hex chars).
  • src/types/index.tsMemoType and MemoInput; memo?: string widened
    to memo?: string | MemoInput on the input params.
  • src/errors/codes.tsTX_INVALID_MEMO added to the registry.
  • Payment and transaction helpers — validate via validateMemoInput and
    build via buildMemo.
  • docs/memo-validation.md (new) — rules per type, the validation.reason
    table, and migration notes.

Error codes

Memo failures on the throwing path now report TX_INVALID_MEMO, which is in the
registry, so isKnownErrorCode() recognises it and describeError() returns real
guidance instead of the unknown-code fallback. validation.reason distinguishes
unsupported_type from too_long, not_unsigned_integer, out_of_range,
invalid_length and not_hexadecimal.

ValidationErrorCode in src/payments/validation.ts is a separate public
taxonomy for the non-throwing validateSendXLMParams path, with its own
INVALID_* naming. It is deliberately left unchanged, so docs/api-reference.md
is untouched.

Backwards compatibility

  • A plain string memo still means text everywhere. No caller needs changes.
  • validateMemo is unchanged, still exported, and its tests still pass.
  • The widened param types and the new PaymentPreview.memoType are additive.
  • Breaking: the throwing path reports TX_INVALID_MEMO instead of the
    unregistered INVALID_MEMO. The text-memo message text is unchanged.

Previews

PaymentPreview gained an optional memoType, mirroring how
TransactionSummary already exposes memo + memoType on the read side, so
previews and fetched transactions describe memos the same way. memo stays a
string.

Tests

29 new tests in tests/memo-validation.test.ts: all five types accepted with
valid input; text measured in bytes not characters; id rejecting negative,
fractional, non-numeric and above 2^64-1; hash/return rejecting wrong length
and non-hex; an unsupported type reporting unsupported_type rather than a
length error; TX_INVALID_MEMO being registry-known; buildMemo producing the
right Stellar memo per type; and the plain-string form behaving exactly as before.

Verification

lint, check:circular (40 modules, no cycles) and build all pass.

Full suite: 46 failed · 706 passed · 1 skipped. The 46 failures are
pre-existing on the base commit — verified by running the suite against a clean
checkout of f6574d5, which gives 46 failed · 677 passed · 1 skipped: same
failures in the same five files. This branch adds exactly the 29 new passing
tests and introduces no regressions.

@El-swaggerito
El-swaggerito merged commit ebd75d1 into Axionvera:main Jul 27, 2026
1 check passed
@XxHugheadxX
XxHugheadxX deleted the feat/memo-validation branch July 27, 2026 22:48
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.

Add SDK transaction memo validation utility

2 participants