diff --git a/src/lib/getSuggestedGasPrice.js b/src/lib/getSuggestedGasPrice.js index cd0ef3c1..507eb305 100644 --- a/src/lib/getSuggestedGasPrice.js +++ b/src/lib/getSuggestedGasPrice.js @@ -2,7 +2,7 @@ import { NETWORK_TYPES } from './network'; import { DEFAULT_GAS_PRICE_GWEI, MAX_GAS_PRICE_GWEI } from './constants'; import Web3 from 'web3'; -// ethgasstation returns values in floating point, one order of magitude +// ethgasstation returns values in floating point, one order of magnitude // more than gwei. see: https://docs.ethgasstation.info // we don't want to charge users more than the gas tank funds const minGas = gas => Math.min(Math.ceil(gas), MAX_GAS_PRICE_GWEI); @@ -11,48 +11,52 @@ const feeToInt = f => (f < 1 ? 1 : Math.round(f)); const feeToWei = fee => Web3.utils.toHex(Web3.utils.toWei(String(fee), 'gwei')); -const weiToGwei = wei => Math.ceil(wei / 1_000_000_000); +const weiToGwei = wei => { + if (wei == null) return DEFAULT_GAS_PRICE_GWEI; + const asBigInt = BigInt(wei.toString()); + const gwei = (asBigInt + 999_999_999n) / 1_000_000_000n; // ceil division + return Number(gwei); +}; -const calculateMaxFee = (baseFee, maxPriorityFee) => - feeToWei(Math.round(2 * baseFee + maxPriorityFee)); +const calculateMaxFee = (baseFeeGwei, maxPriorityFeeGwei) => + feeToInt(2 * baseFeeGwei + maxPriorityFeeGwei); -// Convert seconds to minutes prettily const formatWait = wait => Math.round((wait * 100) / 60) / 100; -export const defaultGasValues = value => ({ - fast: { - price: value, - wait: '1', - maxFeePerGas: value, - maxPriorityFeePerGas: 1, - suggestedBaseFeePerGas: value > 2 ? value - 1 : 1, - }, - average: { - price: value, - wait: '1', - maxFeePerGas: value, - maxPriorityFeePerGas: 1, - suggestedBaseFeePerGas: value > 2 ? value - 1 : 1, - }, - low: { - price: value, - wait: '1', - maxFeePerGas: value, - maxPriorityFeePerGas: 1, - suggestedBaseFeePerGas: value > 2 ? value - 1 : 1, - }, -}); +export const defaultGasValues = value => { + const base = value > 2 ? value - 1 : 1; + return { + fast: { + price: value, + wait: '1', + maxFeePerGas: value, + maxPriorityFeePerGas: 1, + suggestedBaseFeePerGas: base, + }, + average: { + price: value, + wait: '1', + maxFeePerGas: value, + maxPriorityFeePerGas: 1, + suggestedBaseFeePerGas: base, + }, + low: { + price: value, + wait: '1', + maxFeePerGas: value, + maxPriorityFeePerGas: 1, + suggestedBaseFeePerGas: base, + }, + }; +}; const getGasForNetwork = async providerUrl => { try { const [feeResponse, baseFeeResponse] = await Promise.all([ - fetch( - 'https://beaconcha.in/api/v1/execution/gasnow', - { - method: 'get', - cache: 'no-cache', - } - ), + fetch('https://beaconcha.in/api/v1/execution/gasnow', { + method: 'GET', + cache: 'no-cache', + }), fetch( `${providerUrl}/v2/api` + '?module=gastracker' + @@ -71,38 +75,60 @@ const getGasForNetwork = async providerUrl => { baseFeeResponse.json(), ]); - const suggestedBaseFeePerGas = Number(baseFeeJson.result.suggestBaseFee); + const gasData = feeJson && feeJson.data ? feeJson.data : {}; + const resultObj = baseFeeJson && baseFeeJson.result ? baseFeeJson.result : {}; + + let suggestedBaseFeePerGas = Number(resultObj.suggestBaseFee); + if (!Number.isFinite(suggestedBaseFeePerGas) || suggestedBaseFeePerGas <= 0) { + suggestedBaseFeePerGas = DEFAULT_GAS_PRICE_GWEI; + } + + const rapidGwei = weiToGwei(gasData.rapid); + const fastGwei = weiToGwei(gasData.fast); + const slowGwei = weiToGwei(gasData.slow); + + const rapidPriority = Math.max( + 1, + feeToInt(rapidGwei - suggestedBaseFeePerGas) + ); + const fastPriority = Math.max( + 1, + feeToInt(fastGwei - suggestedBaseFeePerGas) + ); + const slowPriority = Math.max( + 1, + feeToInt(slowGwei - suggestedBaseFeePerGas) + ); + + const rapidMaxFee = minGas(calculateMaxFee(suggestedBaseFeePerGas, rapidPriority)); + const fastMaxFee = minGas(calculateMaxFee(suggestedBaseFeePerGas, fastPriority)); + const slowMaxFee = minGas(calculateMaxFee(suggestedBaseFeePerGas, slowPriority)); - // Calculations derived from: - // https://www.blocknative.com/blog/eip-1559-fees return { fast: { - price: minGas(weiToGwei(feeJson.data.rapid)), + price: minGas(rapidGwei), wait: formatWait(15), - maxFeePerGas: weiToGwei(feeJson.data.rapid), - maxPriorityFeePerGas: feeToInt( - weiToGwei(feeJson.data.rapid) - suggestedBaseFeePerGas - ) + maxFeePerGas: rapidMaxFee, + maxPriorityFeePerGas: rapidPriority, + suggestedBaseFeePerGas, }, average: { - price: minGas(weiToGwei(feeJson.data.fast)), + price: minGas(fastGwei), wait: formatWait(60), - maxFeePerGas: weiToGwei(feeJson.data.fast), - maxPriorityFeePerGas: feeToInt( - weiToGwei(feeJson.data.fast) - suggestedBaseFeePerGas - ) + maxFeePerGas: fastMaxFee, + maxPriorityFeePerGas: fastPriority, + suggestedBaseFeePerGas, }, low: { - price: minGas(weiToGwei(feeJson.data.slow)), + price: minGas(slowGwei), wait: formatWait(180), - maxFeePerGas: weiToGwei(feeJson.data.slow), - maxPriorityFeePerGas: feeToInt( - weiToGwei(feeJson.data.slow) - suggestedBaseFeePerGas - ) + maxFeePerGas: slowMaxFee, + maxPriorityFeePerGas: slowPriority, + suggestedBaseFeePerGas, }, }; } catch (e) { - console.warn(e); + console.warn('getGasForNetwork fallback to defaults:', e); return defaultGasValues(DEFAULT_GAS_PRICE_GWEI); } };