Skip to content

Commit

Permalink
feat: rework EIP-1559 fees
Browse files Browse the repository at this point in the history
  • Loading branch information
enzoferey authored Oct 6, 2022
1 parent eb72caf commit 0cfa245
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 132 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
![Tests](https://github.com/enzoferey/network-gas-price/actions/workflows/test.yml/badge.svg)
[![npm version](https://badge.fury.io/js/@enzoferey%2Fnetwork-gas-price.svg)](https://badge.fury.io/js/@enzoferey%2Fnetwork-gas-price)
[![codecov](https://codecov.io/gh/enzoferey/network-gas-price/branch/main/graph/badge.svg?token=EJR8EAA1U8)](https://codecov.io/gh/enzoferey/network-gas-price)
![npm bundle size](https://img.shields.io/bundlephobia/minzip/@enzoferey/network-gas-price?color=g&label=gzip%20size)

Query accurate gas prices on every blockchain network ⛽️

## Highlights

- Zero dependencies 🧹
- Lightweight (749 bytes gzipped) 📦
- Lightweight 📦
- Simple to use ⚡️
- Ethereum and Polygon networks 🚀

Expand Down Expand Up @@ -56,8 +57,7 @@ const networkGasPrice = await getNetworkGasPrice("ethereum");
// NOTE: All prices are returned in Gwei units
```

> 💡 The price level ("low", "average", "high", "asap") you should use depends on your type of application. Most use cases will do okay with "average" or "high". If your application has background transactions support and execution is not time critical, you could use "low". If your application has a strong need to execute transactions as soon as possible, we recommend using the
> "asap" option that adds 20% on top of the "high" reported gas price.
> 💡 The price level ("low", "average", "high", "asap") you should use depends on your type of application. Most use cases will do okay with "average" or "high". If your application has background transactions support and execution is not time critical, you could use "low". If your application has a strong need to execute transactions as soon as possible, we recommend using our custom "asap" option that protects against high gas prices spikes and makes the transaction attractive for miners.
> 🌐 The package currently supports the Ethereum (`"ethereum"`), Polygon (`"polygon"`), Goerli (`"goerli"`), Sepolia (`"sepolia"`), Rinkeby (`"rinkeby"`), and Mumbai (`"mumbai"`) networks. If you would like to add support for a new network, please open an issue or pull request.
Expand Down
14 changes: 14 additions & 0 deletions lib/__tests__/getAsapGasPriceLevel.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { describe, expect, it } from "vitest";

import { getAsapGasPriceLevel } from "../getAsapGasPriceLevel";

describe("getAsapGasPriceLevel", () => {
it("should return the asap gas price level", () => {
const result = getAsapGasPriceLevel(100, 20);

expect(result).toEqual({
maxPriorityFeePerGas: 32.5,
maxFeePerGas: 232.5,
});
});
});
25 changes: 25 additions & 0 deletions lib/getAsapGasPriceLevel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Inspired from https://www.blocknative.com/blog/eip-1559-fees

import type { GasPriceLevel } from "./types";

// +12.5% is the maximum increase of base fee per block
// This means setting a premium max priority fee bigger by 12.5% of base fee
// means likelyhood of getting into block 2 in a gas spike event is super high
const PREMIUM_BASE_FEE_PERCENTAGE_FOR_MAX_PRIORITY_FEE = 0.125;

export function getAsapGasPriceLevel(
baseFee: number,
fastMaxPriorityFee: number
): GasPriceLevel {
const maxPriorityFeePerGas =
fastMaxPriorityFee +
baseFee * PREMIUM_BASE_FEE_PERCENTAGE_FOR_MAX_PRIORITY_FEE;

// Using baseFee * 2 ensures the transaction will remain marketable for six consecutive 100% full blocks
const maxFeePerGas = baseFee * 2 + maxPriorityFeePerGas;

return {
maxPriorityFeePerGas,
maxFeePerGas,
};
}
115 changes: 50 additions & 65 deletions lib/networks/__tests__/getEthereumGasPrice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ import { mockFetch } from "./mockFetch";
import {
GAS_STATION_URL_BY_NETWORK,
DEFAULT_FALLBACK_GAS_PRICE,
ASAP_PERCENTAGE,
getEthereumGasPrice,
} from "../getEthereumGasPrice";

import { getAsapGasPriceLevel } from "../../getAsapGasPriceLevel";

describe("getEthereumGasPrice", () => {
it("should return the Ethereum gas prices per level based on the Ethereum gas station", async () => {
const lowGasPrice = 100;
const averageGasPrice = 110;
const fastGasPrice = 120;
const suggestBaseFee = 100;

const mock = mockFetch({
result: {
SafeGasPrice: lowGasPrice,
ProposeGasPrice: averageGasPrice,
FastGasPrice: fastGasPrice,
suggestBaseFee: String(suggestBaseFee),
SafeGasPrice: "100",
ProposeGasPrice: "110",
FastGasPrice: "120",
},
});

Expand All @@ -30,33 +30,29 @@ describe("getEthereumGasPrice", () => {

expect(result).toEqual({
low: {
maxPriorityFeePerGas: lowGasPrice,
maxFeePerGas: lowGasPrice,
maxPriorityFeePerGas: 0,
maxFeePerGas: 100,
},
average: {
maxPriorityFeePerGas: averageGasPrice,
maxFeePerGas: averageGasPrice,
maxPriorityFeePerGas: 10,
maxFeePerGas: 110,
},
high: {
maxPriorityFeePerGas: fastGasPrice,
maxFeePerGas: fastGasPrice,
},
asap: {
maxPriorityFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxPriorityFeePerGas: 20,
maxFeePerGas: 120,
},
asap: getAsapGasPriceLevel(suggestBaseFee, 20),
});
});
it("should return the Goerli gas prices per level based on the Ethereum gas station", async () => {
const lowGasPrice = 100;
const averageGasPrice = 110;
const fastGasPrice = 120;
const suggestBaseFee = 100;

const mock = mockFetch({
result: {
SafeGasPrice: lowGasPrice,
ProposeGasPrice: averageGasPrice,
FastGasPrice: fastGasPrice,
suggestBaseFee: String(suggestBaseFee),
SafeGasPrice: "100",
ProposeGasPrice: "110",
FastGasPrice: "120",
},
});

Expand All @@ -67,33 +63,29 @@ describe("getEthereumGasPrice", () => {

expect(result).toEqual({
low: {
maxPriorityFeePerGas: lowGasPrice,
maxFeePerGas: lowGasPrice,
maxPriorityFeePerGas: 0,
maxFeePerGas: 100,
},
average: {
maxPriorityFeePerGas: averageGasPrice,
maxFeePerGas: averageGasPrice,
maxPriorityFeePerGas: 10,
maxFeePerGas: 110,
},
high: {
maxPriorityFeePerGas: fastGasPrice,
maxFeePerGas: fastGasPrice,
},
asap: {
maxPriorityFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxPriorityFeePerGas: 20,
maxFeePerGas: 120,
},
asap: getAsapGasPriceLevel(suggestBaseFee, 20),
});
});
it("should return the Sepolia gas prices per level based on the Ethereum gas station", async () => {
const lowGasPrice = 100;
const averageGasPrice = 110;
const fastGasPrice = 120;
const suggestBaseFee = 100;

const mock = mockFetch({
result: {
SafeGasPrice: lowGasPrice,
ProposeGasPrice: averageGasPrice,
FastGasPrice: fastGasPrice,
suggestBaseFee: String(suggestBaseFee),
SafeGasPrice: "100",
ProposeGasPrice: "110",
FastGasPrice: "120",
},
});

Expand All @@ -104,33 +96,29 @@ describe("getEthereumGasPrice", () => {

expect(result).toEqual({
low: {
maxPriorityFeePerGas: lowGasPrice,
maxFeePerGas: lowGasPrice,
maxPriorityFeePerGas: 0,
maxFeePerGas: 100,
},
average: {
maxPriorityFeePerGas: averageGasPrice,
maxFeePerGas: averageGasPrice,
maxPriorityFeePerGas: 10,
maxFeePerGas: 110,
},
high: {
maxPriorityFeePerGas: fastGasPrice,
maxFeePerGas: fastGasPrice,
},
asap: {
maxPriorityFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxPriorityFeePerGas: 20,
maxFeePerGas: 120,
},
asap: getAsapGasPriceLevel(suggestBaseFee, 20),
});
});
it("should return the Rinkeby gas prices per level based on the Ethereum gas station", async () => {
const lowGasPrice = 100;
const averageGasPrice = 110;
const fastGasPrice = 120;
const suggestBaseFee = 100;

const mock = mockFetch({
result: {
SafeGasPrice: lowGasPrice,
ProposeGasPrice: averageGasPrice,
FastGasPrice: fastGasPrice,
suggestBaseFee: String(suggestBaseFee),
SafeGasPrice: "100",
ProposeGasPrice: "110",
FastGasPrice: "120",
},
});

Expand All @@ -141,21 +129,18 @@ describe("getEthereumGasPrice", () => {

expect(result).toEqual({
low: {
maxPriorityFeePerGas: lowGasPrice,
maxFeePerGas: lowGasPrice,
maxPriorityFeePerGas: 0,
maxFeePerGas: 100,
},
average: {
maxPriorityFeePerGas: averageGasPrice,
maxFeePerGas: averageGasPrice,
maxPriorityFeePerGas: 10,
maxFeePerGas: 110,
},
high: {
maxPriorityFeePerGas: fastGasPrice,
maxFeePerGas: fastGasPrice,
},
asap: {
maxPriorityFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxPriorityFeePerGas: 20,
maxFeePerGas: 120,
},
asap: getAsapGasPriceLevel(suggestBaseFee, 20),
});
});
it("should include the API key if provided for Ethereum", async () => {
Expand Down
71 changes: 32 additions & 39 deletions lib/networks/__tests__/getPolygonGasPrice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@ import { mockFetch } from "./mockFetch";
import {
GAS_STATION_URL_BY_NETWORK,
DEFAULT_FALLBACK_GAS_PRICE,
ASAP_PERCENTAGE,
getPolygonGasPrice,
} from "../getPolygonGasPrice";

import { getAsapGasPriceLevel } from "../../getAsapGasPriceLevel";

describe("getPolygonGasPrice", () => {
it("should return the Polygon gas prices per level based on the Polygon gas station", async () => {
const lowGasPrice = 100;
const averageGasPrice = 110;
const fastGasPrice = 120;
const estimatedBaseFee = 100;

const mock = mockFetch({
estimatedBaseFee,
safeLow: {
maxPriorityFee: lowGasPrice,
maxFee: lowGasPrice,
maxPriorityFee: 0,
maxFee: 100,
},
standard: {
maxPriorityFee: averageGasPrice,
maxFee: averageGasPrice,
maxPriorityFee: 1,
maxFee: 110,
},
fast: {
maxPriorityFee: fastGasPrice,
maxFee: fastGasPrice,
maxPriorityFee: 2,
maxFee: 120,
},
});

Expand All @@ -37,40 +37,36 @@ describe("getPolygonGasPrice", () => {

expect(result).toEqual({
low: {
maxPriorityFeePerGas: lowGasPrice,
maxFeePerGas: lowGasPrice,
maxPriorityFeePerGas: 0,
maxFeePerGas: 100,
},
average: {
maxPriorityFeePerGas: averageGasPrice,
maxFeePerGas: averageGasPrice,
maxPriorityFeePerGas: 1,
maxFeePerGas: 110,
},
high: {
maxPriorityFeePerGas: fastGasPrice,
maxFeePerGas: fastGasPrice,
},
asap: {
maxPriorityFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxPriorityFeePerGas: 2,
maxFeePerGas: 120,
},
asap: getAsapGasPriceLevel(estimatedBaseFee, 2),
});
});
it("should return the Mumbai gas prices per level based on the Polygon gas station", async () => {
const lowGasPrice = 100;
const averageGasPrice = 110;
const fastGasPrice = 120;
const estimatedBaseFee = 100;

const mock = mockFetch({
estimatedBaseFee,
safeLow: {
maxPriorityFee: lowGasPrice,
maxFee: lowGasPrice,
maxPriorityFee: 0,
maxFee: 100,
},
standard: {
maxPriorityFee: averageGasPrice,
maxFee: averageGasPrice,
maxPriorityFee: 1,
maxFee: 110,
},
fast: {
maxPriorityFee: fastGasPrice,
maxFee: fastGasPrice,
maxPriorityFee: 2,
maxFee: 120,
},
});

Expand All @@ -81,21 +77,18 @@ describe("getPolygonGasPrice", () => {

expect(result).toEqual({
low: {
maxPriorityFeePerGas: lowGasPrice,
maxFeePerGas: lowGasPrice,
maxPriorityFeePerGas: 0,
maxFeePerGas: 100,
},
average: {
maxPriorityFeePerGas: averageGasPrice,
maxFeePerGas: averageGasPrice,
maxPriorityFeePerGas: 1,
maxFeePerGas: 110,
},
high: {
maxPriorityFeePerGas: fastGasPrice,
maxFeePerGas: fastGasPrice,
},
asap: {
maxPriorityFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxFeePerGas: (fastGasPrice * ASAP_PERCENTAGE) / 100,
maxPriorityFeePerGas: 2,
maxFeePerGas: 120,
},
asap: getAsapGasPriceLevel(estimatedBaseFee, 2),
});
});
it("should return the fallback gas price if there an issue fetching from the Polygon gas station", async () => {
Expand Down
Loading

0 comments on commit 0cfa245

Please sign in to comment.