I need to estimate the gas for an erc20 transfer for a wallet that currently has no eth in it. I am trying to pay the lowest fee possible, so I am calculating the maxPriorityFeePerGas
and maxFeePerGas
with a formula. The problem is the estimate_gas function will throw an error if I use the contract
method with the max_fee and max_priority_fee specified:
maxPriorityFeePerGas, maxFeePerGas = eip1559gas.estimate_gas_fees(self.web3, speed='slow')
unicorns = self.web3.eth.contract(address=tx.contract_address, abi=EIP20_ABI)
unicorns.functions.transfer(to_address, qty).estimateGas(
{'from': '0xB97Fbf5046688aD1A987B4F85A857ded99f82c71', 'maxPriorityFeePerGas': float_to_hex(web3.fromWei(max_fee_priority,'gwei')), 'maxFeePerGas': float_to_hex(web3.fromWei(max_fee, 'gwei'))})
ValueError: {'code': -32000, 'message': 'gas required exceeds allowance (0)'}
But not without those variables, as this works fine:
est = unicorns.functions.transfer(to_address, qty).estimateGas(
{'from': from_address})
So I tried using the web3.eth
method:
w3.eth.estimate_gas({'to': '0xAe44852e3948ebC351Fa7C31dD341F7BD7534c87', 'from': '0xB97Fbf5046688aD1A987B4F85A857ded99f82c71', "data": unicorns.encodeABI('transfer', args=('0xAe44852e3948ebC351Fa7C31dD341F7BD7534c87', qty))})
That gives an estimate that is too low every time, and then the transaction fails: 21644
So what I have been doing as a workaround is just using a static address that I know does have etherum in it, and that works:
est = unicorns.functions.transfer(to_address, sender_bal).estimate_gas(
{'from': '0x7612E93FF157d1973D0f95Be9E4f0bdF93BAf0DF', 'maxPriorityFeePerGas': max_priority_fee_per_gas, 'maxFeePerGas': max_fee_per_gas}) # address that has eth in it
But then this is not the most accurate way to do it because the gas required could be different depending on the address (something to do with the nonce if I understand correctly). I would like to be able to calculate this dynamically, and accurately.
What is the correct way to do this? I'd like to have a function that i can plug in the address and value to like:
def estimate_gas_erc20(contract_address, from_address, to_address):
maxPriorityFeePerGas, maxFeePerGas = eip1559gas.estimate_gas_fees(self.web3, speed='slow')
unicorns = self.web3.eth.contract(address=contract_address, abi=EIP20_ABI)
sender_bal = unicorns.functions.balanceOf(from_address).call()
if sender_bal > 0:
est = unicorns.functions.transfer(to_address, sender_bal).estimate_gas(
{'from': from_address, 'maxPriorityFeePerGas': max_priority_fee_per_gas, 'maxFeePerGas': max_fee_per_gas})
cp.normal(f'Est for {contract_address}: {est}')