Skip to content

Commit

Permalink
feat: implement first release
Browse files Browse the repository at this point in the history
  • Loading branch information
enzoferey authored Jul 25, 2022
1 parent 71a8888 commit 2cfba0b
Show file tree
Hide file tree
Showing 21 changed files with 2,679 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .eslintrc
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
}
}
44 changes: 44 additions & 0 deletions .github/workflows/codecov.yaml
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
66 changes: 66 additions & 0 deletions .github/workflows/test.yml
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
27 changes: 27 additions & 0 deletions .gitignore
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
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist
node_modules
coverage
Empty file added .prettierrc
Empty file.
79 changes: 79 additions & 0 deletions README.md
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 😉
}
```
108 changes: 108 additions & 0 deletions lib/__tests__/getNetworkGasPrice.test.ts
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");
});
});
29 changes: 29 additions & 0 deletions lib/getNetworkGasPrice.ts
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");
}
2 changes: 2 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { getNetworkGasPrice } from "./getNetworkGasPrice";
export * from "./types";
Loading

0 comments on commit 2cfba0b

Please sign in to comment.