-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
2,679 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/recommended", | ||
"prettier" | ||
], | ||
"parser": "@typescript-eslint/parser", | ||
"plugins": ["@typescript-eslint"], | ||
"root": true, | ||
"env": { | ||
"node": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
name: Codecov | ||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
run-tests: | ||
name: Run tests | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
node-version: [14.x] | ||
|
||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v2 | ||
|
||
- name: Use Node.js ${{ matrix.node-version }} | ||
uses: actions/setup-node@v2 | ||
with: | ||
registry-url: https://registry.npmjs.org | ||
|
||
- name: Restore yarn cache if available | ||
uses: actions/cache@v2 | ||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) | ||
with: | ||
path: | | ||
node_modules | ||
*/*/node_modules | ||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} | ||
|
||
- name: Install dependencies | ||
run: | | ||
yarn install --frozen-lockfile | ||
- name: Generate coverage reports | ||
run: | | ||
yarn test:ci | ||
env: | ||
CI: true | ||
|
||
- name: Upload coverage | ||
uses: codecov/codecov-action@v3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
name: Test | ||
on: | ||
pull_request: | ||
types: [opened, reopened, synchronize] | ||
|
||
jobs: | ||
run-tests: | ||
name: Run tests | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
node-version: [14.x] | ||
|
||
steps: | ||
- name: Cancel previous runs | ||
uses: styfle/[email protected] | ||
with: | ||
access_token: ${{ github.token }} | ||
|
||
- name: Checkout repository | ||
uses: actions/checkout@v2 | ||
|
||
- name: Use Node.js ${{ matrix.node-version }} | ||
uses: actions/setup-node@v2 | ||
with: | ||
registry-url: https://registry.npmjs.org | ||
|
||
- name: Restore yarn cache if available | ||
uses: actions/cache@v2 | ||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) | ||
with: | ||
path: | | ||
node_modules | ||
*/*/node_modules | ||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} | ||
|
||
- name: Install dependencies | ||
run: | | ||
yarn install --frozen-lockfile | ||
- name: Run TypeScript type checker | ||
run: | | ||
yarn ts:check | ||
env: | ||
CI: true | ||
|
||
- name: Run formatting check | ||
run: | | ||
yarn format:check | ||
env: | ||
CI: true | ||
|
||
- name: Run linting check | ||
run: | | ||
yarn lint | ||
env: | ||
CI: true | ||
|
||
- name: Run tests | ||
run: | | ||
yarn test:ci | ||
env: | ||
CI: true | ||
|
||
- name: Upload coverage | ||
uses: codecov/codecov-action@v3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
pnpm-debug.log* | ||
lerna-debug.log* | ||
|
||
node_modules | ||
dist | ||
dist-ssr | ||
*.local | ||
|
||
# Editor directories and files | ||
.vscode/* | ||
!.vscode/extensions.json | ||
.idea | ||
.DS_Store | ||
*.suo | ||
*.ntvs* | ||
*.njsproj | ||
*.sln | ||
*.sw? | ||
|
||
# Vitest | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
dist | ||
node_modules | ||
coverage |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,81 @@ | ||
# network-gas-price | ||
|
||
![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) | ||
|
||
Query accurate gas prices on every blockchain network ⛽️ | ||
|
||
## Highlights | ||
|
||
- Zero dependencies 🧹 | ||
- Lightweight (749 bytes gzipped) 📦 | ||
- Simple to use ⚡️ | ||
- Ethereum and Polygon networks 🚀 | ||
|
||
## Why | ||
|
||
Gas price is constantly changing on every blockchain network based on demand to run transactions. When sending a transaction to the network, it's important to set an accurate gas price in order to avoid stuck transactions or pay too much gas fees. | ||
|
||
## Getting started | ||
|
||
1. Install the package | ||
|
||
```sh | ||
yarn install @enzoferey/network-gas-price | ||
``` | ||
|
||
2. Get network prices | ||
|
||
```ts | ||
import { getNetworkGasPrice } from "@enzoferey/network-gas-price"; | ||
|
||
const networkGasPrice = await getNetworkGasPrice("ethereum"); | ||
|
||
// networkGasPrice is an object with the following shape: | ||
// | ||
// { | ||
// low: { | ||
// maxPriorityFeePerGas: number; | ||
// maxFeePerGas: number; | ||
// }, | ||
// average: { | ||
// maxPriorityFeePerGas: number; | ||
// maxFeePerGas: number; | ||
// }, | ||
// high: { | ||
// maxPriorityFeePerGas: number; | ||
// maxFeePerGas: number; | ||
// } | ||
// } | ||
|
||
// 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 package currently supports the Ethereum and Polygon networks (both mainnet and testnet). If you would like to add support for a new network, please open an issue or pull request. | ||
3. Use gas prices (with [Ethers.js](https://github.com/ethers-io/ethers.js/) as an example): | ||
|
||
```ts | ||
import { ethers, BigNumber } from "ethers"; | ||
|
||
function getGweiEthers(gweiAmount: number): BigNumber { | ||
return ethers.utils.parseUnits(Math.ceil(gweiAmount).toString(), "gwei"); | ||
} | ||
|
||
try { | ||
const transaction = await someContract.someMethod(someArgument, { | ||
maxPriorityFeePerGas: getGweiEthers( | ||
networkGasPrice.high.maxPriorityFeePerGas | ||
), | ||
maxFeePerGas: getGweiEthers(networkGasPrice.high.maxFeePerGas), | ||
}); | ||
await transaction.wait(); | ||
} catch (error) { | ||
// Handle error | ||
// -> You could use my package https://github.com/enzoferey/ethers-error-parser for that 😉 | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { describe, it, expect, vi, Mock } from "vitest"; | ||
|
||
import { getEthereumGasPrice } from "../networks/getEthereumGasPrice"; | ||
import { getPolygonGasPrice } from "../networks/getPolygonGasPrice"; | ||
|
||
import { getNetworkGasPrice } from "../getNetworkGasPrice"; | ||
|
||
vi.mock("../networks/getEthereumGasPrice"); | ||
vi.mock("../networks/getPolygonGasPrice"); | ||
|
||
describe("getNetworkGasPrice", () => { | ||
it("should return the Ethereum gas price for Ethereum", async () => { | ||
const gasPrice = 1; | ||
(getEthereumGasPrice as Mock).mockImplementationOnce(async () => { | ||
return gasPrice; | ||
}); | ||
|
||
const result = await getNetworkGasPrice("ethereum"); | ||
|
||
expect(result).toBe(gasPrice); | ||
}); | ||
it("should return the Ethereum gas price for Rinkeby", async () => { | ||
const gasPrice = 1; | ||
(getEthereumGasPrice as Mock).mockImplementationOnce(async () => { | ||
return gasPrice; | ||
}); | ||
|
||
const result = await getNetworkGasPrice("rinkeby"); | ||
|
||
expect(result).toBe(gasPrice); | ||
}); | ||
it("should return the Polygon gas price for Polygon", async () => { | ||
const gasPrice = 1; | ||
(getPolygonGasPrice as Mock).mockImplementationOnce(async () => { | ||
return gasPrice; | ||
}); | ||
|
||
const result = await getNetworkGasPrice("polygon"); | ||
|
||
expect(result).toBe(gasPrice); | ||
}); | ||
it("should return the Polygon gas price for Mumbai", async () => { | ||
const gasPrice = 1; | ||
(getPolygonGasPrice as Mock).mockImplementationOnce(async () => { | ||
return gasPrice; | ||
}); | ||
|
||
const result = await getNetworkGasPrice("mumbai"); | ||
|
||
expect(result).toBe(gasPrice); | ||
}); | ||
it("should pass the Ethereum options", async () => { | ||
const options = { | ||
etherscanApiKey: "testApiKey", | ||
fallbackGasPrice: { ethereum: 1 }, | ||
}; | ||
|
||
await getNetworkGasPrice("ethereum", options); | ||
|
||
expect(getEthereumGasPrice).toHaveBeenCalledWith("ethereum", { | ||
apiKey: options.etherscanApiKey, | ||
fallbackGasPrice: options.fallbackGasPrice.ethereum, | ||
}); | ||
}); | ||
it("should pass the Rinkeby options", async () => { | ||
const options = { | ||
etherscanApiKey: "testApiKey", | ||
fallbackGasPrice: { rinkeby: 1 }, | ||
}; | ||
|
||
await getNetworkGasPrice("rinkeby", options); | ||
|
||
expect(getEthereumGasPrice).toHaveBeenCalledWith("rinkeby", { | ||
apiKey: options.etherscanApiKey, | ||
fallbackGasPrice: options.fallbackGasPrice.rinkeby, | ||
}); | ||
}); | ||
it("should pass the Polygon options", async () => { | ||
const options = { | ||
fallbackGasPrice: { polygon: 1 }, | ||
}; | ||
|
||
await getNetworkGasPrice("polygon", options); | ||
|
||
expect(getPolygonGasPrice).toHaveBeenCalledWith("polygon", { | ||
fallbackGasPrice: options.fallbackGasPrice.polygon, | ||
}); | ||
}); | ||
it("should return the Mumbai options", async () => { | ||
const options = { | ||
fallbackGasPrice: { mumbai: 1 }, | ||
}; | ||
|
||
await getNetworkGasPrice("mumbai", options); | ||
|
||
expect(getPolygonGasPrice).toHaveBeenCalledWith("mumbai", { | ||
fallbackGasPrice: options.fallbackGasPrice.mumbai, | ||
}); | ||
}); | ||
it("should throw if the network is not supported", async () => { | ||
const notSupportedNetwork = "some not supported network"; | ||
|
||
await expect(() => { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- required to bypass type checker | ||
getNetworkGasPrice(notSupportedNetwork as any); | ||
}).toThrow("NOT_SUPPORTED_NETWORK"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import type { GasPrice, Network, Options } from "./types"; | ||
|
||
import { getEthereumGasPrice, getPolygonGasPrice } from "./networks"; | ||
|
||
export function getNetworkGasPrice( | ||
network: Network, | ||
options: Options = {} | ||
): Promise<GasPrice> { | ||
if (network === "ethereum" || network === "rinkeby") { | ||
return getEthereumGasPrice(network, { | ||
apiKey: options.etherscanApiKey, | ||
fallbackGasPrice: | ||
network === "ethereum" | ||
? options.fallbackGasPrice?.ethereum | ||
: options.fallbackGasPrice?.rinkeby, | ||
}); | ||
} | ||
|
||
if (network === "polygon" || network === "mumbai") { | ||
return getPolygonGasPrice(network, { | ||
fallbackGasPrice: | ||
network === "polygon" | ||
? options.fallbackGasPrice?.polygon | ||
: options.fallbackGasPrice?.mumbai, | ||
}); | ||
} | ||
|
||
throw new Error("NOT_SUPPORTED_NETWORK"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { getNetworkGasPrice } from "./getNetworkGasPrice"; | ||
export * from "./types"; |
Oops, something went wrong.