UNPKG

@sky-mavis/smart-order-router

Version:
76 lines 7.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OnChainTokenFeeFetcher = exports.DEFAULT_TOKEN_FEE_RESULT = void 0; const bignumber_1 = require("@ethersproject/bignumber"); const TokenFeeDetector__factory_1 = require("../types/other/factories/TokenFeeDetector__factory"); const util_1 = require("../util"); const DEFAULT_TOKEN_BUY_FEE_BPS = bignumber_1.BigNumber.from(0); const DEFAULT_TOKEN_SELL_FEE_BPS = bignumber_1.BigNumber.from(0); // on detector failure, assume no fee exports.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; 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 = util_1.WRAPPED_NATIVE_CURRENCY[this.chainId]) === null || _a === void 0 ? void 0 : _a.address; this.contract = TokenFeeDetector__factory_1.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, }); util_1.metric.putMetric('TokenFeeFetcherFetchFeesSuccess', 1, util_1.MetricLoggerUnit.Count); return Object.assign({ address }, feeResult); } catch (err) { util_1.log.error({ err }, `Error calling validate on-chain for token ${address}`); util_1.metric.putMetric('TokenFeeFetcherFetchFeesFailure', 1, util_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; } } exports.OnChainTokenFeeFetcher = OnChainTokenFeeFetcher; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4tZmVlLWZldGNoZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3Rva2VuLWZlZS1mZXRjaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHdEQUFxRDtBQUlyRCxrR0FBK0Y7QUFFL0Ysa0NBQWlGO0FBR2pGLE1BQU0seUJBQXlCLEdBQUcscUJBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDcEQsTUFBTSwwQkFBMEIsR0FBRyxxQkFBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUVyRCxxQ0FBcUM7QUFDeEIsUUFBQSx3QkFBd0IsR0FBRztJQUN0QyxTQUFTLEVBQUUseUJBQXlCO0lBQ3BDLFVBQVUsRUFBRSwwQkFBMEI7Q0FDdkMsQ0FBQztBQVVGLG9EQUFvRDtBQUNwRCxNQUFNLG9CQUFvQixHQUFHLENBQUMsT0FBZ0IsRUFBRSxFQUFFO0lBQ2hELFFBQVEsT0FBTyxFQUFFO1FBQ2Y7WUFDRSxtQ0FBbUM7WUFDbkMsT0FBTyw0Q0FBNEMsQ0FBQztLQUN2RDtBQUNILENBQUMsQ0FBQztBQUVGLDhFQUE4RTtBQUM5RSx5REFBeUQ7QUFDekQseUVBQXlFO0FBQ3pFLGdGQUFnRjtBQUNoRixNQUFNLHNCQUFzQixHQUFHLFFBQVEsQ0FBQztBQUN4QywrREFBK0Q7QUFDL0QsTUFBTSxzQkFBc0IsR0FBRyxPQUFTLENBQUM7QUFNekMsTUFBYSxzQkFBc0I7SUFJakMsWUFDVSxPQUFnQixFQUN4QixXQUF5QixFQUNqQixrQkFBa0Isb0JBQW9CLENBQUMsT0FBTyxDQUFDLEVBQy9DLGtCQUFrQixzQkFBc0IsRUFDeEMsc0JBQXNCLHNCQUFzQjs7UUFKNUMsWUFBTyxHQUFQLE9BQU8sQ0FBUztRQUVoQixvQkFBZSxHQUFmLGVBQWUsQ0FBZ0M7UUFDL0Msb0JBQWUsR0FBZixlQUFlLENBQXlCO1FBQ3hDLHdCQUFtQixHQUFuQixtQkFBbUIsQ0FBeUI7UUFF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