Skip to content

Commit e441ba4

Browse files
authored
fix: Support missing 'function' prefix in functionName (#748)
1 parent 05bb234 commit e441ba4

File tree

3 files changed

+52
-13
lines changed

3 files changed

+52
-13
lines changed

src/server/routes/contract/write/write.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { type Static, Type } from "@sinclair/typebox";
1+
import { Type, type Static } from "@sinclair/typebox";
22
import type { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { prepareContractCall, resolveMethod } from "thirdweb";
5-
import { type AbiFunction, parseAbiParams } from "thirdweb/utils";
5+
import { parseAbiParams, type AbiFunction } from "thirdweb/utils";
66
import { getContractV5 } from "../../../../utils/cache/getContractv5";
77
import { prettifyError } from "../../../../utils/error";
88
import { queueTransaction } from "../../../../utils/transaction/queueTransation";
@@ -19,17 +19,26 @@ import {
1919
requiredAddress,
2020
walletWithAAHeaderSchema,
2121
} from "../../../schemas/wallet";
22-
import { sanitizeAbi } from "../../../utils/abi";
22+
import { sanitizeAbi, sanitizeFunctionName } from "../../../utils/abi";
2323
import { getChainIdFromChain } from "../../../utils/chain";
2424
import { parseTransactionOverrides } from "../../../utils/transactionOverrides";
2525

2626
// INPUT
2727
const writeRequestBodySchema = Type.Object({
2828
functionName: Type.String({
29-
description: "The function to call on the contract",
29+
description: `The function to call on the contract. It is highly recommended to provide a full function signature, such as "function mintTo(address to, uint256 amount)", to avoid ambiguity and to skip ABI resolution.`,
30+
examples: ["function mintTo(address to, uint256 amount)"],
3031
}),
3132
args: Type.Array(Type.Any(), {
32-
description: "The arguments to call on the function",
33+
description:
34+
"An array of arguments to provide the function. Supports: numbers, strings, arrays, objects. Do not provide: BigNumber, bigint, Date objects",
35+
examples: [
36+
[
37+
1730380951,
38+
"0x09530565aC1Ce08C3621f5B24Fca6d9a76574620",
39+
["a", "b", "c"],
40+
],
41+
],
3342
}),
3443
...txOverridesWithValueSchema.properties,
3544
abi: Type.Optional(abiArraySchema),
@@ -85,7 +94,8 @@ export async function writeToContract(fastify: FastifyInstance) {
8594
let method: AbiFunction;
8695
let params: Array<string | bigint | boolean | object>;
8796
try {
88-
method = await resolveMethod(functionName)(contract);
97+
const functionNameOrSignature = sanitizeFunctionName(functionName);
98+
method = await resolveMethod(functionNameOrSignature)(contract);
8999
params = parseAbiParams(
90100
method.inputs.map((i) => i.type),
91101
args,
@@ -97,6 +107,7 @@ export async function writeToContract(fastify: FastifyInstance) {
97107
"BAD_REQUEST",
98108
);
99109
}
110+
100111
const transaction = prepareContractCall({
101112
contract,
102113
method,

src/server/utils/abi.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import type { Abi } from "thirdweb/utils";
22
import type { AbiSchemaType } from "../schemas/contract";
33

44
export function sanitizeAbi(abi: AbiSchemaType | undefined): Abi | undefined {
5-
if (!abi) return undefined;
5+
if (!abi) {
6+
return undefined;
7+
}
8+
69
return abi.map((item) => {
710
if (item.type === "function") {
811
return {
@@ -15,3 +18,6 @@ export function sanitizeAbi(abi: AbiSchemaType | undefined): Abi | undefined {
1518
return item;
1619
}) as Abi;
1720
}
21+
22+
export const sanitizeFunctionName = (val: string) =>
23+
val.includes("(") && !val.startsWith("function ") ? `function ${val}` : val;

test/e2e/tests/write.test.ts renamed to test/e2e/tests/routes/write.test.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { beforeAll, describe, expect, test } from "bun:test";
22
import assert from "node:assert";
33
import { type Address, stringToHex } from "thirdweb";
44
import { zeroAddress } from "viem";
5-
import type { ApiError } from "../../../sdk/dist/thirdweb-dev-engine.cjs";
6-
import { CONFIG } from "../config";
7-
import type { setupEngine } from "../utils/engine";
8-
import { pollTransactionStatus } from "../utils/transactions";
9-
import { setup } from "./setup";
5+
import type { ApiError } from "../../../../sdk/dist/thirdweb-dev-engine.cjs.js";
6+
import { CONFIG } from "../../config";
7+
import type { setupEngine } from "../../utils/engine";
8+
import { pollTransactionStatus } from "../../utils/transactions";
9+
import { setup } from "../setup";
1010

11-
describe("Write Tests", () => {
11+
describe("/contract/write route", () => {
1212
let tokenContractAddress: string;
1313
let engine: ReturnType<typeof setupEngine>;
1414
let backendWallet: Address;
@@ -183,6 +183,28 @@ describe("Write Tests", () => {
183183
expect(writeTransactionStatus.minedAt).toBeDefined();
184184
});
185185

186+
test("Write to a contract with function signature without prefix", async () => {
187+
const writeRes = await engine.contract.write(
188+
CONFIG.CHAIN.id.toString(),
189+
tokenContractAddress,
190+
backendWallet,
191+
{
192+
functionName: "setContractURI(string uri)",
193+
args: ["https://signature-test.com"],
194+
},
195+
);
196+
197+
expect(writeRes.result.queueId).toBeDefined();
198+
199+
const writeTransactionStatus = await pollTransactionStatus(
200+
engine,
201+
writeRes.result.queueId,
202+
true,
203+
);
204+
205+
expect(writeTransactionStatus.minedAt).toBeDefined();
206+
});
207+
186208
test("Write to a contract with function abi", async () => {
187209
const writeRes = await engine.contract.write(
188210
CONFIG.CHAIN.id.toString(),

0 commit comments

Comments
 (0)