diff --git a/src/abi/calldata/encoder.ts b/src/abi/calldata/encoder.ts index 63a792d..431add8 100644 --- a/src/abi/calldata/encoder.ts +++ b/src/abi/calldata/encoder.ts @@ -87,7 +87,15 @@ function encodeImpl(to: number[], data: CalldataEncodable) { switch (typeof data) { case "number": { if (!Number.isInteger(data)) { - reportError("floats are not supported", data); + if (Number.isFinite(data) && Math.floor(data) === data) { + // Safe: float with no fractional part (e.g. 1.0 → 1) + encodeNum(to, BigInt(Math.trunc(data))); + return; + } + throw new Error( + `calldata encoding error: float value '${data}' is not supported. ` + + `Convert to an integer or pass as a string instead.` + ); } encodeNum(to, BigInt(data)); return; diff --git a/tests/calldata-encoder.test.ts b/tests/calldata-encoder.test.ts new file mode 100644 index 0000000..87c3e33 --- /dev/null +++ b/tests/calldata-encoder.test.ts @@ -0,0 +1,27 @@ +import { describe, it, expect } from "vitest"; +import { encode } from "../src/abi/calldata/encoder"; +import { decode } from "../src/abi/calldata/decoder"; + +describe("calldata encoder - float handling", () => { + it("should encode integer numbers correctly", () => { + const encoded = encode(42); + const decoded = decode(encoded); + expect(decoded).toBe(42n); + }); + + it("should encode float with no fractional part as integer (e.g. 1.0)", () => { + const encoded = encode(1.0); + const decoded = decode(encoded); + expect(decoded).toBe(1n); + }); + + it("should throw descriptive error for true float values", () => { + expect(() => encode(1.5)).toThrow( + "calldata encoding error: float value '1.5' is not supported" + ); + }); + + it("should throw descriptive error for NaN", () => { + expect(() => encode(NaN)).toThrow(); + }); +});