UNPKG

@sky-mavis/smart-order-router

Version:
119 lines 12.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TokenPropertiesProvider = exports.NEGATIVE_CACHE_ENTRY_TTL = exports.POSITIVE_CACHE_ENTRY_TTL = exports.DEFAULT_TOKEN_PROPERTIES_RESULT = void 0; const katana_core_1 = require("@sky-mavis/katana-core"); const util_1 = require("../util"); const token_fee_fetcher_1 = require("./token-fee-fetcher"); const token_validator_provider_1 = require("./token-validator-provider"); exports.DEFAULT_TOKEN_PROPERTIES_RESULT = { tokenFeeResult: token_fee_fetcher_1.DEFAULT_TOKEN_FEE_RESULT, }; exports.POSITIVE_CACHE_ENTRY_TTL = 1200; // 20 minutes in seconds exports.NEGATIVE_CACHE_ENTRY_TTL = 1200; // 20 minutes in seconds class TokenPropertiesProvider { constructor(chainId, tokenPropertiesCache, tokenFeeFetcher, allowList = token_validator_provider_1.DEFAULT_ALLOWLIST, positiveCacheEntryTTL = exports.POSITIVE_CACHE_ENTRY_TTL, negativeCacheEntryTTL = exports.NEGATIVE_CACHE_ENTRY_TTL) { this.chainId = chainId; this.tokenPropertiesCache = tokenPropertiesCache; this.tokenFeeFetcher = tokenFeeFetcher; this.allowList = allowList; this.positiveCacheEntryTTL = positiveCacheEntryTTL; this.negativeCacheEntryTTL = negativeCacheEntryTTL; this.CACHE_KEY = (chainId, address) => `token-properties-${chainId}-${address}`; } async getTokensProperties(tokens, providerConfig) { const tokenToResult = {}; if (!(providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.enableFeeOnTransferFeeFetching) || this.chainId !== katana_core_1.ChainId.mainnet) { return tokenToResult; } const addressesToFetchFeesOnchain = []; const addressesRaw = this.buildAddressesRaw(tokens); const addressesCacheKeys = this.buildAddressesCacheKeys(tokens); const tokenProperties = await this.tokenPropertiesCache.batchGet(addressesCacheKeys); // Check if we have cached token validation results for any tokens. for (const address of addressesRaw) { const cachedValue = tokenProperties[this.CACHE_KEY(this.chainId, address.toLowerCase())]; if (cachedValue) { util_1.metric.putMetric('TokenPropertiesProviderBatchGetCacheHit', 1, util_1.MetricLoggerUnit.Count); const tokenFee = cachedValue.tokenFeeResult; const tokenFeeResultExists = tokenFee && (tokenFee.buyFeeBps || tokenFee.sellFeeBps); if (tokenFeeResultExists) { util_1.metric.putMetric(`TokenPropertiesProviderCacheHitTokenFeeResultExists${tokenFeeResultExists}`, 1, util_1.MetricLoggerUnit.Count); } else { util_1.metric.putMetric(`TokenPropertiesProviderCacheHitTokenFeeResultNotExists`, 1, util_1.MetricLoggerUnit.Count); } tokenToResult[address] = cachedValue; } else if (this.allowList.has(address)) { tokenToResult[address] = { tokenValidationResult: token_validator_provider_1.TokenValidationResult.UNKN, }; } else { addressesToFetchFeesOnchain.push(address); } } if (addressesToFetchFeesOnchain.length > 0) { let tokenFeeMap = {}; try { tokenFeeMap = await this.tokenFeeFetcher.fetchFees(addressesToFetchFeesOnchain, providerConfig); } catch (err) { util_1.log.error({ err }, `Error fetching fees for tokens ${addressesToFetchFeesOnchain}`); } await Promise.all(addressesToFetchFeesOnchain.map(address => { const tokenFee = tokenFeeMap[address]; const tokenFeeResultExists = tokenFee && (tokenFee.buyFeeBps || tokenFee.sellFeeBps); if (tokenFeeResultExists) { // we will leverage the metric to log the token fee result, if it exists // the idea is that the token fee should not differ by too much across tokens, // so that we can accurately log the token fee for a particular quote request (without breaching metrics dimensionality limit) // in the form of metrics. // if we log as logging, given prod traffic volume, the logging volume will be high. util_1.metric.putMetric(`TokenPropertiesProviderTokenFeeResultCacheMissExists${tokenFeeResultExists}`, 1, util_1.MetricLoggerUnit.Count); const tokenPropertiesResult = { tokenFeeResult: tokenFee, tokenValidationResult: token_validator_provider_1.TokenValidationResult.FOT, }; tokenToResult[address] = tokenPropertiesResult; util_1.metric.putMetric('TokenPropertiesProviderBatchGetCacheMiss', 1, util_1.MetricLoggerUnit.Count); // update cache concurrently // at this point, we are confident that the tokens are FOT, so we can hardcode the validation result return this.tokenPropertiesCache.set(this.CACHE_KEY(this.chainId, address), tokenPropertiesResult, this.positiveCacheEntryTTL); } else { util_1.metric.putMetric(`TokenPropertiesProviderTokenFeeResultCacheMissNotExists`, 1, util_1.MetricLoggerUnit.Count); const tokenPropertiesResult = { tokenFeeResult: undefined, tokenValidationResult: undefined, }; tokenToResult[address] = tokenPropertiesResult; return this.tokenPropertiesCache.set(this.CACHE_KEY(this.chainId, address), tokenPropertiesResult, this.negativeCacheEntryTTL); } })); } return tokenToResult; } buildAddressesRaw(tokens) { const addressesRaw = new Set(); for (const token of tokens) { const address = token.address.toLowerCase(); if (!addressesRaw.has(address)) { addressesRaw.add(address); } } return addressesRaw; } buildAddressesCacheKeys(tokens) { const addressesCacheKeys = new Set(); for (const token of tokens) { const addressCacheKey = this.CACHE_KEY(this.chainId, token.address.toLowerCase()); if (!addressesCacheKeys.has(addressCacheKey)) { addressesCacheKeys.add(addressCacheKey); } } return addressesCacheKeys; } } exports.TokenPropertiesProvider = TokenPropertiesProvider; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4tcHJvcGVydGllcy1wcm92aWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcm92aWRlcnMvdG9rZW4tcHJvcGVydGllcy1wcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSx3REFBaUQ7QUFHakQsa0NBQXdEO0FBR3hELDJEQUE4RztBQUM5Ryx5RUFBc0Y7QUFFekUsUUFBQSwrQkFBK0IsR0FBMEI7SUFDcEUsY0FBYyxFQUFFLDRDQUF3QjtDQUN6QyxDQUFDO0FBQ1csUUFBQSx3QkFBd0IsR0FBRyxJQUFJLENBQUMsQ0FBQyx3QkFBd0I7QUFDekQsUUFBQSx3QkFBd0IsR0FBRyxJQUFJLENBQUMsQ0FBQyx3QkFBd0I7QUFhdEUsTUFBYSx1QkFBdUI7SUFHbEMsWUFDVSxPQUFnQixFQUNoQixvQkFBbUQsRUFDbkQsZUFBaUMsRUFDakMsWUFBWSw0Q0FBaUIsRUFDN0Isd0JBQXdCLGdDQUF3QixFQUNoRCx3QkFBd0IsZ0NBQXdCO1FBTGhELFlBQU8sR0FBUCxPQUFPLENBQVM7UUFDaEIseUJBQW9CLEdBQXBCLG9CQUFvQixDQUErQjtRQUNuRCxvQkFBZSxHQUFmLGVBQWUsQ0FBa0I7UUFDakMsY0FBUyxHQUFULFNBQVMsQ0FBb0I7UUFDN0IsMEJBQXFCLEdBQXJCLHFCQUFxQixDQUEyQjtRQUNoRCwwQkFBcUIsR0FBckIscUJBQXFCLENBQTJCO1FBUmxELGNBQVMsR0FBRyxDQUFDLE9BQWdCLEVBQUUsT0FBZSxFQUFFLEVBQUUsQ0FBQyxvQkFBb0IsT0FBTyxJQUFJLE9BQU8sRUFBRSxDQUFDO0lBU2pHLENBQUM7SUFFRyxLQUFLLENBQUMsbUJBQW1CLENBQUMsTUFBZSxFQUFFLGNBQStCO1FBQy9FLE1BQU0sYUFBYSxHQUF1QixFQUFFLENBQUM7UUFFN0MsSUFBSSxDQUFDLENBQUEsY0FBYyxhQUFkLGNBQWMsdUJBQWQsY0FBYyxDQUFFLDhCQUE4QixDQUFBLElBQUksSUFBSSxDQUFD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