Files
protocol/packages/asset-swapper/src/utils/protocol_fee_utils.ts
Lawrence Forman 6ac7dd006c @0x/asset-swapper: hack together basic sampler service integration
`@0x/asset-swapper`: use gasCost from sampler service

cleanup

`@0x/asset-swapper`: Handle per-fill gas cost correctly in more places

getting multihop back up + refactors for treating all quotes as n-hop

multihop with nice breakdowns

get vips working

get multiplex working

get rfq working

remove unused functions

fix multihop buys

plz work multihop buys

multihop buys seem ok now.
fetch less samples for multihop legs

get quote report and price comparisons working

clean up
2022-03-16 12:16:07 -04:00

93 lines
3.4 KiB
TypeScript

import { BigNumber } from '@0x/utils';
import * as heartbeats from 'heartbeats';
import fetch from 'axios';
import { constants } from '../constants';
import { SwapQuoterError } from '../types';
const MAX_ERROR_COUNT = 5;
export class ProtocolFeeUtils {
private static _instance: ProtocolFeeUtils;
private readonly _ethGasStationUrl!: 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,
initialGasPrice: BigNumber = constants.ZERO_AMOUNT,
): ProtocolFeeUtils {
if (!ProtocolFeeUtils._instance) {
ProtocolFeeUtils._instance = new ProtocolFeeUtils(
gasPricePollingIntervalInMs,
ethGasStationUrl,
initialGasPrice,
);
}
return ProtocolFeeUtils._instance;
}
public async getGasPriceEstimationOrThrowAsync(shouldHardRefresh?: boolean): Promise<BigNumber> {
if (this._gasPriceEstimation.eq(constants.ZERO_AMOUNT)) {
return this._getGasPriceFromGasStationOrThrowAsync();
}
if (shouldHardRefresh) {
return this._getGasPriceFromGasStationOrThrowAsync();
} else {
return this._gasPriceEstimation;
}
}
/**
* Destroys any subscriptions or connections.
*/
public async destroyAsync(): Promise<void> {
this._gasPriceHeart.kill();
}
private constructor(
gasPricePollingIntervalInMs: number,
ethGasStationUrl: string = constants.ETH_GAS_STATION_API_URL,
initialGasPrice: BigNumber = constants.ZERO_AMOUNT,
) {
this._gasPriceHeart = heartbeats.createHeart(gasPricePollingIntervalInMs);
this._gasPriceEstimation = initialGasPrice;
this._ethGasStationUrl = ethGasStationUrl;
this._initializeHeartBeat();
}
// tslint:disable-next-line: prefer-function-over-method
private async _getGasPriceFromGasStationOrThrowAsync(): Promise<BigNumber> {
try {
const res = await fetch(this._ethGasStationUrl);
const gasInfo = res.data;
// 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);
// Reset the error count to 0 once we have a successful response
this._errorCount = 0;
return gasPriceWei;
} catch (e) {
this._errorCount++;
// If we've reached our max error count then throw
if (this._errorCount > MAX_ERROR_COUNT || this._gasPriceEstimation.isZero()) {
this._errorCount = 0;
throw new Error(SwapQuoterError.NoGasPriceProvidedOrEstimated);
}
return this._gasPriceEstimation;
}
}
private _initializeHeartBeat(): void {
this._gasPriceHeart.createEvent(1, async () => {
this._gasPriceEstimation = await this._getGasPriceFromGasStationOrThrowAsync();
});
}
}