From 505579f7617078ee5b614f274bb82414dec7903f Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Thu, 31 Jul 2025 20:03:06 +1200 Subject: [PATCH 1/2] Fix decodeFunction and decodeError functions --- .changeset/tangy-ghosts-joke.md | 5 ++++ .../thirdweb/src/utils/abi/decodeError.ts | 7 +++++- .../src/utils/abi/decodeFunctionData.test.ts | 25 +++++++++++++++++++ .../src/utils/abi/decodeFunctionData.ts | 6 ++++- .../src/utils/abi/decodeFunctionResult.ts | 6 ++++- 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 .changeset/tangy-ghosts-joke.md create mode 100644 packages/thirdweb/src/utils/abi/decodeFunctionData.test.ts diff --git a/.changeset/tangy-ghosts-joke.md b/.changeset/tangy-ghosts-joke.md new file mode 100644 index 00000000000..8ffe0aef8bf --- /dev/null +++ b/.changeset/tangy-ghosts-joke.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Fix decodeFunction and decodeError functions diff --git a/packages/thirdweb/src/utils/abi/decodeError.ts b/packages/thirdweb/src/utils/abi/decodeError.ts index 21947945115..968748dadfc 100644 --- a/packages/thirdweb/src/utils/abi/decodeError.ts +++ b/packages/thirdweb/src/utils/abi/decodeError.ts @@ -3,6 +3,7 @@ import * as ox__AbiError from "ox/AbiError"; import { resolveContractAbi } from "../../contract/actions/resolve-abi.js"; import type { ThirdwebContract } from "../../contract/contract.js"; import type { Hex } from "../encoding/hex.js"; +import { AbiError } from "ox"; /** * Decodes an error. @@ -32,6 +33,10 @@ export async function decodeError(options: { `No ABI found for contract ${contract.address} on chain ${contract.chain.id}`, ); } - const abiError = ox__AbiError.fromAbi(abi, data) as ox__AbiError.AbiError; + const err = abi.filter((i) => i.type === "error" && AbiError.getSelector(i) === data.slice(0, 10)) + const abiError = err[0] as ox__AbiError.AbiError; + if (!abiError) { + throw new Error(`No ABI function found for selector ${data.slice(0, 10)}`); + } return ox__AbiError.decode(abiError, data); } diff --git a/packages/thirdweb/src/utils/abi/decodeFunctionData.test.ts b/packages/thirdweb/src/utils/abi/decodeFunctionData.test.ts new file mode 100644 index 00000000000..68ad65c4f65 --- /dev/null +++ b/packages/thirdweb/src/utils/abi/decodeFunctionData.test.ts @@ -0,0 +1,25 @@ +import { expect, it } from "vitest"; +import { decodeFunctionData } from "./decodeFunctionData.js"; +import { getContract } from "../../contract/contract.js"; +import { defineChain } from "../../chains/utils.js"; +import { TEST_CLIENT } from "../../../test/src/test-clients.js"; + +it.runIf(process.env.TW_SECRET_KEY)( + "decodes function data correctly", + async () => { + const result = await decodeFunctionData({ + contract: getContract({ + address: "0x9480d58e14b1851a2A3C7aEFAd17D48e31D3F93b", + client: TEST_CLIENT, + chain: defineChain(17177) + }), + data: "0xd8fd8f44000000000000000000000000f117ed9dcc8960062484b781097321c8380cead30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002466353238316131632d363830352d343536622d623738322d38356165326165623336643800000000000000000000000000000000000000000000000000000000" + }); + expect(result).toMatchInlineSnapshot(` + [ + "0xf117ed9dcc8960062484b781097321c8380cead3", + "0x66353238316131632d363830352d343536622d623738322d383561653261656233366438", + ] + `); + }, +); diff --git a/packages/thirdweb/src/utils/abi/decodeFunctionData.ts b/packages/thirdweb/src/utils/abi/decodeFunctionData.ts index b1d651edbe9..7bf0865e989 100644 --- a/packages/thirdweb/src/utils/abi/decodeFunctionData.ts +++ b/packages/thirdweb/src/utils/abi/decodeFunctionData.ts @@ -32,6 +32,10 @@ export async function decodeFunctionData(options: { `No ABI found for contract ${contract.address} on chain ${contract.chain.id}`, ); } - const abiFunction = ox__AbiFunction.fromAbi(abi, data); + const fn = abi.filter((i) => i.type === "function" && ox__AbiFunction.getSelector(i) === data.slice(0, 10)) + const abiFunction = fn[0] as ox__AbiFunction.AbiFunction; + if (!abiFunction) { + throw new Error(`No ABI function found for selector ${data.slice(0, 10)}`); + } return ox__AbiFunction.decodeData(abiFunction, data); } diff --git a/packages/thirdweb/src/utils/abi/decodeFunctionResult.ts b/packages/thirdweb/src/utils/abi/decodeFunctionResult.ts index 02057cff8bc..8f87dae6032 100644 --- a/packages/thirdweb/src/utils/abi/decodeFunctionResult.ts +++ b/packages/thirdweb/src/utils/abi/decodeFunctionResult.ts @@ -32,6 +32,10 @@ export async function decodeFunctionResult(options: { `No ABI found for contract ${contract.address} on chain ${contract.chain.id}`, ); } - const abiFunction = ox__AbiFunction.fromAbi(abi, rest.data); + const fn = abi.filter((i) => i.type === "function" && ox__AbiFunction.getSelector(i) === rest.data.slice(0, 10)) + const abiFunction = fn[0] as ox__AbiFunction.AbiFunction; + if (!abiFunction) { + throw new Error(`No ABI function found for selector ${rest.data.slice(0, 10)}`); + } return ox__AbiFunction.decodeResult(abiFunction, rest.data); } From 2dad5b6455b6511d712b4c67958b78f3abbcb100 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Thu, 31 Jul 2025 20:45:45 +1200 Subject: [PATCH 2/2] lint --- packages/thirdweb/src/utils/abi/decodeError.ts | 6 ++++-- .../src/utils/abi/decodeFunctionData.test.ts | 12 ++++++------ .../thirdweb/src/utils/abi/decodeFunctionData.ts | 6 +++++- .../thirdweb/src/utils/abi/decodeFunctionResult.ts | 10 ++++++++-- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/thirdweb/src/utils/abi/decodeError.ts b/packages/thirdweb/src/utils/abi/decodeError.ts index 968748dadfc..9476fe047a1 100644 --- a/packages/thirdweb/src/utils/abi/decodeError.ts +++ b/packages/thirdweb/src/utils/abi/decodeError.ts @@ -1,9 +1,9 @@ +import { AbiError } from "ox"; import type * as ox__Abi from "ox/Abi"; import * as ox__AbiError from "ox/AbiError"; import { resolveContractAbi } from "../../contract/actions/resolve-abi.js"; import type { ThirdwebContract } from "../../contract/contract.js"; import type { Hex } from "../encoding/hex.js"; -import { AbiError } from "ox"; /** * Decodes an error. @@ -33,7 +33,9 @@ export async function decodeError(options: { `No ABI found for contract ${contract.address} on chain ${contract.chain.id}`, ); } - const err = abi.filter((i) => i.type === "error" && AbiError.getSelector(i) === data.slice(0, 10)) + const err = abi.filter( + (i) => i.type === "error" && AbiError.getSelector(i) === data.slice(0, 10), + ); const abiError = err[0] as ox__AbiError.AbiError; if (!abiError) { throw new Error(`No ABI function found for selector ${data.slice(0, 10)}`); diff --git a/packages/thirdweb/src/utils/abi/decodeFunctionData.test.ts b/packages/thirdweb/src/utils/abi/decodeFunctionData.test.ts index 68ad65c4f65..1af9bd8f3da 100644 --- a/packages/thirdweb/src/utils/abi/decodeFunctionData.test.ts +++ b/packages/thirdweb/src/utils/abi/decodeFunctionData.test.ts @@ -1,19 +1,19 @@ import { expect, it } from "vitest"; -import { decodeFunctionData } from "./decodeFunctionData.js"; -import { getContract } from "../../contract/contract.js"; -import { defineChain } from "../../chains/utils.js"; import { TEST_CLIENT } from "../../../test/src/test-clients.js"; +import { defineChain } from "../../chains/utils.js"; +import { getContract } from "../../contract/contract.js"; +import { decodeFunctionData } from "./decodeFunctionData.js"; it.runIf(process.env.TW_SECRET_KEY)( "decodes function data correctly", async () => { - const result = await decodeFunctionData({ + const result = await decodeFunctionData({ contract: getContract({ address: "0x9480d58e14b1851a2A3C7aEFAd17D48e31D3F93b", client: TEST_CLIENT, - chain: defineChain(17177) + chain: defineChain(17177), }), - data: "0xd8fd8f44000000000000000000000000f117ed9dcc8960062484b781097321c8380cead30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002466353238316131632d363830352d343536622d623738322d38356165326165623336643800000000000000000000000000000000000000000000000000000000" + data: "0xd8fd8f44000000000000000000000000f117ed9dcc8960062484b781097321c8380cead30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002466353238316131632d363830352d343536622d623738322d38356165326165623336643800000000000000000000000000000000000000000000000000000000", }); expect(result).toMatchInlineSnapshot(` [ diff --git a/packages/thirdweb/src/utils/abi/decodeFunctionData.ts b/packages/thirdweb/src/utils/abi/decodeFunctionData.ts index 7bf0865e989..9424f68e93b 100644 --- a/packages/thirdweb/src/utils/abi/decodeFunctionData.ts +++ b/packages/thirdweb/src/utils/abi/decodeFunctionData.ts @@ -32,7 +32,11 @@ export async function decodeFunctionData(options: { `No ABI found for contract ${contract.address} on chain ${contract.chain.id}`, ); } - const fn = abi.filter((i) => i.type === "function" && ox__AbiFunction.getSelector(i) === data.slice(0, 10)) + const fn = abi.filter( + (i) => + i.type === "function" && + ox__AbiFunction.getSelector(i) === data.slice(0, 10), + ); const abiFunction = fn[0] as ox__AbiFunction.AbiFunction; if (!abiFunction) { throw new Error(`No ABI function found for selector ${data.slice(0, 10)}`); diff --git a/packages/thirdweb/src/utils/abi/decodeFunctionResult.ts b/packages/thirdweb/src/utils/abi/decodeFunctionResult.ts index 8f87dae6032..7d4231772cc 100644 --- a/packages/thirdweb/src/utils/abi/decodeFunctionResult.ts +++ b/packages/thirdweb/src/utils/abi/decodeFunctionResult.ts @@ -32,10 +32,16 @@ export async function decodeFunctionResult(options: { `No ABI found for contract ${contract.address} on chain ${contract.chain.id}`, ); } - const fn = abi.filter((i) => i.type === "function" && ox__AbiFunction.getSelector(i) === rest.data.slice(0, 10)) + const fn = abi.filter( + (i) => + i.type === "function" && + ox__AbiFunction.getSelector(i) === rest.data.slice(0, 10), + ); const abiFunction = fn[0] as ox__AbiFunction.AbiFunction; if (!abiFunction) { - throw new Error(`No ABI function found for selector ${rest.data.slice(0, 10)}`); + throw new Error( + `No ABI function found for selector ${rest.data.slice(0, 10)}`, + ); } return ox__AbiFunction.decodeResult(abiFunction, rest.data); }