Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

web3.eth.Contract.methods.myMethod() does not accept to insert any parameters. #6275

Open
hubts opened this issue Jul 12, 2023 · 10 comments
Open
Labels

Comments

@hubts
Copy link

hubts commented Jul 12, 2023

Expected behavior

  • Expect web3.eth.Contract.methods.myMethod(myParam) works with parameters.
  • The expectation behavior is explained in comments like below.

image

Actual behavior

  • I implemented smart contract in solidity, and already deployed it to Goerli test network.
  • ABI file was extracted, and I added the file into my code repository.
  • Thus, ABI file was OK. However, the below things are bothering me.
  • web3.eth.Contract.methods.setSystemAddress(address) does not allow the parameter (see the below image).
  • The error says You need 0 arguments, but you got 1 argument..

image

Steps to reproduce the behavior

  1. Setting as below Environment.
  2. Get ABI file into web3.eth.Contract whatever you have to generate Contract.
  3. Call web3.eth.Contract.methods.yourMethod with some parameters.
  4. The syntax does not allow you insert any parameters.

Logs

Sorry, the compile cannot be processed, any error logs cannot be provided.

Environment

  • Use yarn (classic v1) package manager
  • Use NestJS boilerplate with Node.js version 19.16.1 (also in 16.15.1)
  • Use web3 package with version 4.0.2 (maybe recent version)
    image
  • MacOS (M1 ChipSet)
@luu-alex
Copy link
Contributor

Hi there, thank you for submitting this issue. https://docs.web3js.org/guides/smart_contracts/infer_contract_types_guide/
When you define your abi make sure to define it as const like in the example above.
So in your case it would be
const abiFile = .... as const;.
This will fix your methods and allow parameters. Let me know if you need more help :)

@luu-alex luu-alex added the 4.x 4.0 related label Jul 12, 2023
@hubts
Copy link
Author

hubts commented Jul 13, 2023

Thank you for your quick answer. Unfortunately, I read the link, and follow some guides, however, it did not work.

As your answer, I tried:
image
However, the error occurs that "const" assertion can be applied to ...

Then, I tried with the link's answer like:
image

This does not occur any errors on it, however, the "no parameter" problem still occurs.

image

I think with your comment, the error may occur because the type did not set from contract ABI. However, my ABI file was extracted by "Remix" and it is saved in .json file well. Here is a log to print of ABI file in the variable abiFile. (The object is wrapped with array like other ABI files.)

image image

By the way, the problem is still bothering me.

@avkos
Copy link
Contributor

avkos commented Jul 18, 2023

Interesting case. The problem is you read the file (not import) and then convert it to const. I will investigate it.

@avkos
Copy link
Contributor

avkos commented Jul 19, 2023

@hubts
So the main problem is the Typescript can't recognize a type when you use a dynamic import. My vision to solve the problem:
1 option:
convert json file to a typescript file like this one and then use it in your contract initialization.

2 option:
create ABI type and assign to your imported json

type MyAbi = readonly [{
   inputs: [
                   {
                        internalType: 'address';
                        name: 'to';
                        type: 'address';
                   },
                   {
                        internalType: 'uint256';
                        name: 'amount';
                        type: 'uint256';
                   },
];
   name: 'transfer';
   outputs: [
                   {
                       internalType: 'bool';
                       name: '';
                       type: 'bool';
                   },
                  ];
   stateMutability: 'nonpayable';
   type: 'function';
}];

const abi = JSON.parse(fs.readFileSync('./ERC20Token.json', 'utf-8')).abi as unknown as MyAbi;
const contract = new Contract(abi);

contract.methods.transfer('0xe4beef667408b99053dc147ed19592ada0d77f59', 12);

@rickiey
Copy link

rickiey commented Jul 21, 2023

I encountered the same problem

@Muhammad-Altabba
Copy link
Contributor

Hello @rickiey ,
We will look more into this.
However, in the mean time as a fast fix you can try:
(contract.methods.transfer as any)('0xe4beef667408b99053dc147ed19592ada0d77f59', 12); it is ugly we know. And for this will try to improve.

@hubts
Copy link
Author

hubts commented Jul 31, 2023

Hello, @avkos
Thank you for your detailed reply. First of all, the type problem you told me seems to be correct. Below are the results of my own experience with your solutions.

Option 1. Declaring a JSON file as a variable doesn't seem to work.

Like the link, it was declared as a const variable and used as a parameter for Contract. (Web3Contract is my alias for Contract)

image

image

Unfortunately, still not accepting argument.

Option 2. Creating an ABI type works for now.

I declared the const variable in Option 1 as type. I used the type to parse JSON file. Then, Contract.methods finds the type and allows argument!

image

image

Thank you for solving my problem.
However, there are still questions left.

Option 1 did not work by declaring a const variable, but it is working after declaring as type in Option 2. In my thinking, the exact contract function name and arguments cannot be recognized by the type found with the variable (abi) of Contract (as Option 1). In other words, I should specify the function name and arguments using the type (as Option 2).

One thing I'm curious about is that if I do this, after I implement a contract, I will not only make the ABI json, but also copy to declare as a type. There is no exact value from type, so I should read the JSON file to get value. This means that I need to manage and match the two files, ABI json file (value) and ABI typescript file (type).

Is this the right way?

Anyway, this problem has been solved and I can continue the project!

@tadpole2077
Copy link

For Angular and React typescript projects the issue is still active, with a workaround as outlined above.

Additional steps still required - to extract the abi from a contract JSON artefact and manually assign as const fooAbi = [ xxx ] as const within your code.

Would be great if we could find a more seamless solution for typescript frameworks to pull directly from the full JSON contract file and avoid the extra manual work per contract.
Just to recap - extracting the abi from the full JSON artefact using either import or require , encapsulating with [] as const, will result in lost method arguments.

@kevinProground
Copy link

Same problem, fixed it by using 'as const' at the abi.
const nonceAbi = [
{
inputs: [{ internalType: 'address', name: '', type: 'address' }],
name: 'nonces',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
] as const;

@awais-kaleem-blocksdev
Copy link

import React from "react";
import { IERC20_ABI } from "../ABI/main-abis/IERC20";
import { createPublicClient, custom, encodeFunctionData } from "viem";
import { hardhat } from "viem/chains";

function useSimulateContract() {
  // Define the custom RPC URL
  const CUSTOM_RPC_URL = "http://0.0.0.0:8545"; // Replace with your valid RPC URL

  // Create a public client using the custom RPC
  const client = createPublicClient({
    chain: hardhat,
    transport: custom({
      async request({ method, params }) {
        const response = await fetch(CUSTOM_RPC_URL, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            jsonrpc: "2.0",
            method,
            params,
            id: Math.floor(Math.random() * 100000),
          }),
        });

        if (!response.ok) {
          throw new Error(`RPC Error: ${response.statusText}`);
        }

        const json = await response.json();
        if (json.error) {
          throw new Error(`RPC Error: ${json.error.message}`);
        }
        return json.result;
      },
    }),
  });

  const simulate = async () => {
    try {
      console.log("🔄 Simulating contract call...");

      // Correctly encode function data
      const encodedData = encodeFunctionData({
        abi: IERC20_ABI,
        functionName: "transfer",
        args: ["0x9B56caf2981414C7CDBc4F3FD89e8fA016fEf0E0", BigInt(15)],
      });

      // Use `call` for simulation
      const result = await client.call({
        to: "0xFCc5c47bE19d06BF83eB04298b026F81069ff65b", // Contract address
        data: encodedData,
        account: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", // Wallet performing the transfer
      });

      console.log("✅ Simulation Result:", result);
      return result;
    } catch (error) {
      console.error("❌ Simulation failed:", error);
      throw error;
    }
  };

  return simulate;
}

export default useSimulateContract;

tried with viem.sh but getting same error:

ERROR in src/hooks/useSimulateContract.ts:44:46
TS2554: Expected 0 arguments, but got 1.
    42 |
    43 |       // Correctly encode function data
  > 44 |       const encodedData = encodeFunctionData({
       |                                              ^
  > 45 |         abi: IERC20_ABI,
       | ^^^^^^^^^^^^^^^^^^^^^^^^
  > 46 |         functionName: "transfer",
       | ^^^^^^^^^^^^^^^^^^^^^^^^
  > 47 |         args: ["0x9B56caf2981414C7CDBc4F3FD89e8fA016fEf0E0", BigInt(15)],
       | ^^^^^^^^^^^^^^^^^^^^^^^^
  > 48 |       });

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
10 participants