diff --git a/src/utils/unit-conversion.utils.ts b/src/utils/unit-conversion.utils.ts index 6cd186f..766b150 100644 --- a/src/utils/unit-conversion.utils.ts +++ b/src/utils/unit-conversion.utils.ts @@ -18,7 +18,11 @@ const STROOP_DIVISOR = new Decimal(STROOPS_PER_XLM); * stroopsToXlm("10000000") // "1.0000000" */ export function stroopsToXlm(stroops: bigint | string): string { - return new Decimal(stroops.toString()).dividedBy(STROOP_DIVISOR).toFixed(STROOP_DECIMALS); + const dec = new Decimal(stroops.toString()); + if (dec.isNaN()) { + throw new TypeError(`Invalid stroops amount: ${stroops}`); + } + return dec.dividedBy(STROOP_DIVISOR).toFixed(STROOP_DECIMALS); } /** @@ -35,5 +39,9 @@ export function stroopsToXlm(stroops: bigint | string): string { * xlmToStroops(1) // 10_000_000n */ export function xlmToStroops(xlm: string | number): bigint { - return BigInt(new Decimal(xlm).times(STROOP_DIVISOR).toFixed(0, Decimal.ROUND_DOWN)); + const dec = new Decimal(xlm); + if (dec.isNaN()) { + throw new TypeError(`Invalid XLM amount: ${xlm}`); + } + return BigInt(dec.times(STROOP_DIVISOR).toFixed(0, Decimal.ROUND_DOWN)); } diff --git a/tests/unit/utils/unit-conversion.test.ts b/tests/unit/utils/unit-conversion.test.ts new file mode 100644 index 0000000..c231876 --- /dev/null +++ b/tests/unit/utils/unit-conversion.test.ts @@ -0,0 +1,73 @@ +import { stroopsToXlm, xlmToStroops } from "../../../src/utils/unit-conversion.utils"; + +describe("Unit Conversion Utilities", () => { + describe("stroopsToXlm", () => { + it('should convert 0 stroops (bigint) to "0.0000000"', () => { + expect(stroopsToXlm(0n)).toBe("0.0000000"); + }); + + it('should convert 0 stroops (string) to "0.0000000"', () => { + expect(stroopsToXlm("0")).toBe("0.0000000"); + }); + + it('should convert 1 stroop (bigint) to "0.0000001"', () => { + expect(stroopsToXlm(1n)).toBe("0.0000001"); + }); + + it('should convert 1 stroop (string) to "0.0000001"', () => { + expect(stroopsToXlm("1")).toBe("0.0000001"); + }); + + it('should convert 10,000,000 stroops to "1.0000000"', () => { + expect(stroopsToXlm(10000000n)).toBe("1.0000000"); + expect(stroopsToXlm("10000000")).toBe("1.0000000"); + }); + + it("should convert 100,000 XLM (1,000,000,000,000 stroops) correctly", () => { + expect(stroopsToXlm(1000000000000n)).toBe("100000.0000000"); + expect(stroopsToXlm("1000000000000")).toBe("100000.0000000"); + }); + + it("should handle fractional representation without precision loss", () => { + expect(stroopsToXlm(123456789n)).toBe("12.3456789"); + }); + + it("should throw an Error for non-numeric input strings", () => { + expect(() => stroopsToXlm("invalid")).toThrow(); + }); + }); + + describe("xlmToStroops", () => { + it("should convert 0 XLM (number) to 0n", () => { + expect(xlmToStroops(0)).toBe(0n); + }); + + it("should convert 0 XLM (string) to 0n", () => { + expect(xlmToStroops("0")).toBe(0n); + }); + + it("should convert 0.0000001 XLM to 1n stroop", () => { + expect(xlmToStroops(0.0000001)).toBe(1n); + expect(xlmToStroops("0.0000001")).toBe(1n); + }); + + it("should convert 1 XLM to 10,000,000n stroops", () => { + expect(xlmToStroops(1)).toBe(10000000n); + expect(xlmToStroops("1")).toBe(10000000n); + }); + + it("should convert 100,000 XLM to 1,000,000,000,000n stroops", () => { + expect(xlmToStroops(100000)).toBe(1000000000000n); + expect(xlmToStroops("100000")).toBe(1000000000000n); + }); + + it("should prevent floating-point precision loss for tricky decimals", () => { + expect(xlmToStroops("12.3456789")).toBe(123456789n); + expect(xlmToStroops(0.1 + 0.2)).toBe(3000000n); + }); + + it("should throw an Error for non-numeric input strings", () => { + expect(() => xlmToStroops("invalid")).toThrow(); + }); + }); +});