From 36b2783fd115d8eecf3e7a5da5c6ce0dfc4fe2ff Mon Sep 17 00:00:00 2001 From: ehonrie Date: Tue, 25 Aug 2026 22:00:10 +0100 Subject: [PATCH] feat: update on the issue 608 --- src/index.ts | 2 ++ src/utils.ts | 23 +++++++++++++++++++++++ test/utils.test.ts | 32 +++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 2fe2b4a..7305758 100644 --- a/src/index.ts +++ b/src/index.ts @@ -348,6 +348,8 @@ export { watchContractUpgrade } from "./upgrade.js"; export { calculateFee } from "./fee.js"; +export { formatAddress } from "./utils.js"; + export { resolveToken } from "./token.js"; export { watchExpiry } from "./watcher.js"; diff --git a/src/utils.ts b/src/utils.ts index 08a44f9..f5f9fe8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,6 +3,7 @@ */ import { Invoice } from "./types"; import { Account, MuxedAccount, StrKey } from "@stellar/stellar-sdk"; +import { StellarSplitError } from "./errors.js"; /** Number of decimal places used by Stellar token amounts (stroops). */ const STROOPS_PER_UNIT = 10_000_000n; @@ -87,6 +88,28 @@ export function truncateAddress(address: string, chars = 4): string { return `${address.slice(0, chars)}...${address.slice(-chars)}`; } +/** + * Format a Stellar address for display, e.g. "GABCD...WXYZ". + * + * @throws {StellarSplitError} with code `INVALID_RECIPIENT` if `address` is + * shorter than `leading + trailing + 3`. + */ +export function formatAddress( + address: string, + opts?: { leading?: number; trailing?: number } +): string { + const leading = opts?.leading ?? 5; + const trailing = opts?.trailing ?? 4; + if (address.length < leading + trailing + 3) { + throw new StellarSplitError( + `Address too short to format: ${address}`, + "INVALID_RECIPIENT", + { address, leading, trailing } + ); + } + return `${address.slice(0, leading)}...${address.slice(-trailing)}`; +} + /** * Validates if a caller is in the invoice's allowed callers list. */ diff --git a/test/utils.test.ts b/test/utils.test.ts index 2545e1a..703aadb 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -5,7 +5,9 @@ import { addressesEqual, toMuxedAddress, fromMuxedAddress, + formatAddress, } from "../src/utils.js"; +import { StellarSplitError } from "../src/errors.js"; import { Keypair } from "@stellar/stellar-sdk"; describe("utils", () => { @@ -68,10 +70,38 @@ describe("utils", () => { const address = validGAddress1; const id = 1234n; const muxed = toMuxedAddress(address, id); - + const parsed = fromMuxedAddress(muxed); expect(parsed.address).toBe(address); expect(parsed.id).toBe(id); }); }); + + describe("formatAddress", () => { + it("formats with default leading/trailing", () => { + expect(formatAddress("GABCDEFGHIJKLMNOPQRSTUVWXYZ")).toBe("GABCD...WXYZ"); + }); + + it("formats with custom leading/trailing", () => { + expect(formatAddress("GABCDEFGHIJKLMNOPQRSTUVWXYZ", { leading: 2, trailing: 3 })).toBe("GA...XYZ"); + }); + + it("throws SdkError with code INVALID_RECIPIENT when address is too short", () => { + expect(() => formatAddress("GABCDEF")).toThrow(StellarSplitError); + try { + formatAddress("GABCDEF"); + throw new Error("expected formatAddress to throw"); + } catch (err) { + expect(err).toBeInstanceOf(StellarSplitError); + expect((err as StellarSplitError).code).toBe("INVALID_RECIPIENT"); + } + }); + + it("formats a full-length valid Stellar address correctly", () => { + const address = validGAddress1; + expect(address.length).toBe(56); + const formatted = formatAddress(address); + expect(formatted).toBe(`${address.slice(0, 5)}...${address.slice(-4)}`); + }); + }); });