Why does the USDC transferWithAuthorisation method work inconsistently? - ethereum

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.

Related

Is there a way to get the transaction fees on uniswap and sushiswap_

I'm building a trading bot and I need to get the cost of the swap transaction on uniswap and sushiswap. But I cant find anything that can help me get it from an API or something similar.
I tried looking at the docs of uniswap and sushiswap but they only talked about how they calculate the fees but not about if there was any way to get them using the SDK or something similar.
Using web3.js, you can estimate the cost in gas units, and then multiply by the gas price, to get the transaction cost in ETH.
Simplified example estimating execution cost of function foo():
// how many gas units is the transaction going to cost
const gasUnits = await myContract.methods.foo().estimateGas();
// price (recommended by your node) of each gas unit in wei
const gasPrice = await web3.eth.getGasPrice();
Docs:
https://web3js.readthedocs.io/en/v1.8.2/web3-eth-contract.html#methods-mymethod-estimategas
https://web3js.readthedocs.io/en/v1.8.2/web3-eth.html#getgasprice

Setting gas for transaction on Ethereum when interacting with smart contract

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

Why my truffle deploy fails due to insufficient funds?

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.

Solidity gas estimation - always out of gas when setting to 0

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.

What gasPrice to use to deploy contract on congested ethereum mainnet

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.