@maxosllc/smart-order-router
Version:
BlockDAG Smart Order Router
228 lines • 19.6 kB
JavaScript
import { ChainId } from '../../src/util/chains';
import { Token } from '@uniswap/sdk-core';
import _ from 'lodash';
import { log, WRAPPED_NATIVE_CURRENCY } from '../util';
import { BTC_BNB, BUSD_BNB, CELO, CELO_ALFAJORES, CEUR_CELO, CUSD_CELO, CUSD_CELO_ALFAJORES, DAI_ARBITRUM, DAI_ARBITRUM_SEPOLIA, DAI_AVAX, DAI_BNB, DAI_CELO, DAI_CELO_ALFAJORES, DAI_MAINNET, DAI_MOONBEAM, DAI_OPTIMISM, DAI_OPTIMISM_GOERLI, DAI_OPTIMISM_SEPOLIA, DAI_POLYGON_MUMBAI, DAI_UNICHAIN, ETH_BNB, USDB_BLAST, USDC_ARBITRUM, USDC_ARBITRUM_GOERLI, USDC_ARBITRUM_SEPOLIA, USDC_AVAX, USDC_BASE, USDC_BASE_SEPOLIA, USDC_BNB, USDC_ETHEREUM_GNOSIS, USDC_MAINNET, USDC_MOONBEAM, USDC_OPTIMISM, USDC_OPTIMISM_GOERLI, USDC_OPTIMISM_SEPOLIA, USDC_POLYGON, USDC_SEPOLIA, USDC_SONEIUM, USDC_UNICHAIN, USDC_WORLDCHAIN, USDT_ARBITRUM, USDT_BNB, USDT_MAINNET, USDT_MONAD_TESTNET, USDT_OPTIMISM, USDT_OPTIMISM_GOERLI, USDT_OPTIMISM_SEPOLIA, WBTC_ARBITRUM, WBTC_MAINNET, WBTC_MOONBEAM, WBTC_OPTIMISM, WBTC_OPTIMISM_GOERLI, WBTC_OPTIMISM_SEPOLIA, WBTC_WORLDCHAIN, WLD_WORLDCHAIN, WMATIC_POLYGON, WMATIC_POLYGON_MUMBAI, } from './token-provider';
// These tokens will added to the Token cache on initialization.
export const CACHE_SEED_TOKENS = {
[ChainId.MAINNET]: {
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.MAINNET],
USDC: USDC_MAINNET,
USDT: USDT_MAINNET,
WBTC: WBTC_MAINNET,
DAI: DAI_MAINNET,
// This token stores its symbol as bytes32, therefore can not be fetched on-chain using
// our token providers.
// This workaround adds it to the cache, so we won't try to fetch it on-chain.
RING: new Token(ChainId.MAINNET, '0x9469D013805bFfB7D3DEBe5E7839237e535ec483', 18, 'RING', 'RING'),
},
[ChainId.SEPOLIA]: {
USDC: USDC_SEPOLIA,
},
[ChainId.OPTIMISM]: {
USDC: USDC_OPTIMISM,
USDT: USDT_OPTIMISM,
WBTC: WBTC_OPTIMISM,
DAI: DAI_OPTIMISM,
},
[ChainId.OPTIMISM_GOERLI]: {
USDC: USDC_OPTIMISM_GOERLI,
USDT: USDT_OPTIMISM_GOERLI,
WBTC: WBTC_OPTIMISM_GOERLI,
DAI: DAI_OPTIMISM_GOERLI,
},
[ChainId.OPTIMISM_SEPOLIA]: {
USDC: USDC_OPTIMISM_SEPOLIA,
USDT: USDT_OPTIMISM_SEPOLIA,
WBTC: WBTC_OPTIMISM_SEPOLIA,
DAI: DAI_OPTIMISM_SEPOLIA,
},
[ChainId.ARBITRUM_ONE]: {
USDC: USDC_ARBITRUM,
USDT: USDT_ARBITRUM,
WBTC: WBTC_ARBITRUM,
DAI: DAI_ARBITRUM,
},
[ChainId.ARBITRUM_GOERLI]: {
USDC: USDC_ARBITRUM_GOERLI,
},
[ChainId.ARBITRUM_SEPOLIA]: {
USDC: USDC_ARBITRUM_SEPOLIA,
DAI: DAI_ARBITRUM_SEPOLIA,
},
[ChainId.POLYGON]: {
WMATIC: WMATIC_POLYGON,
USDC: USDC_POLYGON,
},
[ChainId.POLYGON_MUMBAI]: {
WMATIC: WMATIC_POLYGON_MUMBAI,
DAI: DAI_POLYGON_MUMBAI,
},
[ChainId.CELO]: {
CELO: CELO,
CUSD: CUSD_CELO,
CEUR: CEUR_CELO,
DAI: DAI_CELO,
},
[ChainId.CELO_ALFAJORES]: {
CELO: CELO_ALFAJORES,
CUSD: CUSD_CELO_ALFAJORES,
CEUR: CUSD_CELO_ALFAJORES,
DAI: DAI_CELO_ALFAJORES,
},
[ChainId.GNOSIS]: {
WXDAI: WRAPPED_NATIVE_CURRENCY[ChainId.GNOSIS],
USDC_ETHEREUM_GNOSIS: USDC_ETHEREUM_GNOSIS,
},
[ChainId.MOONBEAM]: {
USDC: USDC_MOONBEAM,
DAI: DAI_MOONBEAM,
WBTC: WBTC_MOONBEAM,
WGLMR: WRAPPED_NATIVE_CURRENCY[ChainId.MOONBEAM],
},
[ChainId.BNB]: {
USDC: USDC_BNB,
USDT: USDT_BNB,
BUSD: BUSD_BNB,
ETH: ETH_BNB,
DAI: DAI_BNB,
BTC: BTC_BNB,
WBNB: WRAPPED_NATIVE_CURRENCY[ChainId.BNB],
},
[ChainId.AVALANCHE]: {
USDC: USDC_AVAX,
DAI: DAI_AVAX,
WAVAX: WRAPPED_NATIVE_CURRENCY[ChainId.AVALANCHE],
},
[ChainId.BASE]: {
USDC: USDC_BASE,
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.BASE],
},
[ChainId.BLAST]: {
USDB: USDB_BLAST,
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.BLAST],
},
[ChainId.ZORA]: {
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.ZORA],
},
[ChainId.ZKSYNC]: {
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.ZKSYNC],
},
[ChainId.WORLDCHAIN]: {
USDC: USDC_WORLDCHAIN,
WLD: WLD_WORLDCHAIN,
WBTC: WBTC_WORLDCHAIN,
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.WORLDCHAIN],
},
[ChainId.UNICHAIN_SEPOLIA]: {
USDC: USDC_SEPOLIA,
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.UNICHAIN_SEPOLIA],
},
[ChainId.MONAD_TESTNET]: {
USDT: USDT_MONAD_TESTNET,
WMON: WRAPPED_NATIVE_CURRENCY[ChainId.MONAD_TESTNET],
},
[ChainId.BASE_SEPOLIA]: {
USDC: USDC_BASE_SEPOLIA,
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.BASE_SEPOLIA],
},
[ChainId.UNICHAIN]: {
DAI: DAI_UNICHAIN,
USDC: USDC_UNICHAIN,
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.UNICHAIN],
},
[ChainId.SONEIUM]: {
USDC: USDC_SONEIUM,
WETH: WRAPPED_NATIVE_CURRENCY[ChainId.SONEIUM],
},
// Currently we do not have providers for Moonbeam mainnet or Gnosis testnet
};
/**
* Provider for getting token metadata that falls back to a different provider
* in the event of failure.
*
* @export
* @class CachingTokenProviderWithFallback
*/
export class CachingTokenProviderWithFallback {
constructor(chainId,
// Token metadata (e.g. symbol and decimals) don't change so can be cached indefinitely.
// Constructing a new token object is slow as sdk-core does checksumming.
tokenCache, primaryTokenProvider, fallbackTokenProvider) {
this.chainId = chainId;
this.tokenCache = tokenCache;
this.primaryTokenProvider = primaryTokenProvider;
this.fallbackTokenProvider = fallbackTokenProvider;
this.CACHE_KEY = (chainId, address) => `token-${chainId}-${address}`;
}
async getTokens(_addresses) {
const seedTokens = CACHE_SEED_TOKENS[this.chainId];
if (seedTokens) {
for (const token of Object.values(seedTokens)) {
await this.tokenCache.set(this.CACHE_KEY(this.chainId, token.address.toLowerCase()), token);
}
}
const addressToToken = {};
const symbolToToken = {};
const addresses = _(_addresses)
.map((address) => address.toLowerCase())
.uniq()
.value();
const addressesToFindInPrimary = [];
const addressesToFindInSecondary = [];
for (const address of addresses) {
if (await this.tokenCache.has(this.CACHE_KEY(this.chainId, address))) {
addressToToken[address.toLowerCase()] = (await this.tokenCache.get(this.CACHE_KEY(this.chainId, address)));
symbolToToken[addressToToken[address].symbol] =
(await this.tokenCache.get(this.CACHE_KEY(this.chainId, address)));
}
else {
addressesToFindInPrimary.push(address);
}
}
log.info({ addressesToFindInPrimary }, `Found ${addresses.length - addressesToFindInPrimary.length} out of ${addresses.length} tokens in local cache. ${addressesToFindInPrimary.length > 0
? `Checking primary token provider for ${addressesToFindInPrimary.length} tokens`
: ``}
`);
if (addressesToFindInPrimary.length > 0) {
const primaryTokenAccessor = await this.primaryTokenProvider.getTokens(addressesToFindInPrimary);
for (const address of addressesToFindInPrimary) {
const token = primaryTokenAccessor.getTokenByAddress(address);
if (token) {
addressToToken[address.toLowerCase()] = token;
symbolToToken[addressToToken[address].symbol] = token;
await this.tokenCache.set(this.CACHE_KEY(this.chainId, address.toLowerCase()), addressToToken[address]);
}
else {
addressesToFindInSecondary.push(address);
}
}
log.info({ addressesToFindInSecondary }, `Found ${addressesToFindInPrimary.length - addressesToFindInSecondary.length} tokens in primary. ${this.fallbackTokenProvider
? `Checking secondary token provider for ${addressesToFindInSecondary.length} tokens`
: `No fallback token provider specified. About to return.`}`);
}
if (this.fallbackTokenProvider && addressesToFindInSecondary.length > 0) {
const secondaryTokenAccessor = await this.fallbackTokenProvider.getTokens(addressesToFindInSecondary);
for (const address of addressesToFindInSecondary) {
const token = secondaryTokenAccessor.getTokenByAddress(address);
if (token) {
addressToToken[address.toLowerCase()] = token;
symbolToToken[addressToToken[address].symbol] = token;
await this.tokenCache.set(this.CACHE_KEY(this.chainId, address.toLowerCase()), addressToToken[address]);
}
}
}
return {
getTokenByAddress: (address) => {
return addressToToken[address.toLowerCase()];
},
getTokenBySymbol: (symbol) => {
return symbolToToken[symbol.toLowerCase()];
},
getAllTokens: () => {
return Object.values(addressToToken);
},
};
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGluZy10b2tlbi1wcm92aWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcm92aWRlcnMvY2FjaGluZy10b2tlbi1wcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDaEQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzFDLE9BQU8sQ0FBQyxNQUFNLFFBQVEsQ0FBQztBQUV2QixPQUFPLEVBQUUsR0FBRyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sU0FBUyxDQUFDO0FBR3ZELE9BQU8sRUFDTCxPQUFPLEVBQ1AsUUFBUSxFQUNSLElBQUksRUFDSixjQUFjLEVBQ2QsU0FBUyxFQUNULFNBQVMsRUFDVCxtQkFBbUIsRUFDbkIsWUFBWSxFQUNaLG9CQUFvQixFQUNwQixRQUFRLEVBQ1IsT0FBTyxFQUNQLFFBQVEsRUFDUixrQkFBa0IsRUFDbEIsV0FBVyxFQUNYLFlBQVksRUFDWixZQUFZLEVBQ1osbUJBQW1CLEVBQ25CLG9CQUFvQixFQUNwQixrQkFBa0IsRUFDbEIsWUFBWSxFQUNaLE9BQU8sRUFHUCxVQUFVLEVBQ1YsYUFBYSxFQUNiLG9CQUFvQixFQUNwQixxQkFBcUIsRUFDckIsU0FBUyxFQUNULFNBQVMsRUFDVCxpQkFBaUIsRUFDakIsUUFBUSxFQUNSLG9CQUFvQixFQUNwQixZQUFZLEVBQ1osYUFBYSxFQUNiLGFBQWEsRUFDYixvQkFBb0IsRUFDcEIscUJBQXFCLEVBQ3JCLFlBQVksRUFDWixZQUFZLEVBQ1osWUFBWSxFQUNaLGFBQWEsRUFDYixlQUFlLEVBQ2YsYUFBYSxFQUNiLFFBQVEsRUFDUixZQUFZLEVBQ1osa0JBQWtCLEVBQ2xCLGFBQWEsRUFDYixvQkFBb0IsRUFDcEIscUJBQXFCLEVBQ3JCLGFBQWEsRUFDYixZQUFZLEVBQ1osYUFBYSxFQUNiLGFBQWEsRUFDYixvQkFBb0IsRUFD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