Skip to content

react: transaction hooks incompatible with custom ABI contracts #7646

@alecananian

Description

@alecananian

The mutation functions from useSendAndConfirmTransaction (or useSendTransaction / useSendBatchTransactions) are incompatible with contracts created with the abi field provided.

Observed in SDK v5.105.8

Example

import { getContract, prepareContractCall, ZERO_ADDRESS } from "thirdweb";
import { useSendAndConfirmTransaction } from "thirdweb/react";

const contract = getContract({
	client,
	chain: baseSepolia,
	address: ZERO_ADDRESS,
	abi: [{
		type: "function",
		name: "testFunction",
		inputs: [
			{
				name: "input1",
				type: "uint256",
				internalType: "uint256",
			},
		],
		outputs: [],
		stateMutability: "nonpayable",
	}],
});

const transaction = prepareContractCall({
	contract,
	method: "testFunction",
	params: [0n],
});

await sendAndConfirmTransaction(transaction);

The above code results in a type error on the last line:

Argument of type 'PreparedTransaction<readonly [{ readonly type: "function"; readonly name: "testFunction"; readonly inputs: readonly [{ readonly name: "input1"; readonly type: "uint256"; readonly internalType: "uint256"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }], { ...; }, PrepareTransactionOptions>' is not assignable to parameter of type 'PreparedTransaction'.
  Type 'PreparedTransaction<readonly [{ readonly type: "function"; readonly name: "testFunction"; readonly inputs: readonly [{ readonly name: "input1"; readonly type: "uint256"; readonly internalType: "uint256"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }], { ...; }, PrepareTransactionOptions>' is not assignable to type '{ __preparedMethod?: (() => Promise<PreparedMethod<AbiFunction>>) | undefined; __contract?: Readonly<ContractOptions<[], `0x${string}`>> | undefined; }'.
    Types of property '__contract' are incompatible.
      Type 'Readonly<ContractOptions<readonly [{ readonly type: "function"; readonly name: "testFunction"; readonly inputs: readonly [{ readonly name: "input1"; readonly type: "uint256"; readonly internalType: "uint256"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }], `0x${string}`>> | undefined' is not assignable to type 'Readonly<ContractOptions<[], `0x${string}`>> | undefined'.
        Type 'Readonly<ContractOptions<readonly [{ readonly type: "function"; readonly name: "testFunction"; readonly inputs: readonly [{ readonly name: "input1"; readonly type: "uint256"; readonly internalType: "uint256"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }], `0x${string}`>>' is not assignable to type 'Readonly<ContractOptions<[], `0x${string}`>>'.
          Types of property 'abi' are incompatible.
            Type 'readonly [{ readonly type: "function"; readonly name: "testFunction"; readonly inputs: readonly [{ readonly name: "input1"; readonly type: "uint256"; readonly internalType: "uint256"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }] | undefined' is not assignable to type '[] | undefined'.
              The type 'readonly [{ readonly type: "function"; readonly name: "testFunction"; readonly inputs: readonly [{ readonly name: "input1"; readonly type: "uint256"; readonly internalType: "uint256"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }]' is 'readonly' and cannot be assigned to the mutable type '[]'.ts(2345)

Importing the ABI from another file or adding as const to the end don't resolve the type error.

Workarounds

The following workarounds do not produce type errors:

Using method instead of abi

import { getContract, prepareContractCall, ZERO_ADDRESS } from "thirdweb";
import { useSendAndConfirmTransaction } from "thirdweb/react";

const { mutateAsync: sendAndConfirmTransaction } = useSendAndConfirmTransaction();

const contract = getContract({
	client,
	chain: baseSepolia,
	address: ZERO_ADDRESS,
});

const transaction = prepareContractCall({
	contract,
	method: {
		type: "function",
		name: "testFunction",
		inputs: [
			{
				name: "input1",
				type: "uint256",
				internalType: "uint256",
			},
		],
		outputs: [],
		stateMutability: "nonpayable",
	},
	params: [0n],
});

await sendAndConfirmTransaction(transaction);

Using sendAndConfirmTransaction imported from core instead of React hook

import { getContract, prepareContractCall, sendAndConfirmTransaction, ZERO_ADDRESS } from "thirdweb";
import { useActiveAccount } from "thirdweb/react";

const account = useActiveAccount();

const contract = getContract({
	client,
	chain: baseSepolia,
	address: ZERO_ADDRESS,
	abi: [{
		type: "function",
		name: "testFunction",
		inputs: [
			{
				name: "input1",
				type: "uint256",
				internalType: "uint256",
			},
		],
		outputs: [],
		stateMutability: "nonpayable",
	}],
});

const transaction = prepareContractCall({
	contract,
	method: "testFunction",
	params: [0n],
});

await sendAndConfirmTransaction({
	account,
	transaction,
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions