Use 0x gas api instead of eth gas station api [TKR-502] (#532)
* Use 0x gas api instead of eth gas station api * Add integration test for `ProtocolFeeUtils` * Update CHANGELOG.json
This commit is contained in:
parent
3ef5de93bb
commit
d6d79e51e7
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "16.65.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Use 0x gas api instead of eth gas station api",
|
||||
"pr": 532
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "16.64.0",
|
||||
"changes": [
|
||||
|
@ -109,6 +109,7 @@
|
||||
"dirty-chai": "^2.0.1",
|
||||
"gitpkg": "https://github.com/0xProject/gitpkg.git",
|
||||
"mocha": "^6.2.0",
|
||||
"msw": "^0.44.2",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"nyc": "^11.0.1",
|
||||
"shx": "^0.2.2",
|
||||
|
@ -19,7 +19,7 @@ import {
|
||||
DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID,
|
||||
} from './utils/market_operation_utils/constants';
|
||||
|
||||
const ETH_GAS_STATION_API_URL = 'https://ethgasstation.info/api/ethgasAPI.json';
|
||||
const ZERO_EX_GAS_API_URL = 'https://gas.api.0x.org/source/median';
|
||||
const NULL_BYTES = '0x';
|
||||
const NULL_ERC20_ASSET_DATA = '0xf47261b00000000000000000000000000000000000000000000000000000000000000000';
|
||||
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||
@ -48,7 +48,7 @@ const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
|
||||
orderRefreshIntervalMs: 10000, // 10 seconds
|
||||
...DEFAULT_ORDER_PRUNER_OPTS,
|
||||
samplerGasLimit: 500e6,
|
||||
ethGasStationUrl: ETH_GAS_STATION_API_URL,
|
||||
zeroExGasApiUrl: ZERO_EX_GAS_API_URL,
|
||||
rfqt: {
|
||||
integratorsWhitelist: [],
|
||||
makerAssetOfferings: {},
|
||||
@ -99,7 +99,7 @@ export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(30000);
|
||||
export const KEEP_ALIVE_TTL = 5 * 60 * ONE_SECOND_MS;
|
||||
|
||||
export const constants = {
|
||||
ETH_GAS_STATION_API_URL,
|
||||
ZERO_EX_GAS_API_URL,
|
||||
PROTOCOL_FEE_MULTIPLIER,
|
||||
POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS,
|
||||
NULL_BYTES,
|
||||
|
@ -109,7 +109,7 @@ export class SwapQuoter {
|
||||
};
|
||||
this._protocolFeeUtils = ProtocolFeeUtils.getInstance(
|
||||
constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS,
|
||||
options.ethGasStationUrl,
|
||||
options.zeroExGasApiUrl,
|
||||
);
|
||||
// Allow the sampler bytecode to be overwritten using geths override functionality
|
||||
const samplerBytecode = _.get(artifacts.ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object');
|
||||
|
@ -337,7 +337,7 @@ export interface SwapQuoterOpts extends OrderPrunerOpts {
|
||||
contractAddresses?: AssetSwapperContractAddresses;
|
||||
samplerGasLimit?: number;
|
||||
multiBridgeAddress?: string;
|
||||
ethGasStationUrl?: string;
|
||||
zeroExGasApiUrl?: string;
|
||||
rfqt?: SwapQuoterRfqOpts;
|
||||
samplerOverrides?: SamplerOverrides;
|
||||
tokenAdjacencyGraph?: TokenAdjacencyGraph;
|
||||
|
@ -6,28 +6,36 @@ import { SwapQuoterError } from '../types';
|
||||
|
||||
const MAX_ERROR_COUNT = 5;
|
||||
|
||||
interface GasOracleResponse {
|
||||
result: {
|
||||
// gas price in wei
|
||||
fast: number;
|
||||
};
|
||||
}
|
||||
|
||||
export class ProtocolFeeUtils {
|
||||
private static _instance: ProtocolFeeUtils;
|
||||
private readonly _ethGasStationUrl!: string;
|
||||
private readonly _zeroExGasApiUrl: string;
|
||||
private readonly _gasPriceHeart: any;
|
||||
private _gasPriceEstimation: BigNumber = constants.ZERO_AMOUNT;
|
||||
private _errorCount: number = 0;
|
||||
|
||||
public static getInstance(
|
||||
gasPricePollingIntervalInMs: number,
|
||||
ethGasStationUrl: string = constants.ETH_GAS_STATION_API_URL,
|
||||
zeroExGasApiUrl: string = constants.ZERO_EX_GAS_API_URL,
|
||||
initialGasPrice: BigNumber = constants.ZERO_AMOUNT,
|
||||
): ProtocolFeeUtils {
|
||||
if (!ProtocolFeeUtils._instance) {
|
||||
ProtocolFeeUtils._instance = new ProtocolFeeUtils(
|
||||
gasPricePollingIntervalInMs,
|
||||
ethGasStationUrl,
|
||||
zeroExGasApiUrl,
|
||||
initialGasPrice,
|
||||
);
|
||||
}
|
||||
return ProtocolFeeUtils._instance;
|
||||
}
|
||||
|
||||
/** @returns gas price (in wei) */
|
||||
public async getGasPriceEstimationOrThrowAsync(shouldHardRefresh?: boolean): Promise<BigNumber> {
|
||||
if (this._gasPriceEstimation.eq(constants.ZERO_AMOUNT)) {
|
||||
return this._getGasPriceFromGasStationOrThrowAsync();
|
||||
@ -48,27 +56,21 @@ export class ProtocolFeeUtils {
|
||||
|
||||
private constructor(
|
||||
gasPricePollingIntervalInMs: number,
|
||||
ethGasStationUrl: string = constants.ETH_GAS_STATION_API_URL,
|
||||
zeroExGasApiUrl: string = constants.ZERO_EX_GAS_API_URL,
|
||||
initialGasPrice: BigNumber = constants.ZERO_AMOUNT,
|
||||
) {
|
||||
this._gasPriceHeart = heartbeats.createHeart(gasPricePollingIntervalInMs);
|
||||
this._gasPriceEstimation = initialGasPrice;
|
||||
this._ethGasStationUrl = ethGasStationUrl;
|
||||
this._zeroExGasApiUrl = zeroExGasApiUrl;
|
||||
this._initializeHeartBeat();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: prefer-function-over-method
|
||||
private async _getGasPriceFromGasStationOrThrowAsync(): Promise<BigNumber> {
|
||||
try {
|
||||
const res = await fetch(this._ethGasStationUrl);
|
||||
const gasInfo = await res.json();
|
||||
// Eth Gas Station result is gwei * 10
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const BASE_TEN = 10;
|
||||
const gasPriceGwei = new BigNumber(gasInfo.fast / BASE_TEN);
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const unit = new BigNumber(BASE_TEN).pow(9);
|
||||
const gasPriceWei = unit.times(gasPriceGwei);
|
||||
const res = await fetch(this._zeroExGasApiUrl);
|
||||
const gasInfo: GasOracleResponse = await res.json();
|
||||
const gasPriceWei = new BigNumber(gasInfo.result.fast);
|
||||
// Reset the error count to 0 once we have a successful response
|
||||
this._errorCount = 0;
|
||||
return gasPriceWei;
|
||||
|
45
packages/asset-swapper/test/protocol_fee_utils_test.ts
Normal file
45
packages/asset-swapper/test/protocol_fee_utils_test.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import * as chai from 'chai';
|
||||
import 'mocha';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
|
||||
import { ProtocolFeeUtils } from '../src';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
const server = setupServer(
|
||||
rest.get('https://mock-0x-gas-api.org/median', (_req, res, ctx) => {
|
||||
return res(
|
||||
ctx.json({
|
||||
result: {
|
||||
source: 'MEDIAN',
|
||||
timestamp: 1659386474,
|
||||
instant: 22000000000,
|
||||
fast: 18848500000,
|
||||
standard: 14765010000,
|
||||
low: 13265000000,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
describe('ProtocolFeeUtils', () => {
|
||||
describe('getGasPriceEstimationOrThrowAsync', () => {
|
||||
beforeEach(() => {
|
||||
server.listen();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
server.close();
|
||||
});
|
||||
|
||||
it('parses fast gas price response correctly', async () => {
|
||||
const utils = ProtocolFeeUtils.getInstance(420000, 'https://mock-0x-gas-api.org/median');
|
||||
const gasPrice = await utils.getGasPriceEstimationOrThrowAsync();
|
||||
expect(gasPrice.toNumber()).to.eq(18848500000);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": ["@0x/tslint-config"],
|
||||
"rules": {
|
||||
"custom-no-magic-numbers": false,
|
||||
"max-file-line-count": false,
|
||||
"binary-expression-operand-order": false
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user