UNPKG

@sky-mavis/smart-order-router

Version:
72 lines 7.33 kB
import { BigNumber } from '@ethersproject/bignumber'; import { TokenFeeDetector__factory } from '../types/other/factories/TokenFeeDetector__factory'; import { log, metric, MetricLoggerUnit, WRAPPED_NATIVE_CURRENCY } from '../util'; const DEFAULT_TOKEN_BUY_FEE_BPS = BigNumber.from(0); const DEFAULT_TOKEN_SELL_FEE_BPS = BigNumber.from(0); // on detector failure, assume no fee export const DEFAULT_TOKEN_FEE_RESULT = { buyFeeBps: DEFAULT_TOKEN_BUY_FEE_BPS, sellFeeBps: DEFAULT_TOKEN_SELL_FEE_BPS, }; // address at which the FeeDetector lens is deployed const FEE_DETECTOR_ADDRESS = (chainId) => { switch (chainId) { default: // just default to mainnet contract return '0x19C97dc2a25845C7f9d1d519c8C2d4809c58b43f'; } }; // Amount has to be big enough to avoid rounding errors, but small enough that // most v2 pools will have at least this many token units // 100000 is the smallest number that avoids rounding errors in bps terms // 10000 was not sufficient due to rounding errors for rebase token (e.g. stETH) const AMOUNT_TO_FLASH_BORROW = '100000'; // 1M gas limit per validate call, should cover most swap cases const GAS_LIMIT_PER_VALIDATE = 1000000; export class OnChainTokenFeeFetcher { constructor(chainId, rpcProvider, tokenFeeAddress = FEE_DETECTOR_ADDRESS(chainId), gasLimitPerCall = GAS_LIMIT_PER_VALIDATE, amountToFlashBorrow = AMOUNT_TO_FLASH_BORROW) { var _a; this.chainId = chainId; this.tokenFeeAddress = tokenFeeAddress; this.gasLimitPerCall = gasLimitPerCall; this.amountToFlashBorrow = amountToFlashBorrow; this.BASE_TOKEN = (_a = WRAPPED_NATIVE_CURRENCY[this.chainId]) === null || _a === void 0 ? void 0 : _a.address; this.contract = TokenFeeDetector__factory.connect(this.tokenFeeAddress, rpcProvider); } async fetchFees(addresses, providerConfig) { const tokenToResult = {}; const addressesWithoutBaseToken = addresses.filter(address => address.toLowerCase() !== this.BASE_TOKEN.toLowerCase()); const functionParams = addressesWithoutBaseToken.map(address => [ address, this.BASE_TOKEN, this.amountToFlashBorrow, ]); const results = await Promise.all(functionParams.map(async ([address, baseToken, amountToBorrow]) => { try { // We use the validate function instead of batchValidate to avoid poison pill problem. // One token that consumes too much gas could cause the entire batch to fail. const feeResult = await this.contract.callStatic.validate(address, baseToken, amountToBorrow, { gasLimit: this.gasLimitPerCall, blockTag: providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.blockNumber, }); metric.putMetric('TokenFeeFetcherFetchFeesSuccess', 1, MetricLoggerUnit.Count); return { address, ...feeResult }; } catch (err) { log.error({ err }, `Error calling validate on-chain for token ${address}`); metric.putMetric('TokenFeeFetcherFetchFeesFailure', 1, MetricLoggerUnit.Count); // in case of FOT token fee fetch failure, we return null // so that they won't get returned from the token-fee-fetcher // and thus no fee will be applied, and the cache won't cache on FOT tokens with failed fee fetching return { address, buyFeeBps: undefined, sellFeeBps: undefined }; } })); results.forEach(({ address, buyFeeBps, sellFeeBps }) => { if (buyFeeBps || sellFeeBps) { tokenToResult[address] = { buyFeeBps, sellFeeBps }; } }); return tokenToResult; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4tZmVlLWZldGNoZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3Rva2VuLWZlZS1mZXRjaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUlyRCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxvREFBb0QsQ0FBQztBQUUvRixPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxnQkFBZ0IsRUFBRSx1QkFBdUIsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUdqRixNQUFNLHlCQUF5QixHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDcEQsTUFBTSwwQkFBMEIsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBRXJELHFDQUFxQztBQUNyQyxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRztJQUN0QyxTQUFTLEVBQUUseUJBQXlCO0lBQ3BDLFVBQVUsRUFBRSwwQkFBMEI7Q0FDdkMsQ0FBQztBQVVGLG9EQUFvRDtBQUNwRCxNQUFNLG9CQUFvQixHQUFHLENBQUMsT0FBZ0IsRUFBRSxFQUFFO0lBQ2hELFFBQVEsT0FBTyxFQUFFO1FBQ2Y7WUFDRSxtQ0FBbUM7WUFDbkMsT0FBTyw0Q0FBNEMsQ0FBQztLQUN2RDtBQUNILENBQUMsQ0FBQztBQUVGLDhFQUE4RTtBQUM5RSx5REFBeUQ7QUFDekQseUVBQXlFO0FBQ3pFLGdGQUFnRjtBQUNoRixNQUFNLHNCQUFzQixHQUFHLFFBQVEsQ0FBQztBQUN4QywrREFBK0Q7QUFDL0QsTUFBTSxzQkFBc0IsR0FBRyxPQUFTLENBQUM7QUFNekMsTUFBTSxPQUFPLHNCQUFzQjtJQUlqQyxZQUNVLE9BQWdCLEVBQ3hCLFdBQXlCLEVBQ2pCLGtCQUFrQixvQkFBb0IsQ0FBQyxPQUFPLENBQUMsRUFDL0Msa0JBQWtCLHNCQUFzQixFQUN4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