diff --git a/src/transactions/clarity-values.ts b/src/transactions/clarity-values.ts index e0e5156d..77b4a697 100644 --- a/src/transactions/clarity-values.ts +++ b/src/transactions/clarity-values.ts @@ -73,8 +73,12 @@ export function parseArgToClarityValue(arg: unknown): ClarityValue { return boolCV(typedArg.value as boolean); case "principal": return principalCV(typedArg.value as string); - case "buffer": - return bufferCV(Buffer.from(typedArg.value as string, "hex")); + case "buffer": { + // Strip optional 0x/0X prefix — without this, Buffer.from("0x...", "hex") + // silently produces an empty buffer (aibtcdev/landing-page#1012 Finding 2) + const hexStr = (typedArg.value as string).replace(/^0x/i, ""); + return bufferCV(Buffer.from(hexStr, "hex")); + } case "none": return noneCV(); case "some": diff --git a/tests/transactions/clarity-values.test.ts b/tests/transactions/clarity-values.test.ts index fc42cbd9..8db0bbcb 100644 --- a/tests/transactions/clarity-values.test.ts +++ b/tests/transactions/clarity-values.test.ts @@ -210,6 +210,20 @@ describe("parseArgToClarityValue", () => { expect(cv.type).toBe(ClarityType.Buffer); }); + it("should accept 0x-prefixed hex and produce the same bytes as raw hex", () => { + const raw = parseArgToClarityValue({ type: "buffer", value: "deadbeef" }); + const prefixed = parseArgToClarityValue({ type: "buffer", value: "0xdeadbeef" }); + expect(prefixed.type).toBe(ClarityType.Buffer); + expect(cvToString(prefixed)).toBe(cvToString(raw)); + }); + + it("should accept 0X-prefixed hex (uppercase prefix)", () => { + const raw = parseArgToClarityValue({ type: "buffer", value: "deadbeef" }); + const prefixed = parseArgToClarityValue({ type: "buffer", value: "0Xdeadbeef" }); + expect(prefixed.type).toBe(ClarityType.Buffer); + expect(cvToString(prefixed)).toBe(cvToString(raw)); + }); + it("should convert Buffer instance", () => { const buffer = Buffer.from([0xde, 0xad, 0xbe, 0xef]); const cv = parseArgToClarityValue(buffer);