prettier + wordings
This commit is contained in:
parent
8a21dcd282
commit
0b706b704f
6
.prettierrc
Normal file
6
.prettierrc
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"arrowParens": "avoid",
|
||||
"singleQuote": true,
|
||||
"printWidth": 110,
|
||||
"trailingComma": "all"
|
||||
}
|
24
.vscode/launch.json
vendored
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"
|
||||
}
|
||||
]
|
||||
}
|
35
README.md
35
README.md
@ -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)
|
||||
|
||||
A library that has a collection of onchain and offchain gas price oracle URLs
|
||||
|
||||
Current offchain list:
|
||||
|
||||
- https://ethgasstation.info/json/ethgasAPI.json
|
||||
- https://gas-oracle.zoltu.io/
|
||||
- https://www.etherchain.org/api/gasPriceOracle
|
||||
- https://gasprice.poa.network/
|
||||
|
||||
Current onchain list:
|
||||
|
||||
- [chainlink](https://etherscan.io/address/0xA417221ef64b1549575C977764E651c9FAB50141)
|
||||
|
||||
## Installation
|
||||
|
||||
`npm i gas-price-oracle`
|
||||
|
||||
## Import
|
||||
|
||||
```js
|
||||
const { GasPriceOracle } = require('gas-price-oracle');
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic
|
||||
|
||||
```js
|
||||
|
||||
const options = {
|
||||
defaultRpc: 'https://api.mycryptoapi.com/eth'
|
||||
}
|
||||
defaultRpc: 'https://api.mycryptoapi.com/eth',
|
||||
};
|
||||
const oracle = new GasPriceOracle(options);
|
||||
// optional fallbackGasPrices
|
||||
const fallbackGasPrices = {
|
||||
instant: 70, fast: 31, standard: 20, low: 7
|
||||
}
|
||||
oracle.gasPrices(fallbackGasPrices).then((gasPrices) => {
|
||||
console.log(gasPrices) // { instant: 50, fast: 21, standard: 10, low: 3 }
|
||||
instant: 70,
|
||||
fast: 31,
|
||||
standard: 20,
|
||||
low: 7,
|
||||
};
|
||||
oracle.gasPrices(fallbackGasPrices).then(gasPrices => {
|
||||
console.log(gasPrices); // { instant: 50, fast: 21, standard: 10, low: 3 }
|
||||
});
|
||||
```
|
||||
|
||||
### Offchain oracles only
|
||||
|
||||
```js
|
||||
const oracle = new GasPriceOracle();
|
||||
|
||||
oracle.fetchGasPricesOffChain().then((gasPrices) => {
|
||||
console.log(gasPrices) // { instant: 50, fast: 21, standard: 10, low: 3 }
|
||||
oracle.fetchGasPricesOffChain().then(gasPrices => {
|
||||
console.log(gasPrices); // { instant: 50, fast: 21, standard: 10, low: 3 }
|
||||
});
|
||||
```
|
||||
|
||||
### Custom RPC URL for onchain oracles
|
||||
|
||||
```js
|
||||
const defaultRpc = 'https://mainnet.infura.io/v3/<API_KEY>'
|
||||
const defaultRpc = 'https://mainnet.infura.io/v3/<API_KEY>';
|
||||
const oracle = new GasPriceOracle({ defaultRpc });
|
||||
|
||||
oracle.fetchGasPricesOnChain().then((gasPrices) => {
|
||||
console.log(gasPrices) // 21
|
||||
oracle.fetchGasPricesOnChain().then(gasPrices => {
|
||||
console.log(gasPrices); // 21
|
||||
});
|
||||
```
|
||||
|
1304
package-lock.json
generated
1304
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -14,7 +14,10 @@
|
||||
"scripts": {
|
||||
"test": "mocha --timeout 30000 -r ts-node/register tests/*.test.ts",
|
||||
"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)",
|
||||
"keywords": [
|
||||
@ -33,9 +36,11 @@
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"mocha": "^7.2.0",
|
||||
"mockery": "^2.1.0",
|
||||
"tslint": "^6.1.2",
|
||||
"tslint-config-standard": "^9.0.0",
|
||||
"prettier": "^2.1.2",
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import { OffChainOracle, OnChainOracle } from './types';
|
||||
|
||||
const ethgasstation: OffChainOracle = {
|
||||
@ -8,7 +7,7 @@ const ethgasstation: OffChainOracle = {
|
||||
fastPropertyName: 'fast',
|
||||
standardPropertyName: 'average',
|
||||
lowPropertyName: 'safeLow',
|
||||
denominator: 10
|
||||
denominator: 10,
|
||||
};
|
||||
|
||||
const zoltu: OffChainOracle = {
|
||||
@ -18,7 +17,7 @@ const zoltu: OffChainOracle = {
|
||||
fastPropertyName: 'percentile_90',
|
||||
standardPropertyName: 'percentile_60',
|
||||
lowPropertyName: 'percentile_30',
|
||||
denominator: 1
|
||||
denominator: 1,
|
||||
};
|
||||
|
||||
const etherchain: OffChainOracle = {
|
||||
@ -28,7 +27,7 @@ const etherchain: OffChainOracle = {
|
||||
fastPropertyName: 'fast',
|
||||
standardPropertyName: 'standard',
|
||||
lowPropertyName: 'safeLow',
|
||||
denominator: 1
|
||||
denominator: 1,
|
||||
};
|
||||
|
||||
const poa: OffChainOracle = {
|
||||
@ -38,25 +37,28 @@ const poa: OffChainOracle = {
|
||||
fastPropertyName: 'fast',
|
||||
standardPropertyName: 'standard',
|
||||
lowPropertyName: 'slow',
|
||||
denominator: 1
|
||||
denominator: 1,
|
||||
};
|
||||
|
||||
const chainlink: OnChainOracle = {
|
||||
name: 'chainlink',
|
||||
callData: '0x50d25bcd',
|
||||
contract: '0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C',
|
||||
denominator: '1000000000'
|
||||
denominator: '1000000000',
|
||||
};
|
||||
|
||||
export const offChainOracles: { [key: string]: OffChainOracle } = {
|
||||
ethgasstation, zoltu, poa, etherchain
|
||||
ethgasstation,
|
||||
zoltu,
|
||||
poa,
|
||||
etherchain,
|
||||
};
|
||||
|
||||
export const onChainOracles: { [key: string]: OnChainOracle } = {
|
||||
chainlink
|
||||
chainlink,
|
||||
};
|
||||
|
||||
export default {
|
||||
offChainOracles,
|
||||
onChainOracles
|
||||
onChainOracles,
|
||||
};
|
||||
|
22
src/index.ts
22
src/index.ts
@ -17,7 +17,15 @@ export class GasPriceOracle {
|
||||
|
||||
async fetchGasPricesOffChain(): Promise<GasPrice> {
|
||||
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 {
|
||||
const response = await axios.get(url, { timeout: 10000 });
|
||||
if (response.status === 200) {
|
||||
@ -29,7 +37,7 @@ export class GasPriceOracle {
|
||||
instant: parseFloat(gas[instantPropertyName]) / denominator,
|
||||
fast: parseFloat(gas[fastPropertyName]) / denominator,
|
||||
standard: parseFloat(gas[standardPropertyName]) / denominator,
|
||||
low: parseFloat(gas[lowPropertyName]) / denominator
|
||||
low: parseFloat(gas[lowPropertyName]) / denominator,
|
||||
};
|
||||
return gasPrices;
|
||||
} else {
|
||||
@ -39,7 +47,7 @@ export class GasPriceOracle {
|
||||
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> {
|
||||
@ -51,7 +59,7 @@ export class GasPriceOracle {
|
||||
jsonrpc: '2.0',
|
||||
id: 1337,
|
||||
method: 'eth_call',
|
||||
params: [{ 'data': callData, 'to': contract }, 'latest']
|
||||
params: [{ data: callData, to: contract }, 'latest'],
|
||||
};
|
||||
try {
|
||||
const response = await axios.post(rpc, body, { timeout: 10000 });
|
||||
@ -70,7 +78,7 @@ export class GasPriceOracle {
|
||||
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> {
|
||||
@ -79,7 +87,7 @@ export class GasPriceOracle {
|
||||
instant: defaultFastGas * 1.3,
|
||||
fast: defaultFastGas,
|
||||
standard: defaultFastGas * 0.85,
|
||||
low: defaultFastGas * 0.5
|
||||
low: defaultFastGas * 0.5,
|
||||
};
|
||||
this.lastGasPrice = this.lastGasPrice || fallbackGasPrices || defaultFallbackGasPrices;
|
||||
try {
|
||||
@ -95,7 +103,7 @@ export class GasPriceOracle {
|
||||
instant: fastGas * 1.3,
|
||||
fast: fastGas,
|
||||
standard: fastGas * 0.85,
|
||||
low: fastGas * 0.5
|
||||
low: fastGas * 0.5,
|
||||
};
|
||||
return this.lastGasPrice;
|
||||
} catch (e) {
|
||||
|
@ -11,11 +11,11 @@ let oracle = new GasPriceOracle();
|
||||
before('before', function () {
|
||||
let axiosMock = {
|
||||
get: () => {
|
||||
throw new Error('axios GET methdod is mocked for tests');
|
||||
throw new Error('axios GET method is mocked for tests');
|
||||
},
|
||||
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);
|
||||
});
|
||||
@ -43,7 +43,9 @@ describe('fetchGasPricesOffChain', function () {
|
||||
mockery.enable({ useCleanCache: true, warnOnUnregistered: false });
|
||||
const { GasPriceOracle } = require('../src/index');
|
||||
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();
|
||||
});
|
||||
});
|
||||
@ -71,14 +73,18 @@ describe('fetchGasPricesOnChain', function () {
|
||||
it('should remove oracle', async function () {
|
||||
await oracle.fetchGasPricesOnChain();
|
||||
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 () {
|
||||
const { chainlink } = onChainOracles;
|
||||
await oracle.fetchGasPricesOnChain();
|
||||
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);
|
||||
const gas: number = await oracle.fetchGasPricesOnChain();
|
||||
|
||||
@ -90,10 +96,11 @@ describe('fetchGasPricesOnChain', function () {
|
||||
mockery.enable({ useCleanCache: true, warnOnUnregistered: false });
|
||||
const { GasPriceOracle } = require('../src/index');
|
||||
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();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('gasPrice', function () {
|
||||
|
@ -8,11 +8,11 @@
|
||||
"esnext.asynciterable",
|
||||
"es2019"
|
||||
] /* 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. */,
|
||||
"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'. */,
|
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
"declaration": true /* Generates corresponding '.d.ts' file. */,
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "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",
|
||||
"rules": {
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user