I am trying to be able to accurately estimate the gas it will take to send an ERC20 token using Ethers js without first needing that token. Currently, I am able to get an estimate though it does not seem to be super accurate. My code is:
const {ethers} = require("ethers");
const provider = new ethers.providers.EtherscanProvider('homestead', 'API_KEY');
const sendGas = async (to, tokenAddress, amount) => {
const abi = [
// Some details about the token
"function name() view returns (string)",
"function symbol() view returns (string)",
// Get the account balance
"function balanceOf(address) view returns (uint)",
// Send some of your tokens to someone else
"function transfer(address to, uint amount)",
// An event triggered whenever anyone transfers to someone else
"event Transfer(address indexed from, address indexed to, uint amount)"
];
const signer = new ethers.Wallet('PRIVATE_KEY');
const account = signer.connect(provider);
const contract = new ethers.Contract(
tokenAddress,
abi,
account
);
const gasCost = await contract.estimateGas.transfer(to, amount)
console.log(parseInt(gasCost, 10));
return gasCost;
}
sendGas('PUBLIC_KEY', '0xa36085F69e2889c224210F603D836748e7dC0088', '0');
When I run the code given the proper inputs it seemingly works as expected. Except the actual gas used and the estimated amount can diverge rather substantially. Firstly, to even have the function execute properly I need to pass the amount as 0 since I want to be able to estimate the gas for tokens that I don't have yet. If I try with a non-zero balance for a token I do not have I get an error for an insufficient balance. My issue is that I need the gas to be accurate to within a few thousand gas but it is currently all over the place. For example, I tried transferring a coin on kovan and got an estimate of 21560 gas, however, it ended up using 35322 gas for the real transaction (and I have seen even large discrepancies). Is this caused by having the amount to send be 0? If so, is there a workaround to get accurate estimates without needing to have the token in my account?
Less important but if anyone has insight it would be appreciated, how do I determine the transfer abi for a token? The one I am using currently is just a standard one provided in the ethers js documentation. Will this work for all tokens? if not, is there a way to get the abi for transfers of any token?