feat: add SDK transaction memo validation utility (#240) - #304
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
validateMemowas added in #62 and is already wired intosendXLM,sendAsset,previewPayment,validateSendXLMParamsand the offline preparation helpers. Itis 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) andmemo_type(
:97) — but it could only write text. All three build sites hardcodedStellarSDK.Memo.text(memo)(src/payments/index.ts:70,358,src/transactions/offline-preparation.ts:419), and the input types werememo?: stringwith no type field.So a consumer could read a payment carrying
memo_type: 'id'and be unable toconstruct a reply with the same memo.
It also mis-reported failures. A 64-character hex intended as
MEMO_HASHwasmeasured 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 theMEMO_*limit constants. Validatesnone,text(28 bytes),id(unsigned 64-bit),hashandreturn(64 hex chars).
src/types/index.ts—MemoTypeandMemoInput;memo?: stringwidenedto
memo?: string | MemoInputon the input params.src/errors/codes.ts—TX_INVALID_MEMOadded to the registry.validateMemoInputandbuild via
buildMemo.docs/memo-validation.md(new) — rules per type, thevalidation.reasontable, and migration notes.
Error codes
Memo failures on the throwing path now report
TX_INVALID_MEMO, which is in theregistry, so
isKnownErrorCode()recognises it anddescribeError()returns realguidance instead of the unknown-code fallback.
validation.reasondistinguishesunsupported_typefromtoo_long,not_unsigned_integer,out_of_range,invalid_lengthandnot_hexadecimal.ValidationErrorCodeinsrc/payments/validation.tsis a separate publictaxonomy for the non-throwing
validateSendXLMParamspath, with its ownINVALID_*naming. It is deliberately left unchanged, sodocs/api-reference.mdis untouched.
Backwards compatibility
texteverywhere. No caller needs changes.validateMemois unchanged, still exported, and its tests still pass.PaymentPreview.memoTypeare additive.TX_INVALID_MEMOinstead of theunregistered
INVALID_MEMO. The text-memo message text is unchanged.Previews
PaymentPreviewgained an optionalmemoType, mirroring howTransactionSummaryalready exposesmemo+memoTypeon the read side, sopreviews and fetched transactions describe memos the same way.
memostays astring.
Tests
29 new tests in
tests/memo-validation.test.ts: all five types accepted withvalid input; text measured in bytes not characters;
idrejecting negative,fractional, non-numeric and above 2^64-1;
hash/returnrejecting wrong lengthand non-hex; an unsupported type reporting
unsupported_typerather than alength error;
TX_INVALID_MEMObeing registry-known;buildMemoproducing theright Stellar memo per type; and the plain-string form behaving exactly as before.
Verification
lint,check:circular(40 modules, no cycles) andbuildall 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: samefailures in the same five files. This branch adds exactly the 29 new passing
tests and introduces no regressions.