Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 80 additions & 54 deletions src/lib/getSuggestedGasPrice.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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' +
Expand All @@ -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);
}
};
Expand Down