import { V2PoolProvider, ChainId, UniswapMulticallProvider, V2QuoteProvider, OnChainQuoteProvider, StaticV2SubgraphProvider, AlphaRouter, routeAmountsToString } from '@brydge-network/smart-order-router';
import { Token, CurrencyAmount } from '@uniswap/sdk-core';
import { B as BASES_TO_CHECK_TRADES_AGAINST, i as isExactInput, S as SupportedChainId, N as NO_ROUTE } from './index-2abb912e.js';
import JSBI from 'jsbi';
import { getCreate2Address } from '@ethersproject/address';
import { keccak256, pack } from '@ethersproject/solidity';
import { Pair } from '@uniswap/v2-sdk';
import { Protocol } from '@uniswap/router-sdk';
import 'buffer';
import 'jotai';
import 'jotai/utils';
import 'react';
import 'jotai/immer';
import 'tiny-invariant';
import '@ethersproject/units';
import '@ethersproject/abi';
import '@ethersproject/providers';
import '@web3-react/core';
import '@web3-react/eip1193';
import '@web3-react/empty';
import '@web3-react/url';
import '@web3-react/types';
import 'react/jsx-dev-runtime';
import '@uniswap/redux-multicall';
import '@ethersproject/constants';
import '@ethersproject/contracts';
import '@reduxjs/toolkit/query/react';
import '@reduxjs/toolkit';
import 'qs';
import '@uniswap/v3-sdk';
import 'ethers';
import '@brydge-network/token-list';
import '@ethersproject/hash';
import '@brydge-network/utils';
import 'firebase/database';
import 'firebase/app';
import 'cids';
import 'multicodec';
import 'multihashes';
import 'styled-components';
import 'react-feather';
import 'rebass';
import 'wicg-inert';
import 'react-dom';
import 'polished';
import 'wcag-contrast';
import 'popper-max-size-modifier';
import 'react-popper';
import '@babel/runtime/helpers/slicedToArray';
import '@babel/runtime/helpers/defineProperty';
import 'node-vibrant/lib/bundle.js';
import 'setimmediate';
import '@babel/runtime/helpers/classCallCheck';
import '@babel/runtime/helpers/createClass';
import '@babel/runtime/helpers/inherits';
import '@babel/runtime/helpers/possibleConstructorReturn';
import '@babel/runtime/helpers/getPrototypeOf';
import '@babel/runtime/helpers/objectWithoutProperties';
import 'react-virtualized-auto-sizer';
import 'react-window';
import '@ethersproject/bytes';
import '@ethersproject/bignumber';
import 'axios';
import 'make-plural/plurals';
import 'react-redux';
import 'redux';

const FACTORY_ADDRESS$1 = '0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32';
const INIT_CODE_HASH$1 = '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f';
const computePairAddress$1 = _ref => {
  let {
    factoryAddress,
    tokenA,
    tokenB
  } = _ref;
  const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA];
  return getCreate2Address(factoryAddress, keccak256(['bytes'], [pack(['address', 'address'], [token0.address, token1.address])]), INIT_CODE_HASH$1);
};
class QuickswapPair extends Pair {
  static getAddress(tokenA, tokenB) {
    return computePairAddress$1({
      factoryAddress: FACTORY_ADDRESS$1,
      tokenA,
      tokenB
    });
  }
}

/**
 * Provider that does not get data from an external source and instead returns
 * a hardcoded list of Subgraph pools.
 *
 * Since the pools are hardcoded, the liquidity/price values are dummies and should not
 * be depended on.
 *
 * Useful for instances where other data sources are unavailable. E.g. subgraph not available.
 *
 * @export
 * @class StaticV2SubgraphProvider
 */
class QuickswapStaticV2SubgraphProvider {
  constructor(chainId) {
    this.chainId = chainId;
  }
  async getPools(tokenIn, tokenOut) {
    const bases = BASES_TO_CHECK_TRADES_AGAINST[this.chainId];
    if (!bases) {
      return [];
    }
    const basePairs = bases.flatMap(base => bases.map(otherBase => [base, otherBase]));
    if (tokenIn && tokenOut) {
      basePairs.push([tokenIn, tokenOut], ...bases.map(base => [tokenIn, base]), ...bases.map(base => [tokenOut, base]));
    }
    const pairs = basePairs.filter(tokens => Boolean(tokens[0] && tokens[1])).filter(_ref => {
      let [tokenA, tokenB] = _ref;
      return tokenA.address !== tokenB.address && !tokenA.equals(tokenB);
    });
    const poolAddressSet = new Set();
    const subgraphPools = pairs.map(_ref2 => {
      let [tokenA, tokenB] = _ref2;
      const poolAddress = QuickswapPair.getAddress(tokenA, tokenB);
      if (poolAddressSet.has(poolAddress)) {
        return undefined;
      }
      poolAddressSet.add(poolAddress);
      const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA];
      return {
        id: poolAddress,
        liquidity: '100',
        token0: {
          id: token0.address
        },
        token1: {
          id: token1.address
        },
        supply: 100,
        reserve: 100,
        reserveUSD: 100
      };
    }).filter(v => !!v);
    return subgraphPools;
  }
}

class QuickswapV2PoolProvider extends V2PoolProvider {
  POOL_ADDRESS_CACHE_2 = {};
  getPoolAddress(tokenA, tokenB) {
    const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA];
    const cacheKey = `${this.chainId}/${token0.address}/${token1.address}`;
    const cachedAddress = this.POOL_ADDRESS_CACHE_2[cacheKey];
    if (cachedAddress) {
      return {
        poolAddress: cachedAddress,
        token0,
        token1
      };
    }
    const poolAddress = QuickswapPair.getAddress(token0, token1);
    this.POOL_ADDRESS_CACHE_2[cacheKey] = poolAddress;
    return {
      poolAddress,
      token0,
      token1
    };
  }
}

const FACTORY_ADDRESS = '0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10';
const INIT_CODE_HASH = '0x0bbca9af0511ad1a1da383135cf3a8d2ac620e549ef9f6ae3a4c33c2fed0af91';
const computePairAddress = _ref => {
  let {
    factoryAddress,
    tokenA,
    tokenB
  } = _ref;
  const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA];
  return getCreate2Address(factoryAddress, keccak256(['bytes'], [pack(['address', 'address'], [token0.address, token1.address])]), INIT_CODE_HASH);
};
class TraderJoePair extends Pair {
  static getAddress(tokenA, tokenB) {
    return computePairAddress({
      factoryAddress: FACTORY_ADDRESS,
      tokenA,
      tokenB
    });
  }
}

/**
 * Provider that does not get data from an external source and instead returns
 * a hardcoded list of Subgraph pools.
 *
 * Since the pools are hardcoded, the liquidity/price values are dummies and should not
 * be depended on.
 *
 * Useful for instances where other data sources are unavailable. E.g. subgraph not available.
 *
 * @export
 * @class StaticV2SubgraphProvider
 */
class TraderJoeStaticV2SubgraphProvider {
  constructor(chainId) {
    this.chainId = chainId;
  }
  async getPools(tokenIn, tokenOut) {
    const bases = BASES_TO_CHECK_TRADES_AGAINST[this.chainId];
    if (!bases) {
      return [];
    }
    const basePairs = bases.flatMap(base => bases.map(otherBase => [base, otherBase]));
    if (tokenIn && tokenOut) {
      basePairs.push([tokenIn, tokenOut], ...bases.map(base => [tokenIn, base]), ...bases.map(base => [tokenOut, base]));
    }
    const pairs = basePairs.filter(tokens => Boolean(tokens[0] && tokens[1])).filter(_ref => {
      let [tokenA, tokenB] = _ref;
      return tokenA.address !== tokenB.address && !tokenA.equals(tokenB);
    });
    const poolAddressSet = new Set();
    const subgraphPools = pairs.map(_ref2 => {
      let [tokenA, tokenB] = _ref2;
      const poolAddress = TraderJoePair.getAddress(tokenA, tokenB);
      if (poolAddressSet.has(poolAddress)) {
        return undefined;
      }
      poolAddressSet.add(poolAddress);
      const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA];
      return {
        id: poolAddress,
        liquidity: '100',
        token0: {
          id: token0.address
        },
        token1: {
          id: token1.address
        },
        supply: 100,
        reserve: 100,
        reserveUSD: 100
      };
    }).filter(v => !!v);
    return subgraphPools;
  }
}

class TraderJoeV2PoolProvider extends V2PoolProvider {
  POOL_ADDRESS_CACHE_2 = {};
  getPoolAddress(tokenA, tokenB) {
    const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA];
    const cacheKey = `${this.chainId}/${token0.address}/${token1.address}`;
    const cachedAddress = this.POOL_ADDRESS_CACHE_2[cacheKey];
    if (cachedAddress) {
      return {
        poolAddress: cachedAddress,
        token0,
        token1
      };
    }
    const poolAddress = TraderJoePair.getAddress(token0, token1);
    this.POOL_ADDRESS_CACHE_2[cacheKey] = poolAddress;
    return {
      poolAddress,
      token0,
      token1
    };
  }
}

// from routing-api (https://github.com/Uniswap/routing-api/blob/main/lib/handlers/quote/quote.ts#L243-L311)
function transformSwapRouteToGetQuoteResult(_ref) {
  let {
    quote,
    quoteGasAdjusted,
    route,
    routeString,
    estimatedGasUsed,
    estimatedGasUsedQuoteToken,
    estimatedGasUsedUSD,
    gasPriceWei,
    methodParameters,
    blockNumber,
    trade: {
      tradeType,
      inputAmount,
      outputAmount
    }
  } = _ref;
  const routeResponse = [];
  for (const subRoute of route) {
    const {
      amount,
      quote,
      tokenPath
    } = subRoute;
    if (subRoute.protocol === Protocol.V3) {
      const pools = subRoute.route.pools;
      const curRoute = [];
      for (let i = 0; i < pools.length; i++) {
        const nextPool = pools[i];
        const tokenIn = tokenPath[i];
        const tokenOut = tokenPath[i + 1];
        let edgeAmountIn = undefined;
        if (i === 0) {
          edgeAmountIn = isExactInput(tradeType) ? amount.quotient.toString() : quote.quotient.toString();
        }
        let edgeAmountOut = undefined;
        if (i === pools.length - 1) {
          edgeAmountOut = isExactInput(tradeType) ? quote.quotient.toString() : amount.quotient.toString();
        }
        curRoute.push({
          type: 'v3-pool',
          tokenIn: {
            chainId: tokenIn.chainId,
            decimals: tokenIn.decimals,
            address: tokenIn.address,
            symbol: tokenIn.symbol
          },
          tokenOut: {
            chainId: tokenOut.chainId,
            decimals: tokenOut.decimals,
            address: tokenOut.address,
            symbol: tokenOut.symbol
          },
          fee: nextPool.fee.toString(),
          liquidity: nextPool.liquidity.toString(),
          sqrtRatioX96: nextPool.sqrtRatioX96.toString(),
          tickCurrent: nextPool.tickCurrent.toString(),
          amountIn: edgeAmountIn,
          amountOut: edgeAmountOut
        });
      }
      routeResponse.push(curRoute);
    } else if (subRoute.protocol === Protocol.V2) {
      const pools = subRoute.route.pairs;
      const curRoute = [];
      for (let i = 0; i < pools.length; i++) {
        const nextPool = pools[i];
        const tokenIn = tokenPath[i];
        const tokenOut = tokenPath[i + 1];
        let edgeAmountIn = undefined;
        if (i === 0) {
          edgeAmountIn = isExactInput(tradeType) ? amount.quotient.toString() : quote.quotient.toString();
        }
        let edgeAmountOut = undefined;
        if (i === pools.length - 1) {
          edgeAmountOut = isExactInput(tradeType) ? quote.quotient.toString() : amount.quotient.toString();
        }
        const reserve0 = nextPool.reserve0;
        const reserve1 = nextPool.reserve1;
        curRoute.push({
          type: 'v2-pool',
          tokenIn: {
            chainId: tokenIn.chainId,
            decimals: tokenIn.decimals,
            address: tokenIn.address,
            symbol: tokenIn.symbol
          },
          tokenOut: {
            chainId: tokenOut.chainId,
            decimals: tokenOut.decimals,
            address: tokenOut.address,
            symbol: tokenOut.symbol
          },
          reserve0: {
            token: {
              chainId: reserve0.currency.wrapped.chainId,
              decimals: reserve0.currency.wrapped.decimals,
              address: reserve0.currency.wrapped.address,
              symbol: reserve0.currency.wrapped.symbol
            },
            quotient: reserve0.quotient.toString()
          },
          reserve1: {
            token: {
              chainId: reserve1.currency.wrapped.chainId,
              decimals: reserve1.currency.wrapped.decimals,
              address: reserve1.currency.wrapped.address,
              symbol: reserve1.currency.wrapped.symbol
            },
            quotient: reserve1.quotient.toString()
          },
          amountIn: edgeAmountIn,
          amountOut: edgeAmountOut
        });
      }
      routeResponse.push(curRoute);
    }
  }
  const amount = isExactInput(tradeType) ? inputAmount : outputAmount;
  return {
    methodParameters,
    blockNumber: blockNumber.toString(),
    amount: amount.quotient.toString(),
    amountDecimals: amount.toExact(),
    quote: quote.quotient.toString(),
    quoteDecimals: quote.toExact(),
    quoteGasAdjusted: quoteGasAdjusted.quotient.toString(),
    quoteGasAdjustedDecimals: quoteGasAdjusted.toExact(),
    gasUseEstimateQuote: estimatedGasUsedQuoteToken.quotient.toString(),
    gasUseEstimateQuoteDecimals: estimatedGasUsedQuoteToken.toExact(),
    gasUseEstimate: estimatedGasUsed.toString(),
    gasUseEstimateUSD: estimatedGasUsedUSD.toExact(),
    gasPriceWei: gasPriceWei.toString(),
    route: routeResponse,
    routeString
  };
}

// This file is lazy-loaded, so the import of smart-order-router is intentional.
const AUTO_ROUTER_SUPPORTED_CHAINS = Object.values(SupportedChainId).filter(chainId => Number.isInteger(chainId));
function isAutoRouterSupportedChain(chainId) {
  return !!(chainId && AUTO_ROUTER_SUPPORTED_CHAINS.includes(chainId));
}
/** A cache of AlphaRouters, which must be initialized to a specific chain/provider. */
const routersCache = new WeakMap();

// used to coerce the same chain id on two different enums to be retyped to each other
function coerceChainIdTypeToOther(chain) {
  return chain;
}
function getRouter(chainId, provider) {
  const routers = routersCache.get(provider) || {};
  const cached = routers[chainId];
  if (cached) {
    return cached;
  }
  let multicall2Provider;
  let v2PoolProvider;
  let v2QuoteProvider;
  let v2SubgraphProvider;
  let onChainQuoteProvider;
  if (chainId === ChainId.POLYGON) {
    multicall2Provider = new UniswapMulticallProvider(chainId, provider, 375_000);
    v2PoolProvider = new QuickswapV2PoolProvider(chainId, multicall2Provider);
    v2QuoteProvider = new V2QuoteProvider();
    v2SubgraphProvider = new QuickswapStaticV2SubgraphProvider(chainId);

    // V3 computes on-chain, so the quoter must have gas limits appropriate to the provider.
    // Most defaults are fine, but polygon needs a lower gas limit.
    // TODO(zzmp): Upstream to @brydge-network/smart-order-router, possibly making this easier to modify
    // (eg allowing configuration without an instance to avoid duplicating multicall2Provider).
    onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, multicall2Provider, {
      retries: 2,
      minTimeout: 100,
      maxTimeout: 1000
    }, {
      multicallChunk: 10,
      gasLimitPerCall: 5_000_000,
      quoteMinSuccessRate: 0.1
    }, {
      gasLimitOverride: 5_000_000,
      multicallChunk: 5
    }, {
      gasLimitOverride: 6_250_000,
      multicallChunk: 4
    });
  } else if (chainId === ChainId.AVALANCHE) {
    multicall2Provider = new UniswapMulticallProvider(chainId, provider, 375_000);
    v2PoolProvider = new TraderJoeV2PoolProvider(chainId, multicall2Provider);
    v2QuoteProvider = new V2QuoteProvider();
    v2SubgraphProvider = new TraderJoeStaticV2SubgraphProvider(chainId);
  } else {
    // V2 is unsupported for chains other than mainnet.
    // TODO(zzmp): Upstream to @brydge-network/smart-order-router, exporting an enum of supported v2 chains for clarity.
    if (chainId !== ChainId.MAINNET) {
      v2SubgraphProvider = new StaticV2SubgraphProvider(chainId);
    }
  }
  const router = new AlphaRouter({
    provider,
    chainId,
    v2PoolProvider,
    v2SubgraphProvider,
    v2QuoteProvider,
    onChainQuoteProvider,
    multicall2Provider
  });
  routers[chainId] = router;
  routersCache.set(provider, routers);
  return router;
}
async function getQuote(_ref, router, routerConfig) {
  let {
    tradeType,
    tokenIn,
    tokenOut,
    amount: amountRaw
  } = _ref;
  const currencyIn = new Token(tokenIn.chainId, tokenIn.address, tokenIn.decimals, tokenIn.symbol);
  const currencyOut = new Token(tokenOut.chainId, tokenOut.address, tokenOut.decimals, tokenOut.symbol);
  const baseCurrency = isExactInput(tradeType) ? currencyIn : currencyOut;
  const quoteCurrency = isExactInput(tradeType) ? currencyOut : currencyIn;
  const amount = CurrencyAmount.fromRawAmount(baseCurrency, JSBI.BigInt(amountRaw ?? '1')); // a null amountRaw should initialize the route
  const route = await router.route(amount, quoteCurrency, tradeType, /*swapConfig=*/undefined, routerConfig);
  if (amountRaw === null || !route) {
    return NO_ROUTE;
  }
  return transformSwapRouteToGetQuoteResult({
    ...route,
    routeString: routeAmountsToString(route.route)
  });
}
async function getClientSideQuote(_ref2, routerConfig) {
  let {
    tokenInAddress,
    tokenInChainId,
    tokenInDecimals,
    tokenInSymbol,
    tokenOutAddress,
    tokenOutChainId,
    tokenOutDecimals,
    tokenOutSymbol,
    amount,
    tradeType,
    provider
  } = _ref2;
  if (!isAutoRouterSupportedChain(tokenInChainId)) {
    throw new Error(`Router does not support this token's chain (chainId: ${tokenInChainId}).`);
  }
  const router = getRouter(coerceChainIdTypeToOther(tokenInChainId), provider);
  return getQuote({
    tradeType,
    tokenIn: {
      address: tokenInAddress,
      chainId: tokenInChainId,
      decimals: tokenInDecimals,
      symbol: tokenInSymbol
    },
    tokenOut: {
      address: tokenOutAddress,
      chainId: tokenOutChainId,
      decimals: tokenOutDecimals,
      symbol: tokenOutSymbol
    },
    amount
  }, router, routerConfig);
}

export { getClientSideQuote };
//# sourceMappingURL=clientSideSmartOrderRouter-a51a45e3.js.map
