I have enough ETH in the wallet but migration to mainnet fails for illogical reason - not enough funds.
Truffle has strange logic of cost calculation - it deploys Initial migration and my contract (Nft) and then complains that the remaining balance left in the wallet is lower than total upfront cost. Thank you for helping me to understand this.
wallet balance: 0.3981 ETH
upfront cost (gas * price): 0.2755 ETH
deployment cost reported by Truffle: approx.0.26 ETH
remaining balance: 0.1381 ETH
Illogical Error: 0.1381 ETH is lower than upfront cost 0.2755 ETH
truffle-config.js
const HDWalletProvider = require('truffle-hdwallet-provider')
...
live: {
provider: () => new HDWalletProvider(MNEMONIC_LIVE, LIVE_URL),
network_id: 1,
gas: 3450000,
gasPrice: web3.utils.toWei('79', 'gwei'),
confirmations: 1,
timeoutBlocks: 200,
skipDryRun: false,
networkCheckTimeout:1000000
},
Migration dry-run log
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
> block number: 12232671
> block timestamp: 1618329800
> account: 0xbb467DA83d9DB2F10Bb5E6d5C4b48121a62FB80E
> balance: 0.379524194
> gas used: 235234 (0x396e2)
> gas price: 79 gwei
> value sent: 0 ETH
> total cost: 0.018583486 ETH
-------------------------------------
> Total cost: 0.018583486 ETH
3_nft_deploy.js
================
Deploying 'Nft'
----------------
> block number: 12232673
> block timestamp: 1618330490
> account: 0xbb467DA83d9DB2F10Bb5E6d5C4b48121a62FB80E
> balance: 0.138160076
> gas used: 3027724 (0x2e330c)
> gas price: 79 gwei
> value sent: 0 ETH
> total cost: 0.239190196 ETH
Error: sender doesn't have enough funds to send tx. The upfront cost is: 272550000000000000 and the sender's account only has: 138160076000000000
at Migration._deploy (/home/roman/.npm-global/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:103:1)
at process._tickCallback (internal/process/next_tick.js:68:7)
Truffle v5.2.6 (core: 5.2.6)
Node v10.19.0
I had same problem and I was able to contact with truffle support team, they know the issue, here's the answer:
So in doing #4296, #fainashalts discovered that the naïve strategy of doing an eth_estimateGas is insufficient for transactions that revert: in such situations, eth_estimateGas does not provide a quantity in response (it instead errors). This means that Truffle won't be able to proceed with sending the transaction, since it won't have all the information it needs to be able to do so. We need Truffle to be able to send transactions, even if it knows those transactions will revert, because users must be able to inspect such reverted transactions (e.g. via stacktrace inspection, etc.). As a consequence of this, we'll need some additional logic to produce a gas limit value when the estimate cannot be determined via eth_estimateGas.
Best solution for this remains undetermined, but we've uncovered a few options (all specifically relating to the case where eth_estimateGas fails due to revert):
a. Use the block limit (or some value based on the block limit, e.g. blockLimit / 2) as the default transaction gas limit
b. Do a binary search to find the boundary for gas limit between the transaction's failing for "out of gas" and the transaction's failing for "revert", and use that value when sending the transaction to the network.
c. Petition to modify the JSON-RPC and all client implementations so as to ensure eth_estimateGas reports a sensible gas limit value even for transactions that revert
These all seem not-ideal; currently looking for an option (d)
From https://github.com/trufflesuite/truffle/issues/3992
Anyways, you can avoid running dryrun to deploy migration or do what I did which was to adjust gas and gasPrice in order to reduce tx cost and add more funds to my wallet.
If you handle correctly gas and gasPrice, you should not be worried to have more Ethers in your wallet than you really need.
I know, It's not the best solution but works.
Related
The USDC smart contract on Ethereum has a transferWithAuthorisation that any address can call if they have a signature.
However, the method seems to be inconsistent and often fails.
What is the reason for this?
https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48?method=0xe3ee160e
Most of the failures are due to: "Warning! Error encountered during contract execution [execution reverted] "
I debugged some of the failing transactions with Tenderly and learned that they all (or at least those that I debugged) fail on insufficient gas limit.
Each EVM operation costs some predefined amount of gas units. The transaction sender specifies gas limit, and then buys this amount (times gas price) for ETH. If the transaction consumes less gas units than the limit, the difference is refunded.
The transferWithAuthorisation() function seems to cost between 72k and 82k gas units depending on internal code logic (successful transactions: 0x7e..., 0x32..., 0xec...).
However the failing transactions supplied lower gas limit between 59k and 62k (0xd3..., 0xf1..., 0x54...).
So the sender possibly used an incorrect estimation of gas usage, and specified an insufficient limit.
Here is an example of such transaction:
etherscan
It was 569730199030000 Wei on a balance,
I used current gas price(by web3.eth.getGasPrice()) 19888345864 Wei.
So my estimated fee was (19888345864 * 21000) 417655263144000 Wei.
I was trying to send (balance - estimated fee) = 152074935886000 Wei.
The result as you can see "out of gas".
Why it is possible that regular send was required more than 21000 gas? If I understand properly in case if gas price is not enough then miners simply must ignore this tx, but in case if they are agree with the gas price they have to run this transaction normally, and normally sending eth requires gas limit 21000. Where is mistake in my calculations and how to execute such tx properly?
Generally, this often happens when you're trying to send ETH to a contract that either doesn't implement a special function to accept the ETH - or the contract does implement the function but it explicitly rejects the incoming transfer.
Specifically, the first-hand recipient of your transaction is a proxy contract deployed at address 0xB233903ACec807C61eeeCc4F69dd795A617a1732, that redirects the request to a target contract deployed at address 0xd332254f274cc65aa11178b74734e2992b8f349e.
Author of the target contract has not shared its source code, but from the decompiled bytecode it seems to accept incoming ETH transfer only if series of conditions (depending on the payload of the incoming transaction and the state of another contract) is met. Otherwise it rejects the transaction with the revert statement.
def _fallback() payable: # default function
require ext_code.size(0xa24787320ede4cc19d800bf87b41ab9539c4da9d)
static call 0xa24787320ede4cc19d800bf87b41ab9539c4da9d.0x4fef8ec4 with:
gas gas_remaining wei
if not ext_call.success:
revert with ext_call.return_data[0 len return_data.size]
require return_data.size >= 32
delegate ext_call.return_data[0] with:
funct call.data[0 len 4]
gas gas_remaining wei
args call.data[4 len calldata.size - 4]
if not delegate.return_code:
revert with ext_call.return_data[0 len return_data.size]
return ext_call.return_data[0 len return_data.size]
I am using web3-eth-contract package to connect to contract on Ethereum. I am executing it's methods by:
contract.methods
.methodName(ids)
.send({
to: address,
from: address
})
The problem is that I get:
After that I tried to add gasLimit there:
contract.methods
.methodName(ids)
.send({
to: address,
from: address,
gasLimit: 300000,
})
and it worked fine when I use methods that require only simple arguments. When I use methods where I pass array of arguments and there are more arguments than 2 transactions are being cancelled. What should I pass to gasLimit or how can I estimate it so it will work every time?
The gas used to execute the transaction may depend on your parameters, so what you experience is totally reasonable.
Now, to know what gasLimit to set you need to know what the transaction is doing and how much gas it is expected to burn. You can take one of the following approaches:
set the gasLimit very high, so that your transaction is always executed
check the older transactions to the same contract and see how much gas they burnt
use the transaction format after the London Uprade and specify max ETH you are willing to pay for the transaction (maxFeePerGas) instead of setting gasLimit
I'm trying to figure out a solution to this problem, to do with transaction confirmation order and setting values to 0
pragma solidity ^0.5.17;
contract Test {
uint256 amount;
constructor() public {}
function join() public {
amount += 100;
}
function leave() public {
amount -= 100;
}
}
Given these transactions (tested on ropsten):
tx 1) Call Join Confirmed
amount == 100
tx 2) Call Join (gas price 1) Pending
amount == 100 should tx3 get mined first
tx 3) Call Leave (gas price 100) Pending
amount == 0
However tx 2 will always fail with an out of gas error for as long as the amount is set back to 0. This doesn't happen if the value is any higher than 0. My understanding is that it costs more gas to set a value to its 0 state instead of a positive integer, and the gas estimation isn't taking this into account. I've tried delete hoping this would give a gas refund to compensate for the too-low gas limit, but it still failed.
Is there an elegant way to handle this scenario? The only ways I can think of are over-estimating the gas for all join transactions, which has its obvious drawbacks, or never setting amount back to 0.
You are making correct observations.
by setting it to 0 you delete storage, and get gas refund. This is why it takes less amount of gas. But gas refunds have top limit, so you can't use it to store ETH.
It costs 20,000 gas to store one value in a slot (source:https://github.com/ethereum/go-ethereum/blob/d13c59fef0926af0ef0cff0a2e793f95d46442f0/params/protocol_params.go#L41 )
it costs 2,200 gas to load one value from a storage slot (source: https://github.com/ethereum/go-ethereum/blob/d13c59fef0926af0ef0cff0a2e793f95d46442f0/params/protocol_params.go#L89)
That's why you are seeing different gas consumption values.
Just set your gasLimit to some empirically found roughly-estimated value.
Do a trace of your transaction and you will see all gas consumption values.
Now, the way gas refunds work is that during the state transition function, you're asked for the full gas for the run of your contract. During this run, all gas refunds are accumulated in StateDB (temporary state object). At the end of the state transition function, you will get refunds for all storage releases your contract is going to make. This is why you have to set higher gas limit that Etherscan shows, because lets say your contract needs 15,000 gas to run, after storage is released (say for 5,000 gas) , Etherscan will show like the transaction needed 10,000 gas. This is not true because you have got gas refunds at the end, but at the beginning you needed the whole amount of gas (15,000). Gas refunds are sponsored by the miner, his account is going to get less ETH because he is paying you these refunds.
I am attempting to deploy a contract onto the Ethereum mainnet, I have specified:
network_id: 1,
provider: infura,
gas: 5000000,
gasPrice: 140
And I continuously get the errors:
Error: Contract transaction couldn't be found after 50 blocks
or
transaction underpriced
Is this because the mainnet is so congested, miners are not picking up my transaction within the 50 block period?
What gas/gasPrices have other people successfully used on the mainnet?
You can check current gas price at https://ethgasstation.info/ for example. Note that gas price is usually shown in Gwei. So 21 Gwei is 21000000000 wei or 0.000021 eth.
To expand on Andrey's answer, your gas is WAY too low. Historically, you will typically need to pay around 10-20 Gwei to have your transaction mined in an average amount of time. If you can wait 10s of minutes or even hours, you can get away with ~5Gwei. If you need the transaction to execute fast, or if you just want an average transaction time when the network is really congested, you're probably looking at ~40Gwei.
You can programmatically set your gas price based on the median gas price of the most recent mined blocks using web3.eth.getGasPrice(callback). Source.