prettier + wordings

This commit is contained in:
Alexey 2020-10-16 14:10:25 +03:00
parent 8a21dcd282
commit 0b706b704f
12 changed files with 1176 additions and 1384 deletions

@ -2,8 +2,8 @@ name: Node.js CI
on: on:
push: push:
branches: [ '*' ] branches: ['*']
tags: [ 'v[0-9]+.[0-9]+.[0-9]+' ] tags: ['v[0-9]+.[0-9]+.[0-9]+']
pull_request: pull_request:
jobs: jobs:

6
.prettierrc Normal file

@ -0,0 +1,6 @@
{
"arrowParens": "avoid",
"singleQuote": true,
"printWidth": 110,
"trailingComma": "all"
}

24
.vscode/launch.json vendored

@ -1,24 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Mocha Current File",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"--no-timeouts",
"--colors",
"${file}",
"--require",
"ts-node/register"
],
"console": "integratedTerminal",
"sourceMaps": true,
"internalConsoleOptions": "neverOpen"
}
]
}

@ -1,55 +1,66 @@
# Gas Price Oracle library for Ethereum dApps [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/peppersec/gas-price-oracle/Node.js%20CI)](https://github.com/peppersec/gas-price-oracle/actions) [![npm](https://img.shields.io/npm/v/gas-price-oracle)](https://www.npmjs.com/package/gas-price-oracle) # Gas Price Oracle library for Ethereum dApps [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/peppersec/gas-price-oracle/Node.js%20CI)](https://github.com/peppersec/gas-price-oracle/actions) [![npm](https://img.shields.io/npm/v/gas-price-oracle)](https://www.npmjs.com/package/gas-price-oracle)
A library that has a collection of onchain and offchain gas price oracle URLs A library that has a collection of onchain and offchain gas price oracle URLs
Current offchain list: Current offchain list:
- https://ethgasstation.info/json/ethgasAPI.json - https://ethgasstation.info/json/ethgasAPI.json
- https://gas-oracle.zoltu.io/ - https://gas-oracle.zoltu.io/
- https://www.etherchain.org/api/gasPriceOracle - https://www.etherchain.org/api/gasPriceOracle
- https://gasprice.poa.network/ - https://gasprice.poa.network/
Current onchain list: Current onchain list:
- [chainlink](https://etherscan.io/address/0xA417221ef64b1549575C977764E651c9FAB50141) - [chainlink](https://etherscan.io/address/0xA417221ef64b1549575C977764E651c9FAB50141)
## Installation ## Installation
`npm i gas-price-oracle` `npm i gas-price-oracle`
## Import ## Import
```js ```js
const { GasPriceOracle } = require('gas-price-oracle'); const { GasPriceOracle } = require('gas-price-oracle');
``` ```
## Usage ## Usage
### Basic ### Basic
```js ```js
const options = { const options = {
defaultRpc: 'https://api.mycryptoapi.com/eth' defaultRpc: 'https://api.mycryptoapi.com/eth',
} };
const oracle = new GasPriceOracle(options); const oracle = new GasPriceOracle(options);
// optional fallbackGasPrices // optional fallbackGasPrices
const fallbackGasPrices = { const fallbackGasPrices = {
instant: 70, fast: 31, standard: 20, low: 7 instant: 70,
} fast: 31,
oracle.gasPrices(fallbackGasPrices).then((gasPrices) => { standard: 20,
console.log(gasPrices) // { instant: 50, fast: 21, standard: 10, low: 3 } low: 7,
};
oracle.gasPrices(fallbackGasPrices).then(gasPrices => {
console.log(gasPrices); // { instant: 50, fast: 21, standard: 10, low: 3 }
}); });
``` ```
### Offchain oracles only ### Offchain oracles only
```js ```js
const oracle = new GasPriceOracle(); const oracle = new GasPriceOracle();
oracle.fetchGasPricesOffChain().then((gasPrices) => { oracle.fetchGasPricesOffChain().then(gasPrices => {
console.log(gasPrices) // { instant: 50, fast: 21, standard: 10, low: 3 } console.log(gasPrices); // { instant: 50, fast: 21, standard: 10, low: 3 }
}); });
``` ```
### Custom RPC URL for onchain oracles ### Custom RPC URL for onchain oracles
```js ```js
const defaultRpc = 'https://mainnet.infura.io/v3/<API_KEY>' const defaultRpc = 'https://mainnet.infura.io/v3/<API_KEY>';
const oracle = new GasPriceOracle({ defaultRpc }); const oracle = new GasPriceOracle({ defaultRpc });
oracle.fetchGasPricesOnChain().then((gasPrices) => { oracle.fetchGasPricesOnChain().then(gasPrices => {
console.log(gasPrices) // 21 console.log(gasPrices); // 21
}); });
``` ```

1304
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -14,7 +14,10 @@
"scripts": { "scripts": {
"test": "mocha --timeout 30000 -r ts-node/register tests/*.test.ts", "test": "mocha --timeout 30000 -r ts-node/register tests/*.test.ts",
"build": "tsc", "build": "tsc",
"lint": "tslint -p tsconfig.json" "tslint": "tslint -p tsconfig.json",
"prettier:check": "npx prettier --check . --config .prettierrc",
"prettier:fix": "npx prettier --write . --config .prettierrc",
"lint": "yarn tslint && yarn prettier:check"
}, },
"author": "Alexey Pertsev <alexey@peppersec.com> (https://peppersec.com)", "author": "Alexey Pertsev <alexey@peppersec.com> (https://peppersec.com)",
"keywords": [ "keywords": [
@ -33,9 +36,11 @@
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"mocha": "^7.2.0", "mocha": "^7.2.0",
"mockery": "^2.1.0", "mockery": "^2.1.0",
"tslint": "^6.1.2", "prettier": "^2.1.2",
"tslint-config-standard": "^9.0.0",
"ts-node": "^8.10.1", "ts-node": "^8.10.1",
"tslint": "^6.1.2",
"tslint-config-prettier": "^1.18.0",
"tslint-plugin-prettier": "^2.3.0",
"typescript": "^3.9.3" "typescript": "^3.9.3"
}, },
"dependencies": { "dependencies": {

@ -1,4 +1,3 @@
import { OffChainOracle, OnChainOracle } from './types'; import { OffChainOracle, OnChainOracle } from './types';
const ethgasstation: OffChainOracle = { const ethgasstation: OffChainOracle = {
@ -8,7 +7,7 @@ const ethgasstation: OffChainOracle = {
fastPropertyName: 'fast', fastPropertyName: 'fast',
standardPropertyName: 'average', standardPropertyName: 'average',
lowPropertyName: 'safeLow', lowPropertyName: 'safeLow',
denominator: 10 denominator: 10,
}; };
const zoltu: OffChainOracle = { const zoltu: OffChainOracle = {
@ -18,7 +17,7 @@ const zoltu: OffChainOracle = {
fastPropertyName: 'percentile_90', fastPropertyName: 'percentile_90',
standardPropertyName: 'percentile_60', standardPropertyName: 'percentile_60',
lowPropertyName: 'percentile_30', lowPropertyName: 'percentile_30',
denominator: 1 denominator: 1,
}; };
const etherchain: OffChainOracle = { const etherchain: OffChainOracle = {
@ -28,7 +27,7 @@ const etherchain: OffChainOracle = {
fastPropertyName: 'fast', fastPropertyName: 'fast',
standardPropertyName: 'standard', standardPropertyName: 'standard',
lowPropertyName: 'safeLow', lowPropertyName: 'safeLow',
denominator: 1 denominator: 1,
}; };
const poa: OffChainOracle = { const poa: OffChainOracle = {
@ -38,25 +37,28 @@ const poa: OffChainOracle = {
fastPropertyName: 'fast', fastPropertyName: 'fast',
standardPropertyName: 'standard', standardPropertyName: 'standard',
lowPropertyName: 'slow', lowPropertyName: 'slow',
denominator: 1 denominator: 1,
}; };
const chainlink: OnChainOracle = { const chainlink: OnChainOracle = {
name: 'chainlink', name: 'chainlink',
callData: '0x50d25bcd', callData: '0x50d25bcd',
contract: '0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C', contract: '0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C',
denominator: '1000000000' denominator: '1000000000',
}; };
export const offChainOracles: { [key: string]: OffChainOracle } = { export const offChainOracles: { [key: string]: OffChainOracle } = {
ethgasstation, zoltu, poa, etherchain ethgasstation,
zoltu,
poa,
etherchain,
}; };
export const onChainOracles: { [key: string]: OnChainOracle } = { export const onChainOracles: { [key: string]: OnChainOracle } = {
chainlink chainlink,
}; };
export default { export default {
offChainOracles, offChainOracles,
onChainOracles onChainOracles,
}; };

@ -17,7 +17,15 @@ export class GasPriceOracle {
async fetchGasPricesOffChain(): Promise<GasPrice> { async fetchGasPricesOffChain(): Promise<GasPrice> {
for (let oracle of Object.values(this.offChainOracles)) { for (let oracle of Object.values(this.offChainOracles)) {
const { name, url, instantPropertyName, fastPropertyName, standardPropertyName, lowPropertyName, denominator } = oracle; const {
name,
url,
instantPropertyName,
fastPropertyName,
standardPropertyName,
lowPropertyName,
denominator,
} = oracle;
try { try {
const response = await axios.get(url, { timeout: 10000 }); const response = await axios.get(url, { timeout: 10000 });
if (response.status === 200) { if (response.status === 200) {
@ -29,7 +37,7 @@ export class GasPriceOracle {
instant: parseFloat(gas[instantPropertyName]) / denominator, instant: parseFloat(gas[instantPropertyName]) / denominator,
fast: parseFloat(gas[fastPropertyName]) / denominator, fast: parseFloat(gas[fastPropertyName]) / denominator,
standard: parseFloat(gas[standardPropertyName]) / denominator, standard: parseFloat(gas[standardPropertyName]) / denominator,
low: parseFloat(gas[lowPropertyName]) / denominator low: parseFloat(gas[lowPropertyName]) / denominator,
}; };
return gasPrices; return gasPrices;
} else { } else {
@ -39,7 +47,7 @@ export class GasPriceOracle {
console.error(e.message); console.error(e.message);
} }
} }
throw new Error('All oracles are down. Probaly network error.'); throw new Error('All oracles are down. Probably a network error.');
} }
async fetchGasPricesOnChain(): Promise<number> { async fetchGasPricesOnChain(): Promise<number> {
@ -51,7 +59,7 @@ export class GasPriceOracle {
jsonrpc: '2.0', jsonrpc: '2.0',
id: 1337, id: 1337,
method: 'eth_call', method: 'eth_call',
params: [{ 'data': callData, 'to': contract }, 'latest'] params: [{ data: callData, to: contract }, 'latest'],
}; };
try { try {
const response = await axios.post(rpc, body, { timeout: 10000 }); const response = await axios.post(rpc, body, { timeout: 10000 });
@ -70,7 +78,7 @@ export class GasPriceOracle {
console.error(e.message); console.error(e.message);
} }
} }
throw new Error('All oracles are down. Probaly network error.'); throw new Error('All oracles are down. Probably a network error.');
} }
async gasPrices(fallbackGasPrices?: GasPrice): Promise<GasPrice> { async gasPrices(fallbackGasPrices?: GasPrice): Promise<GasPrice> {
@ -79,7 +87,7 @@ export class GasPriceOracle {
instant: defaultFastGas * 1.3, instant: defaultFastGas * 1.3,
fast: defaultFastGas, fast: defaultFastGas,
standard: defaultFastGas * 0.85, standard: defaultFastGas * 0.85,
low: defaultFastGas * 0.5 low: defaultFastGas * 0.5,
}; };
this.lastGasPrice = this.lastGasPrice || fallbackGasPrices || defaultFallbackGasPrices; this.lastGasPrice = this.lastGasPrice || fallbackGasPrices || defaultFallbackGasPrices;
try { try {
@ -95,7 +103,7 @@ export class GasPriceOracle {
instant: fastGas * 1.3, instant: fastGas * 1.3,
fast: fastGas, fast: fastGas,
standard: fastGas * 0.85, standard: fastGas * 0.85,
low: fastGas * 0.5 low: fastGas * 0.5,
}; };
return this.lastGasPrice; return this.lastGasPrice;
} catch (e) { } catch (e) {

@ -11,11 +11,11 @@ let oracle = new GasPriceOracle();
before('before', function () { before('before', function () {
let axiosMock = { let axiosMock = {
get: () => { get: () => {
throw new Error('axios GET methdod is mocked for tests'); throw new Error('axios GET method is mocked for tests');
}, },
post: () => { post: () => {
throw new Error('axios POST methdod is mocked for tests'); throw new Error('axios POST method is mocked for tests');
} },
}; };
mockery.registerMock('axios', axiosMock); mockery.registerMock('axios', axiosMock);
}); });
@ -43,7 +43,9 @@ describe('fetchGasPricesOffChain', function () {
mockery.enable({ useCleanCache: true, warnOnUnregistered: false }); mockery.enable({ useCleanCache: true, warnOnUnregistered: false });
const { GasPriceOracle } = require('../src/index'); const { GasPriceOracle } = require('../src/index');
oracle = new GasPriceOracle(); oracle = new GasPriceOracle();
await oracle.fetchGasPricesOffChain().should.be.rejectedWith('All oracles are down. Probaly network error.'); await oracle
.fetchGasPricesOffChain()
.should.be.rejectedWith('All oracles are down. Probably a network error.');
mockery.disable(); mockery.disable();
}); });
}); });
@ -71,14 +73,18 @@ describe('fetchGasPricesOnChain', function () {
it('should remove oracle', async function () { it('should remove oracle', async function () {
await oracle.fetchGasPricesOnChain(); await oracle.fetchGasPricesOnChain();
oracle.removeOnChainOracle('chainlink'); oracle.removeOnChainOracle('chainlink');
await oracle.fetchGasPricesOnChain().should.be.rejectedWith('All oracles are down. Probaly network error.'); await oracle
.fetchGasPricesOnChain()
.should.be.rejectedWith('All oracles are down. Probably a network error.');
}); });
it('should add oracle', async function () { it('should add oracle', async function () {
const { chainlink } = onChainOracles; const { chainlink } = onChainOracles;
await oracle.fetchGasPricesOnChain(); await oracle.fetchGasPricesOnChain();
oracle.removeOnChainOracle('chainlink'); oracle.removeOnChainOracle('chainlink');
await oracle.fetchGasPricesOnChain().should.be.rejectedWith('All oracles are down. Probaly network error.'); await oracle
.fetchGasPricesOnChain()
.should.be.rejectedWith('All oracles are down. Probably a network error.');
oracle.addOnChainOracle(chainlink); oracle.addOnChainOracle(chainlink);
const gas: number = await oracle.fetchGasPricesOnChain(); const gas: number = await oracle.fetchGasPricesOnChain();
@ -90,10 +96,11 @@ describe('fetchGasPricesOnChain', function () {
mockery.enable({ useCleanCache: true, warnOnUnregistered: false }); mockery.enable({ useCleanCache: true, warnOnUnregistered: false });
const { GasPriceOracle } = require('../src/index'); const { GasPriceOracle } = require('../src/index');
oracle = new GasPriceOracle(); oracle = new GasPriceOracle();
await oracle.fetchGasPricesOnChain().should.be.rejectedWith('All oracles are down. Probaly network error.'); await oracle
.fetchGasPricesOnChain()
.should.be.rejectedWith('All oracles are down. Probably a network error.');
mockery.disable(); mockery.disable();
}); });
}); });
describe('gasPrice', function () { describe('gasPrice', function () {

@ -7,12 +7,12 @@
"es2017", "es2017",
"esnext.asynciterable", "esnext.asynciterable",
"es2019" "es2019"
] /* Specify library files to be included in the compilation. */, ] /* Specify library files to be included in the compilation. */,
"outDir": "./lib", /* Redirect output structure to the directory. */ "outDir": "./lib" /* Redirect output structure to the directory. */,
"strict": true /* Enable all strict type-checking options. */, "strict": true /* Enable all strict type-checking options. */,
"strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */, "strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */,
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"declaration": true, /* Generates corresponding '.d.ts' file. */ "declaration": true /* Generates corresponding '.d.ts' file. */,
// "allowJs": true, /* Allow javascript files to be compiled. */ // "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */ // "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */

@ -1,10 +1,12 @@
{ {
"extends": "tslint-config-standard", "extends": "tslint-config-prettier",
"defaultSeverity": "error", "defaultSeverity": "error",
"rules": { "rules": {
"semicolon": [true, "always"], "semicolon": [true, "always"],
"space-before-function-paren": [true, {"anonymous": "always", "named": "never", "asyncArrow": "always"}], "space-before-function-paren": [
true,
{ "anonymous": "always", "named": "never", "asyncArrow": "always" }
],
"type-literal-delimiter": true "type-literal-delimiter": true
} }
} }

1079
yarn.lock Normal file

File diff suppressed because it is too large Load Diff