node.jstypescriptethereumethers.jserc20

How can I get the estimated gas fee for a contract method?


I want to fetch an estimated gas consumption for an ERC20 method, particularly the "transfer" one.

According to ethers.js docs, the "BaseContractMethod" has an "estimateGas" method which, receiving an array of params, should return a bigint.

When I run my code, I get this error:

Error: no matching fragment (operation="fragment", code=UNSUPPORTED_OPERATION, version=6.6.0)

This is the code I'm writing:

import {
    JsonRpcProvider,
    Wallet,
    Contract,
    ContractTransactionResponse,
    ContractTransactionReceipt,
} from 'ethers';

import { tokenABI as contractAbi } from './EthereumClientTokenABI';


const provider = new JsonRpcProvider(
    (process.env.ETHEREUM_PROVIDER_URL ||
        'https://rpc2.sepolia.org') as string
);
const contractAddress = (process.env.ETHEREUM_CONTRACT_ADDRESS ||
    'myContractAddress') as string;
const contract = new Contract(contractAddress, contractAbi);

// signer wallet
const privateKey = 'senderPk';
const wallet = new Wallet(privateKey, provider);
const contract = contract.connect(wallet) as Contract;

contract.transfer.estimateGas([addressTo, amount]).then((data: any) => console.log(data));

This is the ABI I'm using:

const tokenABI = [
    {
        inputs: [
            { internalType: 'string', name: 'name_', type: 'string' },
            { internalType: 'string', name: 'symbol_', type: 'string' },
            { internalType: 'uint8', name: 'decimals_', type: 'uint8' },
            {
                internalType: 'uint256',
                name: 'initialBalance_',
                type: 'uint256',
            },
            {
                internalType: 'address payable',
                name: 'feeReceiver_',
                type: 'address',
            },
        ],
        stateMutability: 'payable',
        type: 'constructor',
    },
    {
        anonymous: false,
        inputs: [
            {
                indexed: true,
                internalType: 'address',
                name: 'owner',
                type: 'address',
            },
            {
                indexed: true,
                internalType: 'address',
                name: 'spender',
                type: 'address',
            },
            {
                indexed: false,
                internalType: 'uint256',
                name: 'value',
                type: 'uint256',
            },
        ],
        name: 'Approval',
        type: 'event',
    },
    {
        anonymous: false,
        inputs: [
            {
                indexed: true,
                internalType: 'address',
                name: 'from',
                type: 'address',
            },
            {
                indexed: true,
                internalType: 'address',
                name: 'to',
                type: 'address',
            },
            {
                indexed: false,
                internalType: 'uint256',
                name: 'value',
                type: 'uint256',
            },
        ],
        name: 'Transfer',
        type: 'event',
    },
    {
        inputs: [
            { internalType: 'address', name: 'owner', type: 'address' },
            { internalType: 'address', name: 'spender', type: 'address' },
        ],
        name: 'allowance',
        outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
        stateMutability: 'view',
        type: 'function',
    },
    {
        inputs: [
            { internalType: 'address', name: 'spender', type: 'address' },
            { internalType: 'uint256', name: 'amount', type: 'uint256' },
        ],
        name: 'approve',
        outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
        stateMutability: 'nonpayable',
        type: 'function',
    },
    {
        inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
        name: 'balanceOf',
        outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
        stateMutability: 'view',
        type: 'function',
    },
    {
        inputs: [],
        name: 'decimals',
        outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
        stateMutability: 'view',
        type: 'function',
    },
    {
        inputs: [
            { internalType: 'address', name: 'spender', type: 'address' },
            {
                internalType: 'uint256',
                name: 'subtractedValue',
                type: 'uint256',
            },
        ],
        name: 'decreaseAllowance',
        outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
        stateMutability: 'nonpayable',
        type: 'function',
    },
    {
        inputs: [
            { internalType: 'address', name: 'spender', type: 'address' },
            { internalType: 'uint256', name: 'addedValue', type: 'uint256' },
        ],
        name: 'increaseAllowance',
        outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
        stateMutability: 'nonpayable',
        type: 'function',
    },
    {
        inputs: [],
        name: 'name',
        outputs: [{ internalType: 'string', name: '', type: 'string' }],
        stateMutability: 'view',
        type: 'function',
    },
    {
        inputs: [],
        name: 'symbol',
        outputs: [{ internalType: 'string', name: '', type: 'string' }],
        stateMutability: 'view',
        type: 'function',
    },
    {
        inputs: [],
        name: 'totalSupply',
        outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
        stateMutability: 'view',
        type: 'function',
    },
    {
        inputs: [
            { internalType: 'address', name: 'recipient', type: 'address' },
            { internalType: 'uint256', name: 'amount', type: 'uint256' },
        ],
        name: 'transfer',
        outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
        stateMutability: 'nonpayable',
        type: 'function',
    },
    {
        inputs: [
            { internalType: 'address', name: 'sender', type: 'address' },
            { internalType: 'address', name: 'recipient', type: 'address' },
            { internalType: 'uint256', name: 'amount', type: 'uint256' },
        ],
        name: 'transferFrom',
        outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
        stateMutability: 'nonpayable',
        type: 'function',
    },
];

export { tokenABI };

I managed to make transactions with this configuration, so I think it's not a configuration related problem. I would like to understand what is the error I'm getting and if there is something wrong with my approach to calculate the gas.

I'm working over a testnet on this URL: 'https://rpc2.sepolia.org'

Thanks in advance! Regards


Solution

  • It turned out that this line:

    contract.transfer.estimateGas([addressTo, amount]).then((data: any) => console.log(data));
    

    Should be like this:

    contract.transfer.estimateGas(addressTo, amount).then((data: any) => console.log(data));
    

    I asked at Discord channel of ethers and got a immediate answer, so any doubt you can freely ask there.