Fix gas estimation (#1944)

* Fix gas estimation for threshold > 4

* Update gas estimation to be more precise

* Add threshold gas costs on transaction creation estimation

Co-authored-by: Daniel Sanchez <daniel.sanchez@gnosis.pm>
This commit is contained in:
nicolas 2021-02-24 16:21:52 -03:00 committed by GitHub
parent ce1ab8b039
commit b4de1b669a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 16 additions and 3 deletions

View File

@ -5,6 +5,7 @@ import {
estimateGasForTransactionCreation, estimateGasForTransactionCreation,
estimateGasForTransactionExecution, estimateGasForTransactionExecution,
MINIMUM_TRANSACTION_GAS, MINIMUM_TRANSACTION_GAS,
GAS_REQUIRED_PER_SIGNATURE,
} from 'src/logic/safe/transactions/gas' } from 'src/logic/safe/transactions/gas'
import { fromTokenUnit } from 'src/logic/tokens/utils/humanReadableValue' import { fromTokenUnit } from 'src/logic/tokens/utils/humanReadableValue'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
@ -229,12 +230,13 @@ export const useEstimateTransactionGas = ({
safeTxGas, safeTxGas,
approvalAndExecution, approvalAndExecution,
}) })
const gasPrice = manualGasPrice ? web3.utils.toWei(manualGasPrice, 'gwei') : await calculateGasPrice() const gasPrice = manualGasPrice ? web3.utils.toWei(manualGasPrice, 'gwei') : await calculateGasPrice()
const gasPriceFormatted = web3.utils.fromWei(gasPrice, 'gwei') const gasPriceFormatted = web3.utils.fromWei(gasPrice, 'gwei')
const estimatedGasCosts = gasEstimation * parseInt(gasPrice, 10) const estimatedGasCosts = gasEstimation * parseInt(gasPrice, 10)
const gasCost = fromTokenUnit(estimatedGasCosts, nativeCoin.decimals) const gasCost = fromTokenUnit(estimatedGasCosts, nativeCoin.decimals)
const gasCostFormatted = formatAmount(gasCost) const gasCostFormatted = formatAmount(gasCost)
const gasLimit = (gasEstimation * 2 + MINIMUM_TRANSACTION_GAS).toString() const gasLimit = (gasEstimation * 2).toString()
let txEstimationExecutionStatus = EstimationStatus.SUCCESS let txEstimationExecutionStatus = EstimationStatus.SUCCESS
@ -257,7 +259,7 @@ export const useEstimateTransactionGas = ({
} catch (error) { } catch (error) {
console.warn(error.message) console.warn(error.message)
// We put a fixed the amount of gas to let the user try to execute the tx, but it's not accurate so it will probably fail // We put a fixed the amount of gas to let the user try to execute the tx, but it's not accurate so it will probably fail
const gasEstimation = MINIMUM_TRANSACTION_GAS const gasEstimation = MINIMUM_TRANSACTION_GAS + (threshold || 1) * GAS_REQUIRED_PER_SIGNATURE
const gasCost = fromTokenUnit(gasEstimation, nativeCoin.decimals) const gasCost = fromTokenUnit(gasEstimation, nativeCoin.decimals)
const gasCostFormatted = formatAmount(gasCost) const gasCostFormatted = formatAmount(gasCost)
setGasEstimation({ setGasEstimation({

View File

@ -1,4 +1,5 @@
import { BigNumber } from 'bignumber.js' import { BigNumber } from 'bignumber.js'
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts' import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
import { calculateGasOf, EMPTY_DATA } from 'src/logic/wallets/ethTransactions' import { calculateGasOf, EMPTY_DATA } from 'src/logic/wallets/ethTransactions'
import { getWeb3, web3ReadOnly } from 'src/logic/wallets/getWeb3' import { getWeb3, web3ReadOnly } from 'src/logic/wallets/getWeb3'
@ -12,6 +13,8 @@ import { sameString } from 'src/utils/strings'
// 21000 - additional gas costs (e.g. base tx costs, transfer costs) // 21000 - additional gas costs (e.g. base tx costs, transfer costs)
export const MINIMUM_TRANSACTION_GAS = 21000 export const MINIMUM_TRANSACTION_GAS = 21000
// Estimation of gas required for each signature (aproximately 7800, roundup to 8000)
export const GAS_REQUIRED_PER_SIGNATURE = 8000
// Receives the response data of the safe method requiredTxGas() and parses it to get the gas amount // Receives the response data of the safe method requiredTxGas() and parses it to get the gas amount
const parseRequiredTxGasResponse = (data: string): number => { const parseRequiredTxGasResponse = (data: string): number => {
@ -177,9 +180,10 @@ const calculateMinimumGasForTransaction = async (
estimateData: string, estimateData: string,
txGasEstimation: number, txGasEstimation: number,
dataGasEstimation: number, dataGasEstimation: number,
fixedGasCosts: number,
): Promise<number> => { ): Promise<number> => {
for (const additionalGas of additionalGasBatches) { for (const additionalGas of additionalGasBatches) {
const amountOfGasToTryTx = txGasEstimation + dataGasEstimation + additionalGas const amountOfGasToTryTx = txGasEstimation + dataGasEstimation + fixedGasCosts + additionalGas
console.info(`Estimating transaction creation with gas amount: ${amountOfGasToTryTx}`) console.info(`Estimating transaction creation with gas amount: ${amountOfGasToTryTx}`)
try { try {
const estimation = await getGasEstimationTxResponse({ const estimation = await getGasEstimationTxResponse({
@ -224,7 +228,13 @@ export const estimateGasForTransactionCreation = async (
return gasEstimationResponse return gasEstimationResponse
} }
const threshold = await safeInstance.methods.getThreshold().call()
const dataGasEstimation = parseRequiredTxGasResponse(estimateData) const dataGasEstimation = parseRequiredTxGasResponse(estimateData)
// We add the minimum required gas for a transaction
// TODO: This fix will be more accurate when we have a service for estimation.
// This fix takes the safe threshold and multiplies it by GAS_REQUIRED_PER_SIGNATURE.
const fixedGasCosts = MINIMUM_TRANSACTION_GAS + (Number(threshold) || 1) * GAS_REQUIRED_PER_SIGNATURE
const additionalGasBatches = [0, 10000, 20000, 40000, 80000, 160000, 320000, 640000, 1280000, 2560000, 5120000] const additionalGasBatches = [0, 10000, 20000, 40000, 80000, 160000, 320000, 640000, 1280000, 2560000, 5120000]
return await calculateMinimumGasForTransaction( return await calculateMinimumGasForTransaction(
@ -233,6 +243,7 @@ export const estimateGasForTransactionCreation = async (
estimateData, estimateData,
gasEstimationResponse, gasEstimationResponse,
dataGasEstimation, dataGasEstimation,
fixedGasCosts,
) )
} catch (error) { } catch (error) {
console.info('Error calculating tx gas estimation', error.message) console.info('Error calculating tx gas estimation', error.message)