@fanx-protocol/smart-order-router 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +255 -0
- package/LICENSE +674 -0
- package/README.md +273 -0
- package/build/main/index.d.ts +3 -0
- package/build/main/index.js +20 -0
- package/build/main/providers/cache-node.d.ts +10 -0
- package/build/main/providers/cache-node.js +33 -0
- package/build/main/providers/cache.d.ts +14 -0
- package/build/main/providers/cache.js +3 -0
- package/build/main/providers/caching/route/index.d.ts +2 -0
- package/build/main/providers/caching/route/index.js +19 -0
- package/build/main/providers/caching/route/model/cache-mode.d.ts +16 -0
- package/build/main/providers/caching/route/model/cache-mode.js +21 -0
- package/build/main/providers/caching/route/model/cached-route.d.ts +29 -0
- package/build/main/providers/caching/route/model/cached-route.js +89 -0
- package/build/main/providers/caching/route/model/cached-routes.d.ts +67 -0
- package/build/main/providers/caching/route/model/cached-routes.js +81 -0
- package/build/main/providers/caching/route/model/index.d.ts +3 -0
- package/build/main/providers/caching/route/model/index.js +20 -0
- package/build/main/providers/caching/route/route-caching-provider.d.ts +88 -0
- package/build/main/providers/caching/route/route-caching-provider.js +72 -0
- package/build/main/providers/caching-gas-provider.d.ts +23 -0
- package/build/main/providers/caching-gas-provider.js +41 -0
- package/build/main/providers/caching-subgraph-provider.d.ts +33 -0
- package/build/main/providers/caching-subgraph-provider.js +37 -0
- package/build/main/providers/caching-token-list-provider.d.ts +52 -0
- package/build/main/providers/caching-token-list-provider.js +147 -0
- package/build/main/providers/caching-token-provider.d.ts +24 -0
- package/build/main/providers/caching-token-provider.js +108 -0
- package/build/main/providers/eip-1559-gas-price-provider.d.ts +31 -0
- package/build/main/providers/eip-1559-gas-price-provider.js +71 -0
- package/build/main/providers/eth-estimate-gas-provider.d.ts +19 -0
- package/build/main/providers/eth-estimate-gas-provider.js +94 -0
- package/build/main/providers/eth-gas-station-info-gas-price-provider.d.ts +19 -0
- package/build/main/providers/eth-gas-station-info-gas-price-provider.js +36 -0
- package/build/main/providers/gas-price-provider.d.ts +10 -0
- package/build/main/providers/gas-price-provider.js +10 -0
- package/build/main/providers/index.d.ts +38 -0
- package/build/main/providers/index.js +55 -0
- package/build/main/providers/legacy-gas-price-provider.d.ts +7 -0
- package/build/main/providers/legacy-gas-price-provider.js +18 -0
- package/build/main/providers/multicall-provider.d.ts +83 -0
- package/build/main/providers/multicall-provider.js +15 -0
- package/build/main/providers/multicall-uniswap-provider.d.ts +37 -0
- package/build/main/providers/multicall-uniswap-provider.js +164 -0
- package/build/main/providers/on-chain-gas-price-provider.d.ts +19 -0
- package/build/main/providers/on-chain-gas-price-provider.js +36 -0
- package/build/main/providers/on-chain-quote-provider.d.ts +258 -0
- package/build/main/providers/on-chain-quote-provider.js +693 -0
- package/build/main/providers/pool-provider.d.ts +44 -0
- package/build/main/providers/pool-provider.js +73 -0
- package/build/main/providers/portion-provider.d.ts +86 -0
- package/build/main/providers/portion-provider.js +118 -0
- package/build/main/providers/provider.d.ts +38 -0
- package/build/main/providers/provider.js +3 -0
- package/build/main/providers/simulation-provider.d.ts +43 -0
- package/build/main/providers/simulation-provider.js +136 -0
- package/build/main/providers/static-gas-price-provider.d.ts +7 -0
- package/build/main/providers/static-gas-price-provider.js +13 -0
- package/build/main/providers/subgraph-provider-with-fallback.d.ts +11 -0
- package/build/main/providers/subgraph-provider-with-fallback.js +25 -0
- package/build/main/providers/subgraph-provider.d.ts +51 -0
- package/build/main/providers/subgraph-provider.js +120 -0
- package/build/main/providers/swap-router-provider.d.ts +30 -0
- package/build/main/providers/swap-router-provider.js +42 -0
- package/build/main/providers/token-fee-fetcher.d.ts +31 -0
- package/build/main/providers/token-fee-fetcher.js +108 -0
- package/build/main/providers/token-properties-provider.d.ts +31 -0
- package/build/main/providers/token-properties-provider.js +118 -0
- package/build/main/providers/token-provider.d.ts +38 -0
- package/build/main/providers/token-provider.js +175 -0
- package/build/main/providers/token-validator-provider.d.ts +42 -0
- package/build/main/providers/token-validator-provider.js +99 -0
- package/build/main/providers/uri-subgraph-provider.d.ts +20 -0
- package/build/main/providers/uri-subgraph-provider.js +65 -0
- package/build/main/providers/v2/caching-pool-provider.d.ts +33 -0
- package/build/main/providers/v2/caching-pool-provider.js +89 -0
- package/build/main/providers/v2/caching-subgraph-provider.d.ts +19 -0
- package/build/main/providers/v2/caching-subgraph-provider.js +24 -0
- package/build/main/providers/v2/pool-provider.d.ts +63 -0
- package/build/main/providers/v2/pool-provider.js +138 -0
- package/build/main/providers/v2/quote-provider.d.ts +34 -0
- package/build/main/providers/v2/quote-provider.js +90 -0
- package/build/main/providers/v2/static-subgraph-provider.d.ts +19 -0
- package/build/main/providers/v2/static-subgraph-provider.js +75 -0
- package/build/main/providers/v2/subgraph-provider-with-fallback.d.ts +16 -0
- package/build/main/providers/v2/subgraph-provider-with-fallback.js +23 -0
- package/build/main/providers/v2/subgraph-provider.d.ts +36 -0
- package/build/main/providers/v2/subgraph-provider.js +174 -0
- package/build/main/providers/v2/uri-subgraph-provider.d.ts +4 -0
- package/build/main/providers/v2/uri-subgraph-provider.js +8 -0
- package/build/main/providers/v3/caching-pool-provider.d.ts +32 -0
- package/build/main/providers/v3/caching-pool-provider.js +84 -0
- package/build/main/providers/v3/caching-subgraph-provider.d.ts +19 -0
- package/build/main/providers/v3/caching-subgraph-provider.js +24 -0
- package/build/main/providers/v3/gas-data-provider.d.ts +39 -0
- package/build/main/providers/v3/gas-data-provider.js +26 -0
- package/build/main/providers/v3/pool-provider.d.ts +77 -0
- package/build/main/providers/v3/pool-provider.js +108 -0
- package/build/main/providers/v3/static-subgraph-provider.d.ts +21 -0
- package/build/main/providers/v3/static-subgraph-provider.js +89 -0
- package/build/main/providers/v3/subgraph-provider-with-fallback.d.ts +12 -0
- package/build/main/providers/v3/subgraph-provider-with-fallback.js +19 -0
- package/build/main/providers/v3/subgraph-provider.d.ts +46 -0
- package/build/main/providers/v3/subgraph-provider.js +54 -0
- package/build/main/providers/v3/uri-subgraph-provider.d.ts +4 -0
- package/build/main/providers/v3/uri-subgraph-provider.js +8 -0
- package/build/main/routers/alpha-router/alpha-router.d.ts +347 -0
- package/build/main/routers/alpha-router/alpha-router.js +1219 -0
- package/build/main/routers/alpha-router/config.d.ts +4 -0
- package/build/main/routers/alpha-router/config.js +40 -0
- package/build/main/routers/alpha-router/entities/index.d.ts +1 -0
- package/build/main/routers/alpha-router/entities/index.js +18 -0
- package/build/main/routers/alpha-router/entities/route-with-valid-quote.d.ts +167 -0
- package/build/main/routers/alpha-router/entities/route-with-valid-quote.js +166 -0
- package/build/main/routers/alpha-router/functions/best-swap-route.d.ts +22 -0
- package/build/main/routers/alpha-router/functions/best-swap-route.js +534 -0
- package/build/main/routers/alpha-router/functions/calculate-ratio-amount-in.d.ts +3 -0
- package/build/main/routers/alpha-router/functions/calculate-ratio-amount-in.js +18 -0
- package/build/main/routers/alpha-router/functions/compute-all-routes.d.ts +9 -0
- package/build/main/routers/alpha-router/functions/compute-all-routes.js +104 -0
- package/build/main/routers/alpha-router/functions/get-candidate-pools.d.ts +100 -0
- package/build/main/routers/alpha-router/functions/get-candidate-pools.js +1008 -0
- package/build/main/routers/alpha-router/gas-models/gas-costs.d.ts +12 -0
- package/build/main/routers/alpha-router/gas-models/gas-costs.js +90 -0
- package/build/main/routers/alpha-router/gas-models/gas-model.d.ts +106 -0
- package/build/main/routers/alpha-router/gas-models/gas-model.js +68 -0
- package/build/main/routers/alpha-router/gas-models/index.d.ts +2 -0
- package/build/main/routers/alpha-router/gas-models/index.js +19 -0
- package/build/main/routers/alpha-router/gas-models/mixedRoute/mixed-route-heuristic-gas-model.d.ts +24 -0
- package/build/main/routers/alpha-router/gas-models/mixedRoute/mixed-route-heuristic-gas-model.js +161 -0
- package/build/main/routers/alpha-router/gas-models/tick-based-heuristic-gas-model.d.ts +15 -0
- package/build/main/routers/alpha-router/gas-models/tick-based-heuristic-gas-model.js +185 -0
- package/build/main/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.d.ts +31 -0
- package/build/main/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.js +169 -0
- package/build/main/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.d.ts +26 -0
- package/build/main/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.js +41 -0
- package/build/main/routers/alpha-router/index.d.ts +4 -0
- package/build/main/routers/alpha-router/index.js +21 -0
- package/build/main/routers/alpha-router/quoters/base-quoter.d.ts +76 -0
- package/build/main/routers/alpha-router/quoters/base-quoter.js +76 -0
- package/build/main/routers/alpha-router/quoters/index.d.ts +5 -0
- package/build/main/routers/alpha-router/quoters/index.js +22 -0
- package/build/main/routers/alpha-router/quoters/mixed-quoter.d.ts +28 -0
- package/build/main/routers/alpha-router/quoters/mixed-quoter.js +154 -0
- package/build/main/routers/alpha-router/quoters/model/index.d.ts +1 -0
- package/build/main/routers/alpha-router/quoters/model/index.js +18 -0
- package/build/main/routers/alpha-router/quoters/model/results/get-quotes-result.d.ts +6 -0
- package/build/main/routers/alpha-router/quoters/model/results/get-quotes-result.js +3 -0
- package/build/main/routers/alpha-router/quoters/model/results/get-routes-result.d.ts +6 -0
- package/build/main/routers/alpha-router/quoters/model/results/get-routes-result.js +3 -0
- package/build/main/routers/alpha-router/quoters/model/results/index.d.ts +2 -0
- package/build/main/routers/alpha-router/quoters/model/results/index.js +19 -0
- package/build/main/routers/alpha-router/quoters/v2-quoter.d.ts +24 -0
- package/build/main/routers/alpha-router/quoters/v2-quoter.js +140 -0
- package/build/main/routers/alpha-router/quoters/v3-quoter.d.ts +19 -0
- package/build/main/routers/alpha-router/quoters/v3-quoter.js +117 -0
- package/build/main/routers/index.d.ts +3 -0
- package/build/main/routers/index.js +20 -0
- package/build/main/routers/router.d.ts +186 -0
- package/build/main/routers/router.js +55 -0
- package/build/main/tsconfig.tsbuildinfo +1 -0
- package/build/main/types/other/commons.d.ts +16 -0
- package/build/main/types/other/commons.js +6 -0
- package/build/main/types/other/factories/Erc20__factory.d.ts +45 -0
- package/build/main/types/other/factories/Erc20__factory.js +240 -0
- package/build/main/types/other/factories/GasDataArbitrum__factory.d.ts +18 -0
- package/build/main/types/other/factories/GasDataArbitrum__factory.js +58 -0
- package/build/main/types/other/factories/IMixedRouteQuoterV1__factory.d.ts +41 -0
- package/build/main/types/other/factories/IMixedRouteQuoterV1__factory.js +156 -0
- package/build/main/types/other/factories/ITokenValidator__factory.d.ts +22 -0
- package/build/main/types/other/factories/ITokenValidator__factory.js +78 -0
- package/build/main/types/other/factories/MixedRouteQuoterV2__factory.d.ts +86 -0
- package/build/main/types/other/factories/MixedRouteQuoterV2__factory.js +477 -0
- package/build/main/types/other/factories/Permit2__factory.d.ts +87 -0
- package/build/main/types/other/factories/Permit2__factory.js +936 -0
- package/build/main/types/other/factories/SwapRouter02__factory.d.ts +67 -0
- package/build/main/types/other/factories/SwapRouter02__factory.js +1098 -0
- package/build/main/types/other/factories/TokenFeeDetector__factory.d.ts +47 -0
- package/build/main/types/other/factories/TokenFeeDetector__factory.js +243 -0
- package/build/main/types/v2/commons.d.ts +16 -0
- package/build/main/types/v2/commons.js +6 -0
- package/build/main/types/v2/factories/IUniswapV2Pair__factory.d.ts +35 -0
- package/build/main/types/v2/factories/IUniswapV2Pair__factory.js +671 -0
- package/build/main/types/v3/commons.d.ts +16 -0
- package/build/main/types/v3/commons.js +6 -0
- package/build/main/types/v3/factories/IERC20Metadata__factory.d.ts +35 -0
- package/build/main/types/v3/factories/IERC20Metadata__factory.js +242 -0
- package/build/main/types/v3/factories/IQuoterV2__factory.d.ts +41 -0
- package/build/main/types/v3/factories/IQuoterV2__factory.js +220 -0
- package/build/main/types/v3/factories/IUniswapV3PoolState__factory.d.ts +22 -0
- package/build/main/types/v3/factories/IUniswapV3PoolState__factory.js +266 -0
- package/build/main/types/v3/factories/UniswapInterfaceMulticall__factory.d.ts +61 -0
- package/build/main/types/v3/factories/UniswapInterfaceMulticall__factory.js +127 -0
- package/build/main/util/addresses.d.ts +24 -0
- package/build/main/util/addresses.js +76 -0
- package/build/main/util/amounts.d.ts +9 -0
- package/build/main/util/amounts.js +73 -0
- package/build/main/util/chains.d.ts +31 -0
- package/build/main/util/chains.js +97 -0
- package/build/main/util/gas-factory-helpers.d.ts +33 -0
- package/build/main/util/gas-factory-helpers.js +463 -0
- package/build/main/util/index.d.ts +7 -0
- package/build/main/util/index.js +24 -0
- package/build/main/util/l2FeeChains.d.ts +2 -0
- package/build/main/util/l2FeeChains.js +13 -0
- package/build/main/util/log.d.ts +3 -0
- package/build/main/util/log.js +97 -0
- package/build/main/util/methodParameters.d.ts +5 -0
- package/build/main/util/methodParameters.js +183 -0
- package/build/main/util/metric.d.ts +48 -0
- package/build/main/util/metric.js +59 -0
- package/build/main/util/onchainQuoteProviderConfigs.d.ts +42 -0
- package/build/main/util/onchainQuoteProviderConfigs.js +74 -0
- package/build/main/util/protocols.d.ts +2 -0
- package/build/main/util/protocols.js +20 -0
- package/build/main/util/routes.d.ts +11 -0
- package/build/main/util/routes.js +149 -0
- package/build/main/util/unsupported-tokens.d.ts +37 -0
- package/build/main/util/unsupported-tokens.js +1119 -0
- package/build/module/index.d.ts +3 -0
- package/build/module/index.js +4 -0
- package/build/module/providers/cache-node.d.ts +10 -0
- package/build/module/providers/cache-node.js +29 -0
- package/build/module/providers/cache.d.ts +14 -0
- package/build/module/providers/cache.js +2 -0
- package/build/module/providers/caching/route/index.d.ts +2 -0
- package/build/module/providers/caching/route/index.js +3 -0
- package/build/module/providers/caching/route/model/cache-mode.d.ts +16 -0
- package/build/module/providers/caching/route/model/cache-mode.js +18 -0
- package/build/module/providers/caching/route/model/cached-route.d.ts +29 -0
- package/build/module/providers/caching/route/model/cached-route.js +85 -0
- package/build/module/providers/caching/route/model/cached-routes.d.ts +67 -0
- package/build/module/providers/caching/route/model/cached-routes.js +74 -0
- package/build/module/providers/caching/route/model/index.d.ts +3 -0
- package/build/module/providers/caching/route/model/index.js +4 -0
- package/build/module/providers/caching/route/route-caching-provider.d.ts +88 -0
- package/build/module/providers/caching/route/route-caching-provider.js +68 -0
- package/build/module/providers/caching-gas-provider.d.ts +23 -0
- package/build/module/providers/caching-gas-provider.js +37 -0
- package/build/module/providers/caching-subgraph-provider.d.ts +33 -0
- package/build/module/providers/caching-subgraph-provider.js +33 -0
- package/build/module/providers/caching-token-list-provider.d.ts +52 -0
- package/build/module/providers/caching-token-list-provider.js +140 -0
- package/build/module/providers/caching-token-provider.d.ts +24 -0
- package/build/module/providers/caching-token-provider.js +101 -0
- package/build/module/providers/eip-1559-gas-price-provider.d.ts +31 -0
- package/build/module/providers/eip-1559-gas-price-provider.js +64 -0
- package/build/module/providers/eth-estimate-gas-provider.d.ts +19 -0
- package/build/module/providers/eth-estimate-gas-provider.js +102 -0
- package/build/module/providers/eth-gas-station-info-gas-price-provider.d.ts +19 -0
- package/build/module/providers/eth-gas-station-info-gas-price-provider.js +29 -0
- package/build/module/providers/gas-price-provider.d.ts +10 -0
- package/build/module/providers/gas-price-provider.js +6 -0
- package/build/module/providers/index.d.ts +38 -0
- package/build/module/providers/index.js +39 -0
- package/build/module/providers/legacy-gas-price-provider.d.ts +7 -0
- package/build/module/providers/legacy-gas-price-provider.js +14 -0
- package/build/module/providers/multicall-provider.d.ts +83 -0
- package/build/module/providers/multicall-provider.js +11 -0
- package/build/module/providers/multicall-uniswap-provider.d.ts +37 -0
- package/build/module/providers/multicall-uniswap-provider.js +157 -0
- package/build/module/providers/on-chain-gas-price-provider.d.ts +19 -0
- package/build/module/providers/on-chain-gas-price-provider.js +32 -0
- package/build/module/providers/on-chain-quote-provider.d.ts +258 -0
- package/build/module/providers/on-chain-quote-provider.js +687 -0
- package/build/module/providers/pool-provider.d.ts +44 -0
- package/build/module/providers/pool-provider.js +66 -0
- package/build/module/providers/portion-provider.d.ts +86 -0
- package/build/module/providers/portion-provider.js +114 -0
- package/build/module/providers/provider.d.ts +38 -0
- package/build/module/providers/provider.js +2 -0
- package/build/module/providers/simulation-provider.d.ts +43 -0
- package/build/module/providers/simulation-provider.js +138 -0
- package/build/module/providers/static-gas-price-provider.d.ts +7 -0
- package/build/module/providers/static-gas-price-provider.js +9 -0
- package/build/module/providers/subgraph-provider-with-fallback.d.ts +11 -0
- package/build/module/providers/subgraph-provider-with-fallback.js +21 -0
- package/build/module/providers/subgraph-provider.d.ts +51 -0
- package/build/module/providers/subgraph-provider.js +113 -0
- package/build/module/providers/swap-router-provider.d.ts +30 -0
- package/build/module/providers/swap-router-provider.js +38 -0
- package/build/module/providers/token-fee-fetcher.d.ts +31 -0
- package/build/module/providers/token-fee-fetcher.js +104 -0
- package/build/module/providers/token-properties-provider.d.ts +31 -0
- package/build/module/providers/token-properties-provider.js +114 -0
- package/build/module/providers/token-provider.d.ts +38 -0
- package/build/module/providers/token-provider.js +164 -0
- package/build/module/providers/token-validator-provider.d.ts +42 -0
- package/build/module/providers/token-validator-provider.js +92 -0
- package/build/module/providers/uri-subgraph-provider.d.ts +20 -0
- package/build/module/providers/uri-subgraph-provider.js +58 -0
- package/build/module/providers/v2/caching-pool-provider.d.ts +33 -0
- package/build/module/providers/v2/caching-pool-provider.js +85 -0
- package/build/module/providers/v2/caching-subgraph-provider.d.ts +19 -0
- package/build/module/providers/v2/caching-subgraph-provider.js +20 -0
- package/build/module/providers/v2/pool-provider.d.ts +63 -0
- package/build/module/providers/v2/pool-provider.js +131 -0
- package/build/module/providers/v2/quote-provider.d.ts +34 -0
- package/build/module/providers/v2/quote-provider.js +86 -0
- package/build/module/providers/v2/static-subgraph-provider.d.ts +19 -0
- package/build/module/providers/v2/static-subgraph-provider.js +68 -0
- package/build/module/providers/v2/subgraph-provider-with-fallback.d.ts +16 -0
- package/build/module/providers/v2/subgraph-provider-with-fallback.js +19 -0
- package/build/module/providers/v2/subgraph-provider.d.ts +36 -0
- package/build/module/providers/v2/subgraph-provider.js +167 -0
- package/build/module/providers/v2/uri-subgraph-provider.d.ts +4 -0
- package/build/module/providers/v2/uri-subgraph-provider.js +4 -0
- package/build/module/providers/v3/caching-pool-provider.d.ts +32 -0
- package/build/module/providers/v3/caching-pool-provider.js +77 -0
- package/build/module/providers/v3/caching-subgraph-provider.d.ts +19 -0
- package/build/module/providers/v3/caching-subgraph-provider.js +20 -0
- package/build/module/providers/v3/gas-data-provider.d.ts +39 -0
- package/build/module/providers/v3/gas-data-provider.js +22 -0
- package/build/module/providers/v3/pool-provider.d.ts +77 -0
- package/build/module/providers/v3/pool-provider.js +101 -0
- package/build/module/providers/v3/static-subgraph-provider.d.ts +21 -0
- package/build/module/providers/v3/static-subgraph-provider.js +82 -0
- package/build/module/providers/v3/subgraph-provider-with-fallback.d.ts +12 -0
- package/build/module/providers/v3/subgraph-provider-with-fallback.js +15 -0
- package/build/module/providers/v3/subgraph-provider.d.ts +46 -0
- package/build/module/providers/v3/subgraph-provider.js +50 -0
- package/build/module/providers/v3/uri-subgraph-provider.d.ts +4 -0
- package/build/module/providers/v3/uri-subgraph-provider.js +4 -0
- package/build/module/routers/alpha-router/alpha-router.d.ts +347 -0
- package/build/module/routers/alpha-router/alpha-router.js +1229 -0
- package/build/module/routers/alpha-router/config.d.ts +4 -0
- package/build/module/routers/alpha-router/config.js +36 -0
- package/build/module/routers/alpha-router/entities/index.d.ts +1 -0
- package/build/module/routers/alpha-router/entities/index.js +2 -0
- package/build/module/routers/alpha-router/entities/route-with-valid-quote.d.ts +167 -0
- package/build/module/routers/alpha-router/entities/route-with-valid-quote.js +157 -0
- package/build/module/routers/alpha-router/functions/best-swap-route.d.ts +22 -0
- package/build/module/routers/alpha-router/functions/best-swap-route.js +526 -0
- package/build/module/routers/alpha-router/functions/calculate-ratio-amount-in.d.ts +3 -0
- package/build/module/routers/alpha-router/functions/calculate-ratio-amount-in.js +14 -0
- package/build/module/routers/alpha-router/functions/compute-all-routes.d.ts +9 -0
- package/build/module/routers/alpha-router/functions/compute-all-routes.js +97 -0
- package/build/module/routers/alpha-router/functions/get-candidate-pools.d.ts +100 -0
- package/build/module/routers/alpha-router/functions/get-candidate-pools.js +998 -0
- package/build/module/routers/alpha-router/gas-models/gas-costs.d.ts +12 -0
- package/build/module/routers/alpha-router/gas-models/gas-costs.js +79 -0
- package/build/module/routers/alpha-router/gas-models/gas-model.d.ts +106 -0
- package/build/module/routers/alpha-router/gas-models/gas-model.js +102 -0
- package/build/module/routers/alpha-router/gas-models/index.d.ts +2 -0
- package/build/module/routers/alpha-router/gas-models/index.js +3 -0
- package/build/module/routers/alpha-router/gas-models/mixedRoute/mixed-route-heuristic-gas-model.d.ts +24 -0
- package/build/module/routers/alpha-router/gas-models/mixedRoute/mixed-route-heuristic-gas-model.js +154 -0
- package/build/module/routers/alpha-router/gas-models/tick-based-heuristic-gas-model.d.ts +15 -0
- package/build/module/routers/alpha-router/gas-models/tick-based-heuristic-gas-model.js +181 -0
- package/build/module/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.d.ts +31 -0
- package/build/module/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.js +162 -0
- package/build/module/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.d.ts +26 -0
- package/build/module/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.js +37 -0
- package/build/module/routers/alpha-router/index.d.ts +4 -0
- package/build/module/routers/alpha-router/index.js +5 -0
- package/build/module/routers/alpha-router/quoters/base-quoter.d.ts +76 -0
- package/build/module/routers/alpha-router/quoters/base-quoter.js +69 -0
- package/build/module/routers/alpha-router/quoters/index.d.ts +5 -0
- package/build/module/routers/alpha-router/quoters/index.js +6 -0
- package/build/module/routers/alpha-router/quoters/mixed-quoter.d.ts +28 -0
- package/build/module/routers/alpha-router/quoters/mixed-quoter.js +152 -0
- package/build/module/routers/alpha-router/quoters/model/index.d.ts +1 -0
- package/build/module/routers/alpha-router/quoters/model/index.js +2 -0
- package/build/module/routers/alpha-router/quoters/model/results/get-quotes-result.d.ts +6 -0
- package/build/module/routers/alpha-router/quoters/model/results/get-quotes-result.js +2 -0
- package/build/module/routers/alpha-router/quoters/model/results/get-routes-result.d.ts +6 -0
- package/build/module/routers/alpha-router/quoters/model/results/get-routes-result.js +2 -0
- package/build/module/routers/alpha-router/quoters/model/results/index.d.ts +2 -0
- package/build/module/routers/alpha-router/quoters/model/results/index.js +3 -0
- package/build/module/routers/alpha-router/quoters/v2-quoter.d.ts +24 -0
- package/build/module/routers/alpha-router/quoters/v2-quoter.js +137 -0
- package/build/module/routers/alpha-router/quoters/v3-quoter.d.ts +19 -0
- package/build/module/routers/alpha-router/quoters/v3-quoter.js +110 -0
- package/build/module/routers/index.d.ts +3 -0
- package/build/module/routers/index.js +4 -0
- package/build/module/routers/router.d.ts +186 -0
- package/build/module/routers/router.js +47 -0
- package/build/module/tsconfig.module.tsbuildinfo +1 -0
- package/build/module/types/other/commons.d.ts +16 -0
- package/build/module/types/other/commons.js +5 -0
- package/build/module/types/other/factories/Erc20__factory.d.ts +45 -0
- package/build/module/types/other/factories/Erc20__factory.js +236 -0
- package/build/module/types/other/factories/GasDataArbitrum__factory.d.ts +18 -0
- package/build/module/types/other/factories/GasDataArbitrum__factory.js +54 -0
- package/build/module/types/other/factories/IMixedRouteQuoterV1__factory.d.ts +41 -0
- package/build/module/types/other/factories/IMixedRouteQuoterV1__factory.js +152 -0
- package/build/module/types/other/factories/ITokenValidator__factory.d.ts +22 -0
- package/build/module/types/other/factories/ITokenValidator__factory.js +74 -0
- package/build/module/types/other/factories/MixedRouteQuoterV2__factory.d.ts +86 -0
- package/build/module/types/other/factories/MixedRouteQuoterV2__factory.js +473 -0
- package/build/module/types/other/factories/Permit2__factory.d.ts +87 -0
- package/build/module/types/other/factories/Permit2__factory.js +932 -0
- package/build/module/types/other/factories/SwapRouter02__factory.d.ts +67 -0
- package/build/module/types/other/factories/SwapRouter02__factory.js +1094 -0
- package/build/module/types/other/factories/TokenFeeDetector__factory.d.ts +47 -0
- package/build/module/types/other/factories/TokenFeeDetector__factory.js +239 -0
- package/build/module/types/v2/commons.d.ts +16 -0
- package/build/module/types/v2/commons.js +5 -0
- package/build/module/types/v2/factories/IUniswapV2Pair__factory.d.ts +35 -0
- package/build/module/types/v2/factories/IUniswapV2Pair__factory.js +667 -0
- package/build/module/types/v3/commons.d.ts +16 -0
- package/build/module/types/v3/commons.js +5 -0
- package/build/module/types/v3/factories/IERC20Metadata__factory.d.ts +35 -0
- package/build/module/types/v3/factories/IERC20Metadata__factory.js +238 -0
- package/build/module/types/v3/factories/IQuoterV2__factory.d.ts +41 -0
- package/build/module/types/v3/factories/IQuoterV2__factory.js +216 -0
- package/build/module/types/v3/factories/IUniswapV3PoolState__factory.d.ts +22 -0
- package/build/module/types/v3/factories/IUniswapV3PoolState__factory.js +262 -0
- package/build/module/types/v3/factories/UniswapInterfaceMulticall__factory.d.ts +61 -0
- package/build/module/types/v3/factories/UniswapInterfaceMulticall__factory.js +123 -0
- package/build/module/util/addresses.d.ts +24 -0
- package/build/module/util/addresses.js +69 -0
- package/build/module/util/amounts.d.ts +9 -0
- package/build/module/util/amounts.js +62 -0
- package/build/module/util/chains.d.ts +31 -0
- package/build/module/util/chains.js +89 -0
- package/build/module/util/gas-factory-helpers.d.ts +33 -0
- package/build/module/util/gas-factory-helpers.js +446 -0
- package/build/module/util/index.d.ts +7 -0
- package/build/module/util/index.js +8 -0
- package/build/module/util/l2FeeChains.d.ts +2 -0
- package/build/module/util/l2FeeChains.js +10 -0
- package/build/module/util/log.d.ts +3 -0
- package/build/module/util/log.js +93 -0
- package/build/module/util/methodParameters.d.ts +5 -0
- package/build/module/util/methodParameters.js +181 -0
- package/build/module/util/metric.d.ts +48 -0
- package/build/module/util/metric.js +53 -0
- package/build/module/util/onchainQuoteProviderConfigs.d.ts +42 -0
- package/build/module/util/onchainQuoteProviderConfigs.js +76 -0
- package/build/module/util/protocols.d.ts +2 -0
- package/build/module/util/protocols.js +16 -0
- package/build/module/util/routes.d.ts +11 -0
- package/build/module/util/routes.js +137 -0
- package/build/module/util/unsupported-tokens.d.ts +37 -0
- package/build/module/util/unsupported-tokens.js +1116 -0
- package/package.json +133 -0
|
@@ -0,0 +1,1219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AlphaRouter = exports.LowerCaseStringArray = exports.MapWithLowerCaseKey = void 0;
|
|
7
|
+
const bignumber_1 = require("@ethersproject/bignumber");
|
|
8
|
+
const providers_1 = require("@ethersproject/providers");
|
|
9
|
+
const router_sdk_1 = require("@fanx-protocol/router-sdk");
|
|
10
|
+
const sdk_core_1 = require("@fanx-protocol/sdk-core");
|
|
11
|
+
const universal_router_sdk_1 = require("@fanx-protocol/universal-router-sdk");
|
|
12
|
+
const v3_sdk_1 = require("@fanx-protocol/v3-sdk");
|
|
13
|
+
const default_token_list_1 = __importDefault(require("@uniswap/default-token-list"));
|
|
14
|
+
const async_retry_1 = __importDefault(require("async-retry"));
|
|
15
|
+
const jsbi_1 = __importDefault(require("jsbi"));
|
|
16
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
17
|
+
const node_cache_1 = __importDefault(require("node-cache"));
|
|
18
|
+
const providers_2 = require("../../providers");
|
|
19
|
+
const caching_token_list_provider_1 = require("../../providers/caching-token-list-provider");
|
|
20
|
+
const portion_provider_1 = require("../../providers/portion-provider");
|
|
21
|
+
const token_fee_fetcher_1 = require("../../providers/token-fee-fetcher");
|
|
22
|
+
const token_provider_1 = require("../../providers/token-provider");
|
|
23
|
+
const token_validator_provider_1 = require("../../providers/token-validator-provider");
|
|
24
|
+
const pool_provider_1 = require("../../providers/v2/pool-provider");
|
|
25
|
+
const gas_data_provider_1 = require("../../providers/v3/gas-data-provider");
|
|
26
|
+
const pool_provider_2 = require("../../providers/v3/pool-provider");
|
|
27
|
+
// import { CachingV4PoolProvider } from '../../providers/v4/caching-pool-provider';
|
|
28
|
+
// import {
|
|
29
|
+
// IV4PoolProvider,
|
|
30
|
+
// V4PoolProvider,
|
|
31
|
+
// } from '../../providers/v4/pool-provider';
|
|
32
|
+
const Erc20__factory_1 = require("../../types/other/factories/Erc20__factory");
|
|
33
|
+
const util_1 = require("../../util");
|
|
34
|
+
const amounts_1 = require("../../util/amounts");
|
|
35
|
+
const chains_1 = require("../../util/chains");
|
|
36
|
+
const gas_factory_helpers_1 = require("../../util/gas-factory-helpers");
|
|
37
|
+
const log_1 = require("../../util/log");
|
|
38
|
+
const methodParameters_1 = require("../../util/methodParameters");
|
|
39
|
+
const metric_1 = require("../../util/metric");
|
|
40
|
+
const onchainQuoteProviderConfigs_1 = require("../../util/onchainQuoteProviderConfigs");
|
|
41
|
+
const unsupported_tokens_1 = require("../../util/unsupported-tokens");
|
|
42
|
+
const router_1 = require("../router");
|
|
43
|
+
const config_1 = require("./config");
|
|
44
|
+
const best_swap_route_1 = require("./functions/best-swap-route");
|
|
45
|
+
const calculate_ratio_amount_in_1 = require("./functions/calculate-ratio-amount-in");
|
|
46
|
+
const get_candidate_pools_1 = require("./functions/get-candidate-pools");
|
|
47
|
+
const gas_costs_1 = require("./gas-models/gas-costs");
|
|
48
|
+
const mixed_route_heuristic_gas_model_1 = require("./gas-models/mixedRoute/mixed-route-heuristic-gas-model");
|
|
49
|
+
const v2_heuristic_gas_model_1 = require("./gas-models/v2/v2-heuristic-gas-model");
|
|
50
|
+
const v3_heuristic_gas_model_1 = require("./gas-models/v3/v3-heuristic-gas-model");
|
|
51
|
+
// import { V4HeuristicGasModelFactory } from './gas-models/v4/v4-heuristic-gas-model';
|
|
52
|
+
const quoters_1 = require("./quoters");
|
|
53
|
+
class MapWithLowerCaseKey extends Map {
|
|
54
|
+
set(key, value) {
|
|
55
|
+
return super.set(key.toLowerCase(), value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.MapWithLowerCaseKey = MapWithLowerCaseKey;
|
|
59
|
+
class LowerCaseStringArray extends Array {
|
|
60
|
+
constructor(...items) {
|
|
61
|
+
// Convert all items to lowercase before calling the parent constructor
|
|
62
|
+
super(...items.map((item) => item.toLowerCase()));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.LowerCaseStringArray = LowerCaseStringArray;
|
|
66
|
+
class AlphaRouter {
|
|
67
|
+
constructor({ chainId, provider, multicall2Provider,
|
|
68
|
+
// v4SubgraphProvider,
|
|
69
|
+
// v4PoolProvider,
|
|
70
|
+
v3PoolProvider, onChainQuoteProvider, v2PoolProvider, v2QuoteProvider, v2SubgraphProvider, tokenProvider, blockedTokenListProvider, v3SubgraphProvider, gasPriceProvider,
|
|
71
|
+
// v4GasModelFactory,
|
|
72
|
+
v3GasModelFactory, v2GasModelFactory, mixedRouteGasModelFactory, swapRouterProvider, tokenValidatorProvider, arbitrumGasDataProvider, simulator, routeCachingProvider, tokenPropertiesProvider, portionProvider, v2Supported,
|
|
73
|
+
// v4Supported,
|
|
74
|
+
universalRouterVersion, }) {
|
|
75
|
+
this.chainId = chainId;
|
|
76
|
+
this.provider = provider;
|
|
77
|
+
this.multicall2Provider =
|
|
78
|
+
multicall2Provider !== null && multicall2Provider !== void 0 ? multicall2Provider : new providers_2.UniswapMulticallProvider(chainId, provider, 375000);
|
|
79
|
+
// this.v4PoolProvider =
|
|
80
|
+
// v4PoolProvider ??
|
|
81
|
+
// new CachingV4PoolProvider(
|
|
82
|
+
// this.chainId,
|
|
83
|
+
// new V4PoolProvider(ID_TO_CHAIN_ID(chainId), this.multicall2Provider),
|
|
84
|
+
// new NodeJSCache(new NodeCache({ stdTTL: 360, useClones: false }))
|
|
85
|
+
// );
|
|
86
|
+
this.v3PoolProvider =
|
|
87
|
+
v3PoolProvider !== null && v3PoolProvider !== void 0 ? v3PoolProvider : new providers_2.CachingV3PoolProvider(this.chainId, new pool_provider_2.V3PoolProvider((0, chains_1.ID_TO_CHAIN_ID)(chainId), this.multicall2Provider), new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 360, useClones: false })));
|
|
88
|
+
this.simulator = simulator;
|
|
89
|
+
this.routeCachingProvider = routeCachingProvider;
|
|
90
|
+
if (onChainQuoteProvider) {
|
|
91
|
+
this.onChainQuoteProvider = onChainQuoteProvider;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// Only Chiliz and Spicy are supported - use default config
|
|
95
|
+
this.onChainQuoteProvider = new providers_2.OnChainQuoteProvider(chainId, provider, this.multicall2Provider, onchainQuoteProviderConfigs_1.DEFAULT_RETRY_OPTIONS, (_) => onchainQuoteProviderConfigs_1.DEFAULT_BATCH_PARAMS, onchainQuoteProviderConfigs_1.DEFAULT_GAS_ERROR_FAILURE_OVERRIDES, onchainQuoteProviderConfigs_1.DEFAULT_SUCCESS_RATE_FAILURE_OVERRIDES, onchainQuoteProviderConfigs_1.DEFAULT_BLOCK_NUMBER_CONFIGS);
|
|
96
|
+
}
|
|
97
|
+
if (tokenValidatorProvider) {
|
|
98
|
+
this.tokenValidatorProvider = tokenValidatorProvider;
|
|
99
|
+
// } else if (this.chainId === ChainId.MAINNET) { // MAINNET removed
|
|
100
|
+
}
|
|
101
|
+
else if (false) {
|
|
102
|
+
this.tokenValidatorProvider = new token_validator_provider_1.TokenValidatorProvider(this.chainId, this.multicall2Provider, new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 30000, useClones: false })));
|
|
103
|
+
}
|
|
104
|
+
if (tokenPropertiesProvider) {
|
|
105
|
+
this.tokenPropertiesProvider = tokenPropertiesProvider;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
this.tokenPropertiesProvider = new providers_2.TokenPropertiesProvider(this.chainId, new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 86400, useClones: false })), new token_fee_fetcher_1.OnChainTokenFeeFetcher(this.chainId, provider));
|
|
109
|
+
}
|
|
110
|
+
this.v2PoolProvider =
|
|
111
|
+
v2PoolProvider !== null && v2PoolProvider !== void 0 ? v2PoolProvider : new providers_2.CachingV2PoolProvider(chainId, new pool_provider_1.V2PoolProvider(chainId, this.multicall2Provider, this.tokenPropertiesProvider), new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 60, useClones: false })));
|
|
112
|
+
this.v2QuoteProvider = v2QuoteProvider !== null && v2QuoteProvider !== void 0 ? v2QuoteProvider : new providers_2.V2QuoteProvider();
|
|
113
|
+
this.blockedTokenListProvider =
|
|
114
|
+
blockedTokenListProvider !== null && blockedTokenListProvider !== void 0 ? blockedTokenListProvider : new caching_token_list_provider_1.CachingTokenListProvider(chainId, unsupported_tokens_1.UNSUPPORTED_TOKENS, new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 3600, useClones: false })));
|
|
115
|
+
this.tokenProvider =
|
|
116
|
+
tokenProvider !== null && tokenProvider !== void 0 ? tokenProvider : new providers_2.CachingTokenProviderWithFallback(chainId, new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 3600, useClones: false })), new caching_token_list_provider_1.CachingTokenListProvider(chainId, default_token_list_1.default, new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 3600, useClones: false }))), new token_provider_1.TokenProvider(chainId, this.multicall2Provider));
|
|
117
|
+
this.portionProvider = portionProvider !== null && portionProvider !== void 0 ? portionProvider : new portion_provider_1.PortionProvider();
|
|
118
|
+
const chainName = (0, chains_1.ID_TO_NETWORK_NAME)(chainId);
|
|
119
|
+
// ipfs urls in the following format: `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/${protocol}/${chainName}.json`;
|
|
120
|
+
if (v2SubgraphProvider) {
|
|
121
|
+
this.v2SubgraphProvider = v2SubgraphProvider;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
this.v2SubgraphProvider = new providers_2.V2SubgraphProviderWithFallBacks([
|
|
125
|
+
new providers_2.CachingV2SubgraphProvider(chainId, new providers_2.URISubgraphProvider(chainId, `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/v2/${chainName}.json`, undefined, 0), new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 300, useClones: false }))),
|
|
126
|
+
new providers_2.StaticV2SubgraphProvider(chainId),
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
if (v3SubgraphProvider) {
|
|
130
|
+
this.v3SubgraphProvider = v3SubgraphProvider;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
this.v3SubgraphProvider = new providers_2.V3SubgraphProviderWithFallBacks([
|
|
134
|
+
new providers_2.CachingV3SubgraphProvider(chainId, new providers_2.URISubgraphProvider(chainId, `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/v3/${chainName}.json`, undefined, 0), new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 300, useClones: false }))),
|
|
135
|
+
new providers_2.StaticV3SubgraphProvider(chainId, this.v3PoolProvider),
|
|
136
|
+
]);
|
|
137
|
+
}
|
|
138
|
+
// if (v4SubgraphProvider) {
|
|
139
|
+
// this.v4SubgraphProvider = v4SubgraphProvider;
|
|
140
|
+
// } else {
|
|
141
|
+
// this.v4SubgraphProvider = new V4SubgraphProviderWithFallBacks([
|
|
142
|
+
// new CachingV4SubgraphProvider(
|
|
143
|
+
// chainId,
|
|
144
|
+
// new URISubgraphProvider(
|
|
145
|
+
// chainId,
|
|
146
|
+
// `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/v4/${chainName}.json`,
|
|
147
|
+
// undefined,
|
|
148
|
+
// 0
|
|
149
|
+
// ),
|
|
150
|
+
// new NodeJSCache(new NodeCache({ stdTTL: 300, useClones: false }))
|
|
151
|
+
// ),
|
|
152
|
+
// new StaticV4SubgraphProvider(chainId, this.v4PoolProvider),
|
|
153
|
+
// ]);
|
|
154
|
+
// }
|
|
155
|
+
let gasPriceProviderInstance;
|
|
156
|
+
if (providers_1.JsonRpcProvider.isProvider(this.provider)) {
|
|
157
|
+
gasPriceProviderInstance = new providers_2.OnChainGasPriceProvider(chainId, new providers_2.EIP1559GasPriceProvider(this.provider), new providers_2.LegacyGasPriceProvider(this.provider));
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
gasPriceProviderInstance = new providers_2.ETHGasStationInfoProvider(config_1.ETH_GAS_STATION_API_URL);
|
|
161
|
+
}
|
|
162
|
+
this.gasPriceProvider =
|
|
163
|
+
gasPriceProvider !== null && gasPriceProvider !== void 0 ? gasPriceProvider : new providers_2.CachingGasStationProvider(chainId, gasPriceProviderInstance, new providers_2.NodeJSCache(new node_cache_1.default({ stdTTL: 7, useClones: false })));
|
|
164
|
+
// this.v4GasModelFactory =
|
|
165
|
+
// v4GasModelFactory ?? new V4HeuristicGasModelFactory(this.provider);
|
|
166
|
+
this.v3GasModelFactory =
|
|
167
|
+
v3GasModelFactory !== null && v3GasModelFactory !== void 0 ? v3GasModelFactory : new v3_heuristic_gas_model_1.V3HeuristicGasModelFactory(this.provider);
|
|
168
|
+
this.v2GasModelFactory =
|
|
169
|
+
v2GasModelFactory !== null && v2GasModelFactory !== void 0 ? v2GasModelFactory : new v2_heuristic_gas_model_1.V2HeuristicGasModelFactory(this.provider);
|
|
170
|
+
this.mixedRouteGasModelFactory =
|
|
171
|
+
mixedRouteGasModelFactory !== null && mixedRouteGasModelFactory !== void 0 ? mixedRouteGasModelFactory : new mixed_route_heuristic_gas_model_1.MixedRouteHeuristicGasModelFactory();
|
|
172
|
+
this.swapRouterProvider =
|
|
173
|
+
swapRouterProvider !== null && swapRouterProvider !== void 0 ? swapRouterProvider : new providers_2.SwapRouterProvider(this.multicall2Provider, this.chainId);
|
|
174
|
+
if (
|
|
175
|
+
// chainId === ChainId.ARBITRUM_ONE || // ARBITRUM chains removed
|
|
176
|
+
// chainId === ChainId.ARBITRUM_GOERLI
|
|
177
|
+
false) {
|
|
178
|
+
this.l2GasDataProvider =
|
|
179
|
+
arbitrumGasDataProvider !== null && arbitrumGasDataProvider !== void 0 ? arbitrumGasDataProvider : new gas_data_provider_1.ArbitrumGasDataProvider(chainId, this.provider);
|
|
180
|
+
}
|
|
181
|
+
// Initialize the Quoters.
|
|
182
|
+
// Quoters are an abstraction encapsulating the business logic of fetching routes and quotes.
|
|
183
|
+
this.v2Quoter = new quoters_1.V2Quoter(this.v2SubgraphProvider, this.v2PoolProvider, this.v2QuoteProvider, this.v2GasModelFactory, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider, this.l2GasDataProvider);
|
|
184
|
+
this.v3Quoter = new quoters_1.V3Quoter(this.v3SubgraphProvider, this.v3PoolProvider, this.onChainQuoteProvider, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
185
|
+
// this.v4Quoter = new V4Quoter(
|
|
186
|
+
// this.v4SubgraphProvider,
|
|
187
|
+
// this.v4PoolProvider,
|
|
188
|
+
// this.onChainQuoteProvider,
|
|
189
|
+
// this.tokenProvider,
|
|
190
|
+
// this.chainId,
|
|
191
|
+
// this.blockedTokenListProvider,
|
|
192
|
+
// this.tokenValidatorProvider
|
|
193
|
+
// );
|
|
194
|
+
this.mixedQuoter = new quoters_1.MixedQuoter(
|
|
195
|
+
// this.v4SubgraphProvider,
|
|
196
|
+
// this.v4PoolProvider,
|
|
197
|
+
this.v3SubgraphProvider, this.v3PoolProvider, this.v2SubgraphProvider, this.v2PoolProvider, this.onChainQuoteProvider, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
198
|
+
this.v2Supported = v2Supported !== null && v2Supported !== void 0 ? v2Supported : chains_1.V2_SUPPORTED;
|
|
199
|
+
// this.v4Supported = v4Supported ?? V4_SUPPORTED;
|
|
200
|
+
this.universalRouterVersion =
|
|
201
|
+
universalRouterVersion !== null && universalRouterVersion !== void 0 ? universalRouterVersion : universal_router_sdk_1.UniversalRouterVersion.V1_2;
|
|
202
|
+
}
|
|
203
|
+
async routeToRatio(token0Balance, token1Balance, position, swapAndAddConfig, swapAndAddOptions, routingConfig = (0, config_1.DEFAULT_ROUTING_CONFIG_BY_CHAIN)(this.chainId)) {
|
|
204
|
+
if (token1Balance.currency.wrapped.sortsBefore(token0Balance.currency.wrapped)) {
|
|
205
|
+
[token0Balance, token1Balance] = [token1Balance, token0Balance];
|
|
206
|
+
}
|
|
207
|
+
let preSwapOptimalRatio = this.calculateOptimalRatio(position, position.pool.sqrtRatioX96, true);
|
|
208
|
+
// set up parameters according to which token will be swapped
|
|
209
|
+
let zeroForOne;
|
|
210
|
+
if (position.pool.tickCurrent > position.tickUpper) {
|
|
211
|
+
zeroForOne = true;
|
|
212
|
+
}
|
|
213
|
+
else if (position.pool.tickCurrent < position.tickLower) {
|
|
214
|
+
zeroForOne = false;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
zeroForOne = new sdk_core_1.Fraction(token0Balance.quotient, token1Balance.quotient).greaterThan(preSwapOptimalRatio);
|
|
218
|
+
if (!zeroForOne)
|
|
219
|
+
preSwapOptimalRatio = preSwapOptimalRatio.invert();
|
|
220
|
+
}
|
|
221
|
+
const [inputBalance, outputBalance] = zeroForOne
|
|
222
|
+
? [token0Balance, token1Balance]
|
|
223
|
+
: [token1Balance, token0Balance];
|
|
224
|
+
let optimalRatio = preSwapOptimalRatio;
|
|
225
|
+
let postSwapTargetPool = position.pool;
|
|
226
|
+
let exchangeRate = zeroForOne
|
|
227
|
+
? position.pool.token0Price
|
|
228
|
+
: position.pool.token1Price;
|
|
229
|
+
let swap = null;
|
|
230
|
+
let ratioAchieved = false;
|
|
231
|
+
let n = 0;
|
|
232
|
+
// iterate until we find a swap with a sufficient ratio or return null
|
|
233
|
+
while (!ratioAchieved) {
|
|
234
|
+
n++;
|
|
235
|
+
if (n > swapAndAddConfig.maxIterations) {
|
|
236
|
+
log_1.log.info('max iterations exceeded');
|
|
237
|
+
return {
|
|
238
|
+
status: router_1.SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
239
|
+
error: 'max iterations exceeded',
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
const amountToSwap = (0, calculate_ratio_amount_in_1.calculateRatioAmountIn)(optimalRatio, exchangeRate, inputBalance, outputBalance);
|
|
243
|
+
if (amountToSwap.equalTo(0)) {
|
|
244
|
+
log_1.log.info(`no swap needed: amountToSwap = 0`);
|
|
245
|
+
return {
|
|
246
|
+
status: router_1.SwapToRatioStatus.NO_SWAP_NEEDED,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
swap = await this.route(amountToSwap, outputBalance.currency, sdk_core_1.TradeType.EXACT_INPUT, undefined, Object.assign(Object.assign(Object.assign({}, (0, config_1.DEFAULT_ROUTING_CONFIG_BY_CHAIN)(this.chainId)), routingConfig), {
|
|
250
|
+
/// @dev We do not want to query for mixedRoutes for routeToRatio as they are not supported
|
|
251
|
+
/// [Protocol.V3, Protocol.V2] will make sure we only query for V3 and V2
|
|
252
|
+
protocols: [router_sdk_1.Protocol.V3, router_sdk_1.Protocol.V2] }));
|
|
253
|
+
if (!swap) {
|
|
254
|
+
log_1.log.info('no route found from this.route()');
|
|
255
|
+
return {
|
|
256
|
+
status: router_1.SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
257
|
+
error: 'no route found',
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const inputBalanceUpdated = inputBalance.subtract(swap.trade.inputAmount);
|
|
261
|
+
const outputBalanceUpdated = outputBalance.add(swap.trade.outputAmount);
|
|
262
|
+
const newRatio = inputBalanceUpdated.divide(outputBalanceUpdated);
|
|
263
|
+
let targetPoolPriceUpdate;
|
|
264
|
+
swap.route.forEach((route) => {
|
|
265
|
+
if (route.protocol === router_sdk_1.Protocol.V3) {
|
|
266
|
+
const v3Route = route;
|
|
267
|
+
v3Route.route.pools.forEach((pool, i) => {
|
|
268
|
+
if (pool.token0.equals(position.pool.token0) &&
|
|
269
|
+
pool.token1.equals(position.pool.token1) &&
|
|
270
|
+
pool.fee === position.pool.fee) {
|
|
271
|
+
targetPoolPriceUpdate = jsbi_1.default.BigInt(v3Route.sqrtPriceX96AfterList[i].toString());
|
|
272
|
+
optimalRatio = this.calculateOptimalRatio(position, jsbi_1.default.BigInt(targetPoolPriceUpdate.toString()), zeroForOne);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
if (!targetPoolPriceUpdate) {
|
|
278
|
+
optimalRatio = preSwapOptimalRatio;
|
|
279
|
+
}
|
|
280
|
+
ratioAchieved =
|
|
281
|
+
newRatio.equalTo(optimalRatio) ||
|
|
282
|
+
this.absoluteValue(newRatio.asFraction.divide(optimalRatio).subtract(1)).lessThan(swapAndAddConfig.ratioErrorTolerance);
|
|
283
|
+
if (ratioAchieved && targetPoolPriceUpdate) {
|
|
284
|
+
postSwapTargetPool = new v3_sdk_1.Pool(position.pool.token0, position.pool.token1, position.pool.fee, targetPoolPriceUpdate, position.pool.liquidity, v3_sdk_1.TickMath.getTickAtSqrtRatio(targetPoolPriceUpdate), position.pool.tickDataProvider);
|
|
285
|
+
}
|
|
286
|
+
exchangeRate = swap.trade.outputAmount.divide(swap.trade.inputAmount);
|
|
287
|
+
log_1.log.info({
|
|
288
|
+
exchangeRate: exchangeRate.asFraction.toFixed(18),
|
|
289
|
+
optimalRatio: optimalRatio.asFraction.toFixed(18),
|
|
290
|
+
newRatio: newRatio.asFraction.toFixed(18),
|
|
291
|
+
inputBalanceUpdated: inputBalanceUpdated.asFraction.toFixed(18),
|
|
292
|
+
outputBalanceUpdated: outputBalanceUpdated.asFraction.toFixed(18),
|
|
293
|
+
ratioErrorTolerance: swapAndAddConfig.ratioErrorTolerance.toFixed(18),
|
|
294
|
+
iterationN: n.toString(),
|
|
295
|
+
}, 'QuoteToRatio Iteration Parameters');
|
|
296
|
+
if (exchangeRate.equalTo(0)) {
|
|
297
|
+
log_1.log.info('exchangeRate to 0');
|
|
298
|
+
return {
|
|
299
|
+
status: router_1.SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
300
|
+
error: 'insufficient liquidity to swap to optimal ratio',
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (!swap) {
|
|
305
|
+
return {
|
|
306
|
+
status: router_1.SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
307
|
+
error: 'no route found',
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
let methodParameters;
|
|
311
|
+
if (swapAndAddOptions) {
|
|
312
|
+
methodParameters = await this.buildSwapAndAddMethodParameters(swap.trade, swapAndAddOptions, {
|
|
313
|
+
initialBalanceTokenIn: inputBalance,
|
|
314
|
+
initialBalanceTokenOut: outputBalance,
|
|
315
|
+
preLiquidityPosition: position,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
status: router_1.SwapToRatioStatus.SUCCESS,
|
|
320
|
+
result: Object.assign(Object.assign({}, swap), { methodParameters, optimalRatio, postSwapTargetPool }),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* @inheritdoc IRouter
|
|
325
|
+
*/
|
|
326
|
+
async route(amount, quoteCurrency, tradeType, swapConfig, partialRoutingConfig = {}) {
|
|
327
|
+
var _a, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
328
|
+
const originalAmount = amount;
|
|
329
|
+
const { currencyIn, currencyOut } = this.determineCurrencyInOutFromTradeType(tradeType, amount, quoteCurrency);
|
|
330
|
+
const tokenIn = currencyIn.wrapped;
|
|
331
|
+
const tokenOut = currencyOut.wrapped;
|
|
332
|
+
const tokenOutProperties = await this.tokenPropertiesProvider.getTokensProperties([currencyOut], partialRoutingConfig);
|
|
333
|
+
const feeTakenOnTransfer = (_c = (_a = tokenOutProperties[(0, util_1.getAddressLowerCase)(currencyOut)]) === null || _a === void 0 ? void 0 : _a.tokenFeeResult) === null || _c === void 0 ? void 0 : _c.feeTakenOnTransfer;
|
|
334
|
+
const externalTransferFailed = (_e = (_d = tokenOutProperties[(0, util_1.getAddressLowerCase)(currencyOut)]) === null || _d === void 0 ? void 0 : _d.tokenFeeResult) === null || _e === void 0 ? void 0 : _e.externalTransferFailed;
|
|
335
|
+
// We want to log the fee on transfer output tokens that we are taking fee or not
|
|
336
|
+
// Ideally the trade size (normalized in USD) would be ideal to log here, but we don't have spot price of output tokens here.
|
|
337
|
+
// We have to make sure token out is FOT with either buy/sell fee bps > 0
|
|
338
|
+
if (((_h = (_g = (_f = tokenOutProperties[(0, util_1.getAddressLowerCase)(currencyOut)]) === null || _f === void 0 ? void 0 : _f.tokenFeeResult) === null || _g === void 0 ? void 0 : _g.buyFeeBps) === null || _h === void 0 ? void 0 : _h.gt(0)) ||
|
|
339
|
+
((_l = (_k = (_j = tokenOutProperties[(0, util_1.getAddressLowerCase)(currencyOut)]) === null || _j === void 0 ? void 0 : _j.tokenFeeResult) === null || _k === void 0 ? void 0 : _k.sellFeeBps) === null || _l === void 0 ? void 0 : _l.gt(0))) {
|
|
340
|
+
if (feeTakenOnTransfer || externalTransferFailed) {
|
|
341
|
+
// also to be extra safe, in case of FOT with feeTakenOnTransfer or externalTransferFailed,
|
|
342
|
+
// we nullify the fee and flat fee to avoid any potential issues.
|
|
343
|
+
// although neither web nor wallet should use the calldata returned from routing/SOR
|
|
344
|
+
if ((swapConfig === null || swapConfig === void 0 ? void 0 : swapConfig.type) === router_1.SwapType.UNIVERSAL_ROUTER) {
|
|
345
|
+
swapConfig.fee = undefined;
|
|
346
|
+
swapConfig.flatFee = undefined;
|
|
347
|
+
}
|
|
348
|
+
metric_1.metric.putMetric('TokenOutFeeOnTransferNotTakingFee', 1, metric_1.MetricLoggerUnit.Count);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
metric_1.metric.putMetric('TokenOutFeeOnTransferTakingFee', 1, metric_1.MetricLoggerUnit.Count);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (tradeType === sdk_core_1.TradeType.EXACT_OUTPUT) {
|
|
355
|
+
const portionAmount = this.portionProvider.getPortionAmount(amount, tradeType, feeTakenOnTransfer, externalTransferFailed, swapConfig);
|
|
356
|
+
if (portionAmount && portionAmount.greaterThan(router_sdk_1.ZERO)) {
|
|
357
|
+
// In case of exact out swap, before we route, we need to make sure that the
|
|
358
|
+
// token out amount accounts for flat portion, and token in amount after the best swap route contains the token in equivalent of portion.
|
|
359
|
+
// In other words, in case a pool's LP fee bps is lower than the portion bps (0.01%/0.05% for v3), a pool can go insolvency.
|
|
360
|
+
// This is because instead of the swapper being responsible for the portion,
|
|
361
|
+
// the pool instead gets responsible for the portion.
|
|
362
|
+
// The addition below avoids that situation.
|
|
363
|
+
amount = amount.add(portionAmount);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
metric_1.metric.setProperty('chainId', this.chainId);
|
|
367
|
+
metric_1.metric.setProperty('pair', `${currencyIn.symbol}/${currencyOut.symbol}`);
|
|
368
|
+
metric_1.metric.setProperty('tokenIn', (0, util_1.getAddress)(currencyIn));
|
|
369
|
+
metric_1.metric.setProperty('tokenOut', (0, util_1.getAddress)(currencyOut));
|
|
370
|
+
metric_1.metric.setProperty('tradeType', tradeType === sdk_core_1.TradeType.EXACT_INPUT ? 'ExactIn' : 'ExactOut');
|
|
371
|
+
metric_1.metric.putMetric(`QuoteRequestedForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
372
|
+
// Get a block number to specify in all our calls. Ensures data we fetch from chain is
|
|
373
|
+
// from the same block.
|
|
374
|
+
const blockNumber = (_m = partialRoutingConfig.blockNumber) !== null && _m !== void 0 ? _m : this.getBlockNumberPromise();
|
|
375
|
+
const routingConfig = lodash_1.default.merge({
|
|
376
|
+
// These settings could be changed by the partialRoutingConfig
|
|
377
|
+
useCachedRoutes: true,
|
|
378
|
+
writeToCachedRoutes: true,
|
|
379
|
+
optimisticCachedRoutes: false,
|
|
380
|
+
}, (0, config_1.DEFAULT_ROUTING_CONFIG_BY_CHAIN)(this.chainId), partialRoutingConfig, { blockNumber });
|
|
381
|
+
if (routingConfig.debugRouting) {
|
|
382
|
+
log_1.log.warn(`Finalized routing config is ${JSON.stringify(routingConfig)}`);
|
|
383
|
+
}
|
|
384
|
+
const gasPriceWei = await this.getGasPriceWei(await blockNumber, await partialRoutingConfig.blockNumber);
|
|
385
|
+
const quoteToken = quoteCurrency.wrapped;
|
|
386
|
+
// const gasTokenAccessor = await this.tokenProvider.getTokens([routingConfig.gasToken!]);
|
|
387
|
+
const gasToken = routingConfig.gasToken
|
|
388
|
+
? (await this.tokenProvider.getTokens([routingConfig.gasToken])).getTokenByAddress(routingConfig.gasToken)
|
|
389
|
+
: undefined;
|
|
390
|
+
const providerConfig = Object.assign(Object.assign({}, routingConfig), { blockNumber, additionalGasOverhead: (0, gas_costs_1.NATIVE_OVERHEAD)(this.chainId, amount.currency, quoteCurrency), gasToken,
|
|
391
|
+
externalTransferFailed,
|
|
392
|
+
feeTakenOnTransfer });
|
|
393
|
+
const { v2GasModel: v2GasModel, v3GasModel: v3GasModel,
|
|
394
|
+
// v4GasModel: v4GasModel,
|
|
395
|
+
mixedRouteGasModel: mixedRouteGasModel, } = await this.getGasModels(gasPriceWei, amount.currency.wrapped, quoteToken, providerConfig);
|
|
396
|
+
// Create a Set to sanitize the protocols input, a Set of undefined becomes an empty set,
|
|
397
|
+
// Then create an Array from the values of that Set.
|
|
398
|
+
const protocols = Array.from(new Set(routingConfig.protocols).values());
|
|
399
|
+
const cacheMode = (_o = routingConfig.overwriteCacheMode) !== null && _o !== void 0 ? _o : (await ((_p = this.routeCachingProvider) === null || _p === void 0 ? void 0 : _p.getCacheMode(this.chainId, amount, quoteToken, tradeType, protocols)));
|
|
400
|
+
// Fetch CachedRoutes
|
|
401
|
+
let cachedRoutes;
|
|
402
|
+
if (routingConfig.useCachedRoutes && cacheMode !== providers_2.CacheMode.Darkmode) {
|
|
403
|
+
cachedRoutes = await ((_q = this.routeCachingProvider) === null || _q === void 0 ? void 0 : _q.getCachedRoute(this.chainId, amount, quoteToken, tradeType, protocols, await blockNumber, routingConfig.optimisticCachedRoutes));
|
|
404
|
+
}
|
|
405
|
+
if ((0, util_1.shouldWipeoutCachedRoutes)(cachedRoutes, routingConfig)) {
|
|
406
|
+
cachedRoutes = undefined;
|
|
407
|
+
}
|
|
408
|
+
metric_1.metric.putMetric(routingConfig.useCachedRoutes
|
|
409
|
+
? 'GetQuoteUsingCachedRoutes'
|
|
410
|
+
: 'GetQuoteNotUsingCachedRoutes', 1, metric_1.MetricLoggerUnit.Count);
|
|
411
|
+
if (cacheMode &&
|
|
412
|
+
routingConfig.useCachedRoutes &&
|
|
413
|
+
cacheMode !== providers_2.CacheMode.Darkmode &&
|
|
414
|
+
!cachedRoutes) {
|
|
415
|
+
metric_1.metric.putMetric(`GetCachedRoute_miss_${cacheMode}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
416
|
+
log_1.log.info({
|
|
417
|
+
tokenIn: tokenIn.symbol,
|
|
418
|
+
tokenInAddress: tokenIn.address,
|
|
419
|
+
tokenOut: tokenOut.symbol,
|
|
420
|
+
tokenOutAddress: tokenOut.address,
|
|
421
|
+
cacheMode,
|
|
422
|
+
amount: amount.toExact(),
|
|
423
|
+
chainId: this.chainId,
|
|
424
|
+
tradeType: this.tradeTypeStr(tradeType),
|
|
425
|
+
}, `GetCachedRoute miss ${cacheMode} for ${this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType)}`);
|
|
426
|
+
}
|
|
427
|
+
else if (cachedRoutes && routingConfig.useCachedRoutes) {
|
|
428
|
+
metric_1.metric.putMetric(`GetCachedRoute_hit_${cacheMode}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
429
|
+
log_1.log.info({
|
|
430
|
+
tokenIn: tokenIn.symbol,
|
|
431
|
+
tokenInAddress: tokenIn.address,
|
|
432
|
+
tokenOut: tokenOut.symbol,
|
|
433
|
+
tokenOutAddress: tokenOut.address,
|
|
434
|
+
cacheMode,
|
|
435
|
+
amount: amount.toExact(),
|
|
436
|
+
chainId: this.chainId,
|
|
437
|
+
tradeType: this.tradeTypeStr(tradeType),
|
|
438
|
+
}, `GetCachedRoute hit ${cacheMode} for ${this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType)}`);
|
|
439
|
+
}
|
|
440
|
+
let swapRouteFromCachePromise = Promise.resolve(null);
|
|
441
|
+
if (cachedRoutes) {
|
|
442
|
+
swapRouteFromCachePromise = this.getSwapRouteFromCache(tokenIn, tokenOut, cachedRoutes, await blockNumber, amount, quoteToken, tradeType, routingConfig, v3GasModel,
|
|
443
|
+
// v4GasModel,
|
|
444
|
+
mixedRouteGasModel, gasPriceWei, v2GasModel, swapConfig, providerConfig);
|
|
445
|
+
}
|
|
446
|
+
let swapRouteFromChainPromise = Promise.resolve(null);
|
|
447
|
+
if (!cachedRoutes || cacheMode !== providers_2.CacheMode.Livemode) {
|
|
448
|
+
swapRouteFromChainPromise = this.getSwapRouteFromChain(amount, tokenIn, tokenOut, protocols, quoteToken, tradeType, routingConfig, v3GasModel,
|
|
449
|
+
// v4GasModel,
|
|
450
|
+
mixedRouteGasModel, gasPriceWei, v2GasModel, swapConfig, providerConfig);
|
|
451
|
+
}
|
|
452
|
+
const [swapRouteFromCache, swapRouteFromChain] = await Promise.all([
|
|
453
|
+
swapRouteFromCachePromise,
|
|
454
|
+
swapRouteFromChainPromise,
|
|
455
|
+
]);
|
|
456
|
+
let swapRouteRaw;
|
|
457
|
+
let hitsCachedRoute = false;
|
|
458
|
+
if (cacheMode === providers_2.CacheMode.Livemode && swapRouteFromCache) {
|
|
459
|
+
log_1.log.info(`CacheMode is ${cacheMode}, and we are using swapRoute from cache`);
|
|
460
|
+
hitsCachedRoute = true;
|
|
461
|
+
swapRouteRaw = swapRouteFromCache;
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
log_1.log.info(`CacheMode is ${cacheMode}, and we are using materialized swapRoute`);
|
|
465
|
+
swapRouteRaw = swapRouteFromChain;
|
|
466
|
+
}
|
|
467
|
+
if (cacheMode === providers_2.CacheMode.Tapcompare &&
|
|
468
|
+
swapRouteFromCache &&
|
|
469
|
+
swapRouteFromChain) {
|
|
470
|
+
const quoteDiff = swapRouteFromChain.quote.subtract(swapRouteFromCache.quote);
|
|
471
|
+
const quoteGasAdjustedDiff = swapRouteFromChain.quoteGasAdjusted.subtract(swapRouteFromCache.quoteGasAdjusted);
|
|
472
|
+
const gasUsedDiff = swapRouteFromChain.estimatedGasUsed.sub(swapRouteFromCache.estimatedGasUsed);
|
|
473
|
+
// Only log if quoteDiff is different from 0, or if quoteGasAdjustedDiff and gasUsedDiff are both different from 0
|
|
474
|
+
if (!quoteDiff.equalTo(0) ||
|
|
475
|
+
!(quoteGasAdjustedDiff.equalTo(0) || gasUsedDiff.eq(0))) {
|
|
476
|
+
try {
|
|
477
|
+
// Calculates the percentage of the difference with respect to the quoteFromChain (not from cache)
|
|
478
|
+
const misquotePercent = quoteGasAdjustedDiff
|
|
479
|
+
.divide(swapRouteFromChain.quoteGasAdjusted)
|
|
480
|
+
.multiply(100);
|
|
481
|
+
metric_1.metric.putMetric(`TapcompareCachedRoute_quoteGasAdjustedDiffPercent`, Number(misquotePercent.toExact()), metric_1.MetricLoggerUnit.Percent);
|
|
482
|
+
log_1.log.warn({
|
|
483
|
+
quoteFromChain: swapRouteFromChain.quote.toExact(),
|
|
484
|
+
quoteFromCache: swapRouteFromCache.quote.toExact(),
|
|
485
|
+
quoteDiff: quoteDiff.toExact(),
|
|
486
|
+
quoteGasAdjustedFromChain: swapRouteFromChain.quoteGasAdjusted.toExact(),
|
|
487
|
+
quoteGasAdjustedFromCache: swapRouteFromCache.quoteGasAdjusted.toExact(),
|
|
488
|
+
quoteGasAdjustedDiff: quoteGasAdjustedDiff.toExact(),
|
|
489
|
+
gasUsedFromChain: swapRouteFromChain.estimatedGasUsed.toString(),
|
|
490
|
+
gasUsedFromCache: swapRouteFromCache.estimatedGasUsed.toString(),
|
|
491
|
+
gasUsedDiff: gasUsedDiff.toString(),
|
|
492
|
+
routesFromChain: swapRouteFromChain.routes.toString(),
|
|
493
|
+
routesFromCache: swapRouteFromCache.routes.toString(),
|
|
494
|
+
amount: amount.toExact(),
|
|
495
|
+
originalAmount: cachedRoutes === null || cachedRoutes === void 0 ? void 0 : cachedRoutes.originalAmount,
|
|
496
|
+
pair: this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType),
|
|
497
|
+
blockNumber,
|
|
498
|
+
}, `Comparing quotes between Chain and Cache for ${this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType)}`);
|
|
499
|
+
}
|
|
500
|
+
catch (error) {
|
|
501
|
+
// This is in response to the 'division by zero' error
|
|
502
|
+
// during https://uniswapteam.slack.com/archives/C059TGEC57W/p1723997015399579
|
|
503
|
+
if (error instanceof RangeError &&
|
|
504
|
+
error.message.includes('Division by zero')) {
|
|
505
|
+
log_1.log.error({
|
|
506
|
+
quoteGasAdjustedDiff: quoteGasAdjustedDiff.toExact(),
|
|
507
|
+
swapRouteFromChainQuoteGasAdjusted: swapRouteFromChain.quoteGasAdjusted.toExact(),
|
|
508
|
+
}, 'Error calculating misquote percent');
|
|
509
|
+
metric_1.metric.putMetric(`TapcompareCachedRoute_quoteGasAdjustedDiffPercent_divzero`, 1, metric_1.MetricLoggerUnit.Count);
|
|
510
|
+
}
|
|
511
|
+
// Log but don't throw here - this is only for logging.
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (!swapRouteRaw) {
|
|
516
|
+
return null;
|
|
517
|
+
}
|
|
518
|
+
const { quote, quoteGasAdjusted, estimatedGasUsed, routes: routeAmounts, estimatedGasUsedQuoteToken, estimatedGasUsedUSD, estimatedGasUsedGasToken, } = swapRouteRaw;
|
|
519
|
+
if (this.routeCachingProvider &&
|
|
520
|
+
routingConfig.writeToCachedRoutes &&
|
|
521
|
+
cacheMode !== providers_2.CacheMode.Darkmode &&
|
|
522
|
+
swapRouteFromChain) {
|
|
523
|
+
// Generate the object to be cached
|
|
524
|
+
const routesToCache = providers_2.CachedRoutes.fromRoutesWithValidQuotes(swapRouteFromChain.routes, this.chainId, tokenIn, tokenOut, protocols.sort(), await blockNumber, tradeType, amount.toExact());
|
|
525
|
+
if (routesToCache) {
|
|
526
|
+
// Attempt to insert the entry in cache. This is fire and forget promise.
|
|
527
|
+
// The catch method will prevent any exception from blocking the normal code execution.
|
|
528
|
+
this.routeCachingProvider
|
|
529
|
+
.setCachedRoute(routesToCache, amount)
|
|
530
|
+
.then((success) => {
|
|
531
|
+
const status = success ? 'success' : 'rejected';
|
|
532
|
+
metric_1.metric.putMetric(`SetCachedRoute_${status}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
533
|
+
})
|
|
534
|
+
.catch((reason) => {
|
|
535
|
+
log_1.log.error({
|
|
536
|
+
reason: reason,
|
|
537
|
+
tokenPair: this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType),
|
|
538
|
+
}, `SetCachedRoute failure`);
|
|
539
|
+
metric_1.metric.putMetric(`SetCachedRoute_failure`, 1, metric_1.MetricLoggerUnit.Count);
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
metric_1.metric.putMetric(`SetCachedRoute_unnecessary`, 1, metric_1.MetricLoggerUnit.Count);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
metric_1.metric.putMetric(`QuoteFoundForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
547
|
+
// Build Trade object that represents the optimal swap.
|
|
548
|
+
const trade = (0, methodParameters_1.buildTrade)(currencyIn, currencyOut, tradeType, routeAmounts);
|
|
549
|
+
let methodParameters;
|
|
550
|
+
// If user provided recipient, deadline etc. we also generate the calldata required to execute
|
|
551
|
+
// the swap and return it too.
|
|
552
|
+
if (swapConfig) {
|
|
553
|
+
methodParameters = (0, methodParameters_1.buildSwapMethodParameters)(trade, swapConfig, this.chainId);
|
|
554
|
+
}
|
|
555
|
+
const tokenOutAmount = tradeType === sdk_core_1.TradeType.EXACT_OUTPUT
|
|
556
|
+
? originalAmount // we need to pass in originalAmount instead of amount, because amount already added portionAmount in case of exact out swap
|
|
557
|
+
: quote;
|
|
558
|
+
const portionAmount = this.portionProvider.getPortionAmount(tokenOutAmount, tradeType, feeTakenOnTransfer, externalTransferFailed, swapConfig);
|
|
559
|
+
const portionQuoteAmount = this.portionProvider.getPortionQuoteAmount(tradeType, quote, amount, // we need to pass in amount instead of originalAmount here, because amount here needs to add the portion for exact out
|
|
560
|
+
portionAmount);
|
|
561
|
+
// we need to correct quote and quote gas adjusted for exact output when portion is part of the exact out swap
|
|
562
|
+
const correctedQuote = this.portionProvider.getQuote(tradeType, quote, portionQuoteAmount);
|
|
563
|
+
const correctedQuoteGasAdjusted = this.portionProvider.getQuoteGasAdjusted(tradeType, quoteGasAdjusted, portionQuoteAmount);
|
|
564
|
+
const quoteGasAndPortionAdjusted = this.portionProvider.getQuoteGasAndPortionAdjusted(tradeType, quoteGasAdjusted, portionAmount);
|
|
565
|
+
const swapRoute = {
|
|
566
|
+
quote: correctedQuote,
|
|
567
|
+
quoteGasAdjusted: correctedQuoteGasAdjusted,
|
|
568
|
+
estimatedGasUsed,
|
|
569
|
+
estimatedGasUsedQuoteToken,
|
|
570
|
+
estimatedGasUsedUSD,
|
|
571
|
+
estimatedGasUsedGasToken,
|
|
572
|
+
gasPriceWei,
|
|
573
|
+
route: routeAmounts,
|
|
574
|
+
trade,
|
|
575
|
+
methodParameters,
|
|
576
|
+
blockNumber: bignumber_1.BigNumber.from(await blockNumber),
|
|
577
|
+
hitsCachedRoute: hitsCachedRoute,
|
|
578
|
+
portionAmount: portionAmount,
|
|
579
|
+
quoteGasAndPortionAdjusted: quoteGasAndPortionAdjusted,
|
|
580
|
+
};
|
|
581
|
+
if (swapConfig &&
|
|
582
|
+
swapConfig.simulate &&
|
|
583
|
+
methodParameters &&
|
|
584
|
+
methodParameters.calldata) {
|
|
585
|
+
if (!this.simulator) {
|
|
586
|
+
throw new Error('Simulator not initialized!');
|
|
587
|
+
}
|
|
588
|
+
log_1.log.info(JSON.stringify({ swapConfig, methodParameters, providerConfig }, null, 2), `Starting simulation`);
|
|
589
|
+
const fromAddress = swapConfig.simulate.fromAddress;
|
|
590
|
+
const beforeSimulate = Date.now();
|
|
591
|
+
const swapRouteWithSimulation = await this.simulator.simulate(fromAddress, swapConfig, swapRoute, amount,
|
|
592
|
+
// Quote will be in WETH even if quoteCurrency is ETH
|
|
593
|
+
// So we init a new CurrencyAmount object here
|
|
594
|
+
amounts_1.CurrencyAmount.fromRawAmount(quoteCurrency, quote.quotient.toString()), providerConfig);
|
|
595
|
+
metric_1.metric.putMetric('SimulateTransaction', Date.now() - beforeSimulate, metric_1.MetricLoggerUnit.Milliseconds);
|
|
596
|
+
return swapRouteWithSimulation;
|
|
597
|
+
}
|
|
598
|
+
return swapRoute;
|
|
599
|
+
}
|
|
600
|
+
async getSwapRouteFromCache(tokenIn, tokenOut, cachedRoutes, blockNumber, amount, quoteToken, tradeType, routingConfig, v3GasModel,
|
|
601
|
+
// v4GasModel: IGasModel<V4RouteWithValidQuote>,
|
|
602
|
+
mixedRouteGasModel, gasPriceWei, v2GasModel, swapConfig, providerConfig) {
|
|
603
|
+
var _a, _c, _d, _e, _f, _g;
|
|
604
|
+
const tokenPairProperties = await this.tokenPropertiesProvider.getTokensProperties([tokenIn, tokenOut], providerConfig);
|
|
605
|
+
const sellTokenIsFot = (_d = (_c = (_a = tokenPairProperties[tokenIn.address.toLowerCase()]) === null || _a === void 0 ? void 0 : _a.tokenFeeResult) === null || _c === void 0 ? void 0 : _c.sellFeeBps) === null || _d === void 0 ? void 0 : _d.gt(0);
|
|
606
|
+
const buyTokenIsFot = (_g = (_f = (_e = tokenPairProperties[tokenOut.address.toLowerCase()]) === null || _e === void 0 ? void 0 : _e.tokenFeeResult) === null || _f === void 0 ? void 0 : _f.buyFeeBps) === null || _g === void 0 ? void 0 : _g.gt(0);
|
|
607
|
+
const fotInDirectSwap = sellTokenIsFot || buyTokenIsFot;
|
|
608
|
+
log_1.log.info({
|
|
609
|
+
protocols: cachedRoutes.protocolsCovered,
|
|
610
|
+
tradeType: cachedRoutes.tradeType,
|
|
611
|
+
cachedBlockNumber: cachedRoutes.blockNumber,
|
|
612
|
+
quoteBlockNumber: blockNumber,
|
|
613
|
+
}, 'Routing across CachedRoute');
|
|
614
|
+
const quotePromises = [];
|
|
615
|
+
// const v4Routes = cachedRoutes.routes.filter(
|
|
616
|
+
// (route) => route.protocol === Protocol.V4
|
|
617
|
+
// );
|
|
618
|
+
const v3Routes = cachedRoutes.routes.filter((route) => route.protocol === router_sdk_1.Protocol.V3);
|
|
619
|
+
const v2Routes = cachedRoutes.routes.filter((route) => route.protocol === router_sdk_1.Protocol.V2);
|
|
620
|
+
const mixedRoutes = cachedRoutes.routes.filter((route) => route.protocol === router_sdk_1.Protocol.MIXED);
|
|
621
|
+
let percents;
|
|
622
|
+
let amounts;
|
|
623
|
+
if (cachedRoutes.routes.length > 1) {
|
|
624
|
+
// If we have more than 1 route, we will quote the different percents for it, following the regular process
|
|
625
|
+
[percents, amounts] = this.getAmountDistribution(amount, routingConfig);
|
|
626
|
+
}
|
|
627
|
+
else if (cachedRoutes.routes.length == 1) {
|
|
628
|
+
[percents, amounts] = [[100], [amount]];
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
// In this case this means that there's no route, so we return null
|
|
632
|
+
return Promise.resolve(null);
|
|
633
|
+
}
|
|
634
|
+
// if (v4Routes.length > 0) {
|
|
635
|
+
// const v4RoutesFromCache: V4Route[] = v4Routes.map(
|
|
636
|
+
// (cachedRoute) => cachedRoute.route as V4Route
|
|
637
|
+
// );
|
|
638
|
+
// metric.putMetric(
|
|
639
|
+
// 'SwapRouteFromCache_V4_GetQuotes_Request',
|
|
640
|
+
// 1,
|
|
641
|
+
// MetricLoggerUnit.Count
|
|
642
|
+
// );
|
|
643
|
+
// const beforeGetQuotes = Date.now();
|
|
644
|
+
// quotePromises.push(
|
|
645
|
+
// this.v4Quoter
|
|
646
|
+
// .getQuotes(
|
|
647
|
+
// v4RoutesFromCache,
|
|
648
|
+
// amounts,
|
|
649
|
+
// percents,
|
|
650
|
+
// quoteToken,
|
|
651
|
+
// tradeType,
|
|
652
|
+
// routingConfig,
|
|
653
|
+
// undefined,
|
|
654
|
+
// v4GasModel
|
|
655
|
+
// )
|
|
656
|
+
// .then((result) => {
|
|
657
|
+
// metric.putMetric(
|
|
658
|
+
// `SwapRouteFromCache_V4_GetQuotes_Load`,
|
|
659
|
+
// Date.now() - beforeGetQuotes,
|
|
660
|
+
// MetricLoggerUnit.Milliseconds
|
|
661
|
+
// );
|
|
662
|
+
// return result;
|
|
663
|
+
// })
|
|
664
|
+
// );
|
|
665
|
+
// }
|
|
666
|
+
if (!fotInDirectSwap) {
|
|
667
|
+
if (v3Routes.length > 0) {
|
|
668
|
+
const v3RoutesFromCache = v3Routes.map((cachedRoute) => cachedRoute.route);
|
|
669
|
+
metric_1.metric.putMetric('SwapRouteFromCache_V3_GetQuotes_Request', 1, metric_1.MetricLoggerUnit.Count);
|
|
670
|
+
const beforeGetQuotes = Date.now();
|
|
671
|
+
quotePromises.push(this.v3Quoter
|
|
672
|
+
.getQuotes(v3RoutesFromCache, amounts, percents, quoteToken, tradeType, routingConfig, undefined, v3GasModel)
|
|
673
|
+
.then((result) => {
|
|
674
|
+
metric_1.metric.putMetric(`SwapRouteFromCache_V3_GetQuotes_Load`, Date.now() - beforeGetQuotes, metric_1.MetricLoggerUnit.Milliseconds);
|
|
675
|
+
return result;
|
|
676
|
+
}));
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (v2Routes.length > 0) {
|
|
680
|
+
const v2RoutesFromCache = v2Routes.map((cachedRoute) => cachedRoute.route);
|
|
681
|
+
metric_1.metric.putMetric('SwapRouteFromCache_V2_GetQuotes_Request', 1, metric_1.MetricLoggerUnit.Count);
|
|
682
|
+
const beforeGetQuotes = Date.now();
|
|
683
|
+
quotePromises.push(this.v2Quoter
|
|
684
|
+
.refreshRoutesThenGetQuotes(cachedRoutes.currencyIn.wrapped, cachedRoutes.currencyOut.wrapped, v2RoutesFromCache, amounts, percents, quoteToken, tradeType, routingConfig, gasPriceWei)
|
|
685
|
+
.then((result) => {
|
|
686
|
+
metric_1.metric.putMetric(`SwapRouteFromCache_V2_GetQuotes_Load`, Date.now() - beforeGetQuotes, metric_1.MetricLoggerUnit.Milliseconds);
|
|
687
|
+
return result;
|
|
688
|
+
}));
|
|
689
|
+
}
|
|
690
|
+
if (!fotInDirectSwap) {
|
|
691
|
+
if (mixedRoutes.length > 0) {
|
|
692
|
+
const mixedRoutesFromCache = mixedRoutes.map((cachedRoute) => cachedRoute.route);
|
|
693
|
+
metric_1.metric.putMetric('SwapRouteFromCache_Mixed_GetQuotes_Request', 1, metric_1.MetricLoggerUnit.Count);
|
|
694
|
+
const beforeGetQuotes = Date.now();
|
|
695
|
+
quotePromises.push(this.mixedQuoter
|
|
696
|
+
.getQuotes(mixedRoutesFromCache, amounts, percents, quoteToken, tradeType, routingConfig, undefined, mixedRouteGasModel)
|
|
697
|
+
.then((result) => {
|
|
698
|
+
metric_1.metric.putMetric(`SwapRouteFromCache_Mixed_GetQuotes_Load`, Date.now() - beforeGetQuotes, metric_1.MetricLoggerUnit.Milliseconds);
|
|
699
|
+
return result;
|
|
700
|
+
}));
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const getQuotesResults = await Promise.all(quotePromises);
|
|
704
|
+
const allRoutesWithValidQuotes = lodash_1.default.flatMap(getQuotesResults, (quoteResult) => quoteResult.routesWithValidQuotes);
|
|
705
|
+
return (0, best_swap_route_1.getBestSwapRoute)(amount, percents, allRoutesWithValidQuotes, tradeType, this.chainId, routingConfig, this.portionProvider, v2GasModel, v3GasModel,
|
|
706
|
+
// v4GasModel,
|
|
707
|
+
swapConfig, providerConfig);
|
|
708
|
+
}
|
|
709
|
+
async getSwapRouteFromChain(amount, tokenIn, tokenOut, protocols, quoteToken, tradeType, routingConfig, v3GasModel,
|
|
710
|
+
// v4GasModel: IGasModel<V4RouteWithValidQuote>,
|
|
711
|
+
mixedRouteGasModel, gasPriceWei, v2GasModel, swapConfig, providerConfig) {
|
|
712
|
+
var _a, _c, _d, _e, _f, _g, _h;
|
|
713
|
+
const tokenPairProperties = await this.tokenPropertiesProvider.getTokensProperties([tokenIn, tokenOut], providerConfig);
|
|
714
|
+
const sellTokenIsFot = (_d = (_c = (_a = tokenPairProperties[tokenIn.address.toLowerCase()]) === null || _a === void 0 ? void 0 : _a.tokenFeeResult) === null || _c === void 0 ? void 0 : _c.sellFeeBps) === null || _d === void 0 ? void 0 : _d.gt(0);
|
|
715
|
+
const buyTokenIsFot = (_g = (_f = (_e = tokenPairProperties[tokenOut.address.toLowerCase()]) === null || _e === void 0 ? void 0 : _e.tokenFeeResult) === null || _f === void 0 ? void 0 : _f.buyFeeBps) === null || _g === void 0 ? void 0 : _g.gt(0);
|
|
716
|
+
const fotInDirectSwap = sellTokenIsFot || buyTokenIsFot;
|
|
717
|
+
// Generate our distribution of amounts, i.e. fractions of the input amount.
|
|
718
|
+
// We will get quotes for fractions of the input amount for different routes, then
|
|
719
|
+
// combine to generate split routes.
|
|
720
|
+
const [percents, amounts] = this.getAmountDistribution(amount, routingConfig);
|
|
721
|
+
const noProtocolsSpecified = protocols.length === 0;
|
|
722
|
+
// const v4ProtocolSpecified = protocols.includes(Protocol.V4);
|
|
723
|
+
const v3ProtocolSpecified = protocols.includes(router_sdk_1.Protocol.V3);
|
|
724
|
+
const v2ProtocolSpecified = protocols.includes(router_sdk_1.Protocol.V2);
|
|
725
|
+
const v2SupportedInChain = (_h = this.v2Supported) === null || _h === void 0 ? void 0 : _h.includes(this.chainId);
|
|
726
|
+
// const v4SupportedInChain = this.v4Supported?.includes(this.chainId);
|
|
727
|
+
const shouldQueryMixedProtocol = protocols.includes(router_sdk_1.Protocol.MIXED) ||
|
|
728
|
+
(noProtocolsSpecified && v2SupportedInChain); /* && v4SupportedInChain */
|
|
729
|
+
const mixedProtocolAllowed = [
|
|
730
|
+
// ChainId.MAINNET,
|
|
731
|
+
// ChainId.SEPOLIA,
|
|
732
|
+
// ChainId.GOERLI,
|
|
733
|
+
sdk_core_1.ChainId.CHILIZ,
|
|
734
|
+
sdk_core_1.ChainId.SPICY,
|
|
735
|
+
].includes(this.chainId) && tradeType === sdk_core_1.TradeType.EXACT_INPUT;
|
|
736
|
+
const beforeGetCandidates = Date.now();
|
|
737
|
+
// let v4CandidatePoolsPromise: Promise<V4CandidatePools | undefined> =
|
|
738
|
+
// Promise.resolve(undefined);
|
|
739
|
+
// we are explicitly requiring people to specify v4 for now
|
|
740
|
+
// if (
|
|
741
|
+
// v4SupportedInChain &&
|
|
742
|
+
// (v4ProtocolSpecified ||
|
|
743
|
+
// noProtocolsSpecified ||
|
|
744
|
+
// (shouldQueryMixedProtocol && mixedProtocolAllowed))
|
|
745
|
+
// ) {
|
|
746
|
+
// // if (v4ProtocolSpecified || noProtocolsSpecified) {
|
|
747
|
+
// v4CandidatePoolsPromise = getV4CandidatePools({
|
|
748
|
+
// currencyIn: tokenIn,
|
|
749
|
+
// currencyOut: tokenOut,
|
|
750
|
+
// tokenProvider: this.tokenProvider,
|
|
751
|
+
// blockedTokenListProvider: this.blockedTokenListProvider,
|
|
752
|
+
// poolProvider: this.v4PoolProvider,
|
|
753
|
+
// routeType: tradeType,
|
|
754
|
+
// subgraphProvider: this.v4SubgraphProvider,
|
|
755
|
+
// routingConfig,
|
|
756
|
+
// chainId: this.chainId,
|
|
757
|
+
// }).then((candidatePools) => {
|
|
758
|
+
// metric.putMetric(
|
|
759
|
+
// 'GetV4CandidatePools',
|
|
760
|
+
// Date.now() - beforeGetCandidates,
|
|
761
|
+
// MetricLoggerUnit.Milliseconds
|
|
762
|
+
// );
|
|
763
|
+
// return candidatePools;
|
|
764
|
+
// });
|
|
765
|
+
// }
|
|
766
|
+
let v3CandidatePoolsPromise = Promise.resolve(undefined);
|
|
767
|
+
if (!fotInDirectSwap) {
|
|
768
|
+
if (v3ProtocolSpecified ||
|
|
769
|
+
noProtocolsSpecified ||
|
|
770
|
+
(shouldQueryMixedProtocol && mixedProtocolAllowed)) {
|
|
771
|
+
v3CandidatePoolsPromise = (0, get_candidate_pools_1.getV3CandidatePools)({
|
|
772
|
+
tokenIn,
|
|
773
|
+
tokenOut,
|
|
774
|
+
tokenProvider: this.tokenProvider,
|
|
775
|
+
blockedTokenListProvider: this.blockedTokenListProvider,
|
|
776
|
+
poolProvider: this.v3PoolProvider,
|
|
777
|
+
routeType: tradeType,
|
|
778
|
+
subgraphProvider: this.v3SubgraphProvider,
|
|
779
|
+
routingConfig,
|
|
780
|
+
chainId: this.chainId,
|
|
781
|
+
}).then((candidatePools) => {
|
|
782
|
+
metric_1.metric.putMetric('GetV3CandidatePools', Date.now() - beforeGetCandidates, metric_1.MetricLoggerUnit.Milliseconds);
|
|
783
|
+
return candidatePools;
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
let v2CandidatePoolsPromise = Promise.resolve(undefined);
|
|
788
|
+
if ((v2SupportedInChain && (v2ProtocolSpecified || noProtocolsSpecified)) ||
|
|
789
|
+
(shouldQueryMixedProtocol && mixedProtocolAllowed)) {
|
|
790
|
+
// Fetch all the pools that we will consider routing via. There are thousands
|
|
791
|
+
// of pools, so we filter them to a set of candidate pools that we expect will
|
|
792
|
+
// result in good prices.
|
|
793
|
+
v2CandidatePoolsPromise = (0, get_candidate_pools_1.getV2CandidatePools)({
|
|
794
|
+
tokenIn,
|
|
795
|
+
tokenOut,
|
|
796
|
+
tokenProvider: this.tokenProvider,
|
|
797
|
+
blockedTokenListProvider: this.blockedTokenListProvider,
|
|
798
|
+
poolProvider: this.v2PoolProvider,
|
|
799
|
+
routeType: tradeType,
|
|
800
|
+
subgraphProvider: this.v2SubgraphProvider,
|
|
801
|
+
routingConfig,
|
|
802
|
+
chainId: this.chainId,
|
|
803
|
+
}).then((candidatePools) => {
|
|
804
|
+
metric_1.metric.putMetric('GetV2CandidatePools', Date.now() - beforeGetCandidates, metric_1.MetricLoggerUnit.Milliseconds);
|
|
805
|
+
return candidatePools;
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
const quotePromises = [];
|
|
809
|
+
// for v4, for now we explicitly require people to specify
|
|
810
|
+
// if (v4SupportedInChain && v4ProtocolSpecified) {
|
|
811
|
+
// log.info({ protocols, tradeType }, 'Routing across V4');
|
|
812
|
+
// metric.putMetric(
|
|
813
|
+
// 'SwapRouteFromChain_V4_GetRoutesThenQuotes_Request',
|
|
814
|
+
// 1,
|
|
815
|
+
// MetricLoggerUnit.Count
|
|
816
|
+
// );
|
|
817
|
+
// const beforeGetRoutesThenQuotes = Date.now();
|
|
818
|
+
// quotePromises.push(
|
|
819
|
+
// v4CandidatePoolsPromise.then((v4CandidatePools) =>
|
|
820
|
+
// this.v4Quoter
|
|
821
|
+
// .getRoutesThenQuotes(
|
|
822
|
+
// tokenIn,
|
|
823
|
+
// tokenOut,
|
|
824
|
+
// amount,
|
|
825
|
+
// amounts,
|
|
826
|
+
// percents,
|
|
827
|
+
// quoteToken,
|
|
828
|
+
// v4CandidatePools!,
|
|
829
|
+
// tradeType,
|
|
830
|
+
// routingConfig,
|
|
831
|
+
// v3GasModel
|
|
832
|
+
// )
|
|
833
|
+
// .then((result) => {
|
|
834
|
+
// metric.putMetric(
|
|
835
|
+
// `SwapRouteFromChain_V4_GetRoutesThenQuotes_Load`,
|
|
836
|
+
// Date.now() - beforeGetRoutesThenQuotes,
|
|
837
|
+
// MetricLoggerUnit.Milliseconds
|
|
838
|
+
// );
|
|
839
|
+
// return result;
|
|
840
|
+
// })
|
|
841
|
+
// )
|
|
842
|
+
// );
|
|
843
|
+
// }
|
|
844
|
+
if (!fotInDirectSwap) {
|
|
845
|
+
// Maybe Quote V3 - if V3 is specified, or no protocol is specified
|
|
846
|
+
if (v3ProtocolSpecified || noProtocolsSpecified) {
|
|
847
|
+
log_1.log.info({ protocols, tradeType }, 'Routing across V3');
|
|
848
|
+
metric_1.metric.putMetric('SwapRouteFromChain_V3_GetRoutesThenQuotes_Request', 1, metric_1.MetricLoggerUnit.Count);
|
|
849
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
850
|
+
quotePromises.push(v3CandidatePoolsPromise.then((v3CandidatePools) => this.v3Quoter
|
|
851
|
+
.getRoutesThenQuotes(tokenIn, tokenOut, amount, amounts, percents, quoteToken, v3CandidatePools, tradeType, routingConfig, v3GasModel)
|
|
852
|
+
.then((result) => {
|
|
853
|
+
metric_1.metric.putMetric(`SwapRouteFromChain_V3_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, metric_1.MetricLoggerUnit.Milliseconds);
|
|
854
|
+
return result;
|
|
855
|
+
})));
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
// Maybe Quote V2 - if V2 is specified, or no protocol is specified AND v2 is supported in this chain
|
|
859
|
+
if (v2SupportedInChain && (v2ProtocolSpecified || noProtocolsSpecified)) {
|
|
860
|
+
log_1.log.info({ protocols, tradeType }, 'Routing across V2');
|
|
861
|
+
metric_1.metric.putMetric('SwapRouteFromChain_V2_GetRoutesThenQuotes_Request', 1, metric_1.MetricLoggerUnit.Count);
|
|
862
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
863
|
+
quotePromises.push(v2CandidatePoolsPromise.then((v2CandidatePools) => this.v2Quoter
|
|
864
|
+
.getRoutesThenQuotes(tokenIn, tokenOut, amount, amounts, percents, quoteToken, v2CandidatePools, tradeType, routingConfig, v2GasModel, gasPriceWei)
|
|
865
|
+
.then((result) => {
|
|
866
|
+
metric_1.metric.putMetric(`SwapRouteFromChain_V2_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, metric_1.MetricLoggerUnit.Milliseconds);
|
|
867
|
+
return result;
|
|
868
|
+
})));
|
|
869
|
+
}
|
|
870
|
+
if (!fotInDirectSwap) {
|
|
871
|
+
// Maybe Quote mixed routes
|
|
872
|
+
// if MixedProtocol is specified or no protocol is specified and v2 is supported AND tradeType is ExactIn
|
|
873
|
+
// AND is Mainnet or Gorli
|
|
874
|
+
if (shouldQueryMixedProtocol && mixedProtocolAllowed) {
|
|
875
|
+
log_1.log.info({ protocols, tradeType }, 'Routing across MixedRoutes');
|
|
876
|
+
metric_1.metric.putMetric('SwapRouteFromChain_Mixed_GetRoutesThenQuotes_Request', 1, metric_1.MetricLoggerUnit.Count);
|
|
877
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
878
|
+
quotePromises.push(Promise.all([
|
|
879
|
+
// v4CandidatePoolsPromise,
|
|
880
|
+
v3CandidatePoolsPromise,
|
|
881
|
+
v2CandidatePoolsPromise,
|
|
882
|
+
]).then(async ([v3CandidatePools, v2CandidatePools]) => {
|
|
883
|
+
const crossLiquidityPools = await (0, get_candidate_pools_1.getMixedCrossLiquidityCandidatePools)({
|
|
884
|
+
tokenIn,
|
|
885
|
+
tokenOut,
|
|
886
|
+
blockNumber: routingConfig.blockNumber,
|
|
887
|
+
v2SubgraphProvider: this.v2SubgraphProvider,
|
|
888
|
+
v3SubgraphProvider: this.v3SubgraphProvider,
|
|
889
|
+
v2Candidates: v2CandidatePools,
|
|
890
|
+
v3Candidates: v3CandidatePools,
|
|
891
|
+
// v4Candidates: undefined,
|
|
892
|
+
});
|
|
893
|
+
return this.mixedQuoter
|
|
894
|
+
.getRoutesThenQuotes(tokenIn, tokenOut, amount, amounts, percents, quoteToken, [
|
|
895
|
+
// v4CandidatePools!,
|
|
896
|
+
v3CandidatePools,
|
|
897
|
+
v2CandidatePools,
|
|
898
|
+
crossLiquidityPools,
|
|
899
|
+
], tradeType, routingConfig, mixedRouteGasModel)
|
|
900
|
+
.then((result) => {
|
|
901
|
+
metric_1.metric.putMetric(`SwapRouteFromChain_Mixed_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, metric_1.MetricLoggerUnit.Milliseconds);
|
|
902
|
+
return result;
|
|
903
|
+
});
|
|
904
|
+
}));
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
const getQuotesResults = await Promise.all(quotePromises);
|
|
908
|
+
const allRoutesWithValidQuotes = [];
|
|
909
|
+
const allCandidatePools = [];
|
|
910
|
+
getQuotesResults.forEach((getQuoteResult) => {
|
|
911
|
+
if (!getQuoteResult) {
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
allRoutesWithValidQuotes.push(...getQuoteResult.routesWithValidQuotes);
|
|
915
|
+
if (getQuoteResult.candidatePools) {
|
|
916
|
+
allCandidatePools.push(getQuoteResult.candidatePools);
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
if (allRoutesWithValidQuotes.length === 0) {
|
|
920
|
+
log_1.log.info({ allRoutesWithValidQuotes }, 'Received no valid quotes');
|
|
921
|
+
return null;
|
|
922
|
+
}
|
|
923
|
+
// Given all the quotes for all the amounts for all the routes, find the best combination.
|
|
924
|
+
const bestSwapRoute = await (0, best_swap_route_1.getBestSwapRoute)(amount, percents, allRoutesWithValidQuotes, tradeType, this.chainId, routingConfig, this.portionProvider, v2GasModel, v3GasModel,
|
|
925
|
+
// v4GasModel,
|
|
926
|
+
swapConfig, providerConfig);
|
|
927
|
+
if (bestSwapRoute) {
|
|
928
|
+
this.emitPoolSelectionMetrics(bestSwapRoute, allCandidatePools);
|
|
929
|
+
}
|
|
930
|
+
return bestSwapRoute;
|
|
931
|
+
}
|
|
932
|
+
tradeTypeStr(tradeType) {
|
|
933
|
+
return tradeType === sdk_core_1.TradeType.EXACT_INPUT ? 'ExactIn' : 'ExactOut';
|
|
934
|
+
}
|
|
935
|
+
tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType) {
|
|
936
|
+
return `${tokenIn.symbol}/${tokenOut.symbol}/${this.tradeTypeStr(tradeType)}/${this.chainId}`;
|
|
937
|
+
}
|
|
938
|
+
determineCurrencyInOutFromTradeType(tradeType, amount, quoteCurrency) {
|
|
939
|
+
if (tradeType === sdk_core_1.TradeType.EXACT_INPUT) {
|
|
940
|
+
return {
|
|
941
|
+
currencyIn: amount.currency,
|
|
942
|
+
currencyOut: quoteCurrency,
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
else {
|
|
946
|
+
return {
|
|
947
|
+
currencyIn: quoteCurrency,
|
|
948
|
+
currencyOut: amount.currency,
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
async getGasPriceWei(latestBlockNumber, requestBlockNumber) {
|
|
953
|
+
// Track how long it takes to resolve this async call.
|
|
954
|
+
const beforeGasTimestamp = Date.now();
|
|
955
|
+
// Get an estimate of the gas price to use when estimating gas cost of different routes.
|
|
956
|
+
const { gasPriceWei } = await this.gasPriceProvider.getGasPrice(latestBlockNumber, requestBlockNumber);
|
|
957
|
+
metric_1.metric.putMetric('GasPriceLoad', Date.now() - beforeGasTimestamp, metric_1.MetricLoggerUnit.Milliseconds);
|
|
958
|
+
return gasPriceWei;
|
|
959
|
+
}
|
|
960
|
+
async getGasModels(gasPriceWei, amountToken, quoteToken, providerConfig) {
|
|
961
|
+
var _a;
|
|
962
|
+
const beforeGasModel = Date.now();
|
|
963
|
+
const usdPoolPromise = (0, gas_factory_helpers_1.getHighestLiquidityV3USDPool)(this.chainId, this.v3PoolProvider, providerConfig);
|
|
964
|
+
const nativeCurrency = util_1.WRAPPED_NATIVE_CURRENCY[this.chainId];
|
|
965
|
+
const nativeAndQuoteTokenV3PoolPromise = !quoteToken.equals(nativeCurrency)
|
|
966
|
+
? (0, gas_factory_helpers_1.getHighestLiquidityV3NativePool)(quoteToken, this.v3PoolProvider, providerConfig)
|
|
967
|
+
: Promise.resolve(null);
|
|
968
|
+
const nativeAndAmountTokenV3PoolPromise = !amountToken.equals(nativeCurrency)
|
|
969
|
+
? (0, gas_factory_helpers_1.getHighestLiquidityV3NativePool)(amountToken, this.v3PoolProvider, providerConfig)
|
|
970
|
+
: Promise.resolve(null);
|
|
971
|
+
// If a specific gas token is specified in the provider config
|
|
972
|
+
// fetch the highest liq V3 pool with it and the native currency
|
|
973
|
+
const nativeAndSpecifiedGasTokenV3PoolPromise = (providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.gasToken) &&
|
|
974
|
+
!(providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.gasToken.equals(nativeCurrency))
|
|
975
|
+
? (0, gas_factory_helpers_1.getHighestLiquidityV3NativePool)(providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.gasToken, this.v3PoolProvider, providerConfig)
|
|
976
|
+
: Promise.resolve(null);
|
|
977
|
+
const [usdPool, nativeAndQuoteTokenV3Pool, nativeAndAmountTokenV3Pool, nativeAndSpecifiedGasTokenV3Pool,] = await Promise.all([
|
|
978
|
+
usdPoolPromise,
|
|
979
|
+
nativeAndQuoteTokenV3PoolPromise,
|
|
980
|
+
nativeAndAmountTokenV3PoolPromise,
|
|
981
|
+
nativeAndSpecifiedGasTokenV3PoolPromise,
|
|
982
|
+
]);
|
|
983
|
+
const pools = {
|
|
984
|
+
usdPool: usdPool,
|
|
985
|
+
nativeAndQuoteTokenV3Pool: nativeAndQuoteTokenV3Pool,
|
|
986
|
+
nativeAndAmountTokenV3Pool: nativeAndAmountTokenV3Pool,
|
|
987
|
+
nativeAndSpecifiedGasTokenV3Pool: nativeAndSpecifiedGasTokenV3Pool,
|
|
988
|
+
};
|
|
989
|
+
const v2GasModelPromise = ((_a = this.v2Supported) === null || _a === void 0 ? void 0 : _a.includes(this.chainId))
|
|
990
|
+
? this.v2GasModelFactory
|
|
991
|
+
.buildGasModel({
|
|
992
|
+
chainId: this.chainId,
|
|
993
|
+
gasPriceWei,
|
|
994
|
+
poolProvider: this.v2PoolProvider,
|
|
995
|
+
token: quoteToken,
|
|
996
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
997
|
+
providerConfig: providerConfig,
|
|
998
|
+
})
|
|
999
|
+
.catch((_) => undefined) // If v2 model throws uncaught exception, we return undefined v2 gas model, so there's a chance v3 route can go through
|
|
1000
|
+
: Promise.resolve(undefined);
|
|
1001
|
+
const v3GasModelPromise = this.v3GasModelFactory.buildGasModel({
|
|
1002
|
+
chainId: this.chainId,
|
|
1003
|
+
gasPriceWei,
|
|
1004
|
+
pools,
|
|
1005
|
+
amountToken,
|
|
1006
|
+
quoteToken,
|
|
1007
|
+
v2poolProvider: this.v2PoolProvider,
|
|
1008
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
1009
|
+
providerConfig: providerConfig,
|
|
1010
|
+
});
|
|
1011
|
+
// const v4GasModelPromise = this.v4GasModelFactory.buildGasModel({
|
|
1012
|
+
// chainId: this.chainId,
|
|
1013
|
+
// gasPriceWei,
|
|
1014
|
+
// pools,
|
|
1015
|
+
// amountToken,
|
|
1016
|
+
// quoteToken,
|
|
1017
|
+
// v2poolProvider: this.v2PoolProvider,
|
|
1018
|
+
// l2GasDataProvider: this.l2GasDataProvider,
|
|
1019
|
+
// providerConfig: providerConfig,
|
|
1020
|
+
// });
|
|
1021
|
+
const mixedRouteGasModelPromise = this.mixedRouteGasModelFactory.buildGasModel({
|
|
1022
|
+
chainId: this.chainId,
|
|
1023
|
+
gasPriceWei,
|
|
1024
|
+
pools,
|
|
1025
|
+
amountToken,
|
|
1026
|
+
quoteToken,
|
|
1027
|
+
v2poolProvider: this.v2PoolProvider,
|
|
1028
|
+
providerConfig: providerConfig,
|
|
1029
|
+
});
|
|
1030
|
+
const [v2GasModel, v3GasModel /* , V4GasModel */, mixedRouteGasModel] = await Promise.all([
|
|
1031
|
+
v2GasModelPromise,
|
|
1032
|
+
v3GasModelPromise,
|
|
1033
|
+
// v4GasModelPromise,
|
|
1034
|
+
mixedRouteGasModelPromise,
|
|
1035
|
+
]);
|
|
1036
|
+
metric_1.metric.putMetric('GasModelCreation', Date.now() - beforeGasModel, metric_1.MetricLoggerUnit.Milliseconds);
|
|
1037
|
+
return {
|
|
1038
|
+
v2GasModel: v2GasModel,
|
|
1039
|
+
v3GasModel: v3GasModel,
|
|
1040
|
+
// v4GasModel: V4GasModel,
|
|
1041
|
+
mixedRouteGasModel: mixedRouteGasModel,
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
// Note multiplications here can result in a loss of precision in the amounts (e.g. taking 50% of 101)
|
|
1045
|
+
// This is reconcilled at the end of the algorithm by adding any lost precision to one of
|
|
1046
|
+
// the splits in the route.
|
|
1047
|
+
getAmountDistribution(amount, routingConfig) {
|
|
1048
|
+
const { distributionPercent } = routingConfig;
|
|
1049
|
+
const percents = [];
|
|
1050
|
+
const amounts = [];
|
|
1051
|
+
for (let i = 1; i <= 100 / distributionPercent; i++) {
|
|
1052
|
+
percents.push(i * distributionPercent);
|
|
1053
|
+
amounts.push(amount.multiply(new sdk_core_1.Fraction(i * distributionPercent, 100)));
|
|
1054
|
+
}
|
|
1055
|
+
return [percents, amounts];
|
|
1056
|
+
}
|
|
1057
|
+
async buildSwapAndAddMethodParameters(trade, swapAndAddOptions, swapAndAddParameters) {
|
|
1058
|
+
const { swapOptions: { recipient, slippageTolerance, deadline, inputTokenPermit }, addLiquidityOptions: addLiquidityConfig, } = swapAndAddOptions;
|
|
1059
|
+
const preLiquidityPosition = swapAndAddParameters.preLiquidityPosition;
|
|
1060
|
+
const finalBalanceTokenIn = swapAndAddParameters.initialBalanceTokenIn.subtract(trade.inputAmount);
|
|
1061
|
+
const finalBalanceTokenOut = swapAndAddParameters.initialBalanceTokenOut.add(trade.outputAmount);
|
|
1062
|
+
const approvalTypes = await this.swapRouterProvider.getApprovalType(finalBalanceTokenIn, finalBalanceTokenOut);
|
|
1063
|
+
const zeroForOne = finalBalanceTokenIn.currency.wrapped.sortsBefore(finalBalanceTokenOut.currency.wrapped);
|
|
1064
|
+
return Object.assign(Object.assign({}, router_sdk_1.SwapRouter.swapAndAddCallParameters(trade, {
|
|
1065
|
+
recipient,
|
|
1066
|
+
slippageTolerance,
|
|
1067
|
+
deadlineOrPreviousBlockhash: deadline,
|
|
1068
|
+
inputTokenPermit,
|
|
1069
|
+
}, v3_sdk_1.Position.fromAmounts({
|
|
1070
|
+
pool: preLiquidityPosition.pool,
|
|
1071
|
+
tickLower: preLiquidityPosition.tickLower,
|
|
1072
|
+
tickUpper: preLiquidityPosition.tickUpper,
|
|
1073
|
+
amount0: zeroForOne
|
|
1074
|
+
? finalBalanceTokenIn.quotient.toString()
|
|
1075
|
+
: finalBalanceTokenOut.quotient.toString(),
|
|
1076
|
+
amount1: zeroForOne
|
|
1077
|
+
? finalBalanceTokenOut.quotient.toString()
|
|
1078
|
+
: finalBalanceTokenIn.quotient.toString(),
|
|
1079
|
+
useFullPrecision: false,
|
|
1080
|
+
}), addLiquidityConfig, approvalTypes.approvalTokenIn, approvalTypes.approvalTokenOut)), { to: (0, util_1.SWAP_ROUTER_02_ADDRESSES)(this.chainId) });
|
|
1081
|
+
}
|
|
1082
|
+
emitPoolSelectionMetrics(swapRouteRaw, allPoolsBySelection) {
|
|
1083
|
+
const poolAddressesUsed = new Set();
|
|
1084
|
+
const { routes: routeAmounts } = swapRouteRaw;
|
|
1085
|
+
(0, lodash_1.default)(routeAmounts)
|
|
1086
|
+
.flatMap((routeAmount) => {
|
|
1087
|
+
const { poolIdentifiers: poolAddresses } = routeAmount;
|
|
1088
|
+
return poolAddresses;
|
|
1089
|
+
})
|
|
1090
|
+
.forEach((address) => {
|
|
1091
|
+
poolAddressesUsed.add(address.toLowerCase());
|
|
1092
|
+
});
|
|
1093
|
+
for (const poolsBySelection of allPoolsBySelection) {
|
|
1094
|
+
const { protocol } = poolsBySelection;
|
|
1095
|
+
lodash_1.default.forIn(poolsBySelection.selections, (pools, topNSelection) => {
|
|
1096
|
+
const topNUsed = lodash_1.default.findLastIndex(pools, (pool) => poolAddressesUsed.has(pool.id.toLowerCase())) + 1;
|
|
1097
|
+
metric_1.metric.putMetric(lodash_1.default.capitalize(`${protocol}${topNSelection}`), topNUsed, metric_1.MetricLoggerUnit.Count);
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
let hasV3Route = false;
|
|
1101
|
+
let hasV2Route = false;
|
|
1102
|
+
let hasMixedRoute = false;
|
|
1103
|
+
for (const routeAmount of routeAmounts) {
|
|
1104
|
+
if (routeAmount.protocol === router_sdk_1.Protocol.V3) {
|
|
1105
|
+
hasV3Route = true;
|
|
1106
|
+
}
|
|
1107
|
+
if (routeAmount.protocol === router_sdk_1.Protocol.V2) {
|
|
1108
|
+
hasV2Route = true;
|
|
1109
|
+
}
|
|
1110
|
+
if (routeAmount.protocol === router_sdk_1.Protocol.MIXED) {
|
|
1111
|
+
hasMixedRoute = true;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (hasMixedRoute && (hasV3Route || hasV2Route)) {
|
|
1115
|
+
if (hasV3Route && hasV2Route) {
|
|
1116
|
+
metric_1.metric.putMetric(`MixedAndV3AndV2SplitRoute`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1117
|
+
metric_1.metric.putMetric(`MixedAndV3AndV2SplitRouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1118
|
+
}
|
|
1119
|
+
else if (hasV3Route) {
|
|
1120
|
+
metric_1.metric.putMetric(`MixedAndV3SplitRoute`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1121
|
+
metric_1.metric.putMetric(`MixedAndV3SplitRouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1122
|
+
}
|
|
1123
|
+
else if (hasV2Route) {
|
|
1124
|
+
metric_1.metric.putMetric(`MixedAndV2SplitRoute`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1125
|
+
metric_1.metric.putMetric(`MixedAndV2SplitRouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
else if (hasV3Route && hasV2Route) {
|
|
1129
|
+
metric_1.metric.putMetric(`V3AndV2SplitRoute`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1130
|
+
metric_1.metric.putMetric(`V3AndV2SplitRouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1131
|
+
}
|
|
1132
|
+
else if (hasMixedRoute) {
|
|
1133
|
+
if (routeAmounts.length > 1) {
|
|
1134
|
+
metric_1.metric.putMetric(`MixedSplitRoute`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1135
|
+
metric_1.metric.putMetric(`MixedSplitRouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1136
|
+
}
|
|
1137
|
+
else {
|
|
1138
|
+
metric_1.metric.putMetric(`MixedRoute`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1139
|
+
metric_1.metric.putMetric(`MixedRouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
else if (hasV3Route) {
|
|
1143
|
+
if (routeAmounts.length > 1) {
|
|
1144
|
+
metric_1.metric.putMetric(`V3SplitRoute`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1145
|
+
metric_1.metric.putMetric(`V3SplitRouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1146
|
+
}
|
|
1147
|
+
else {
|
|
1148
|
+
metric_1.metric.putMetric(`V3Route`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1149
|
+
metric_1.metric.putMetric(`V3RouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
else if (hasV2Route) {
|
|
1153
|
+
if (routeAmounts.length > 1) {
|
|
1154
|
+
metric_1.metric.putMetric(`V2SplitRoute`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1155
|
+
metric_1.metric.putMetric(`V2SplitRouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1156
|
+
}
|
|
1157
|
+
else {
|
|
1158
|
+
metric_1.metric.putMetric(`V2Route`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1159
|
+
metric_1.metric.putMetric(`V2RouteForChain${this.chainId}`, 1, metric_1.MetricLoggerUnit.Count);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
calculateOptimalRatio(position, sqrtRatioX96, zeroForOne) {
|
|
1164
|
+
const upperSqrtRatioX96 = v3_sdk_1.TickMath.getSqrtRatioAtTick(position.tickUpper);
|
|
1165
|
+
const lowerSqrtRatioX96 = v3_sdk_1.TickMath.getSqrtRatioAtTick(position.tickLower);
|
|
1166
|
+
// returns Fraction(0, 1) for any out of range position regardless of zeroForOne. Implication: function
|
|
1167
|
+
// cannot be used to determine the trading direction of out of range positions.
|
|
1168
|
+
if (jsbi_1.default.greaterThan(sqrtRatioX96, upperSqrtRatioX96) ||
|
|
1169
|
+
jsbi_1.default.lessThan(sqrtRatioX96, lowerSqrtRatioX96)) {
|
|
1170
|
+
return new sdk_core_1.Fraction(0, 1);
|
|
1171
|
+
}
|
|
1172
|
+
const precision = jsbi_1.default.BigInt('1' + '0'.repeat(18));
|
|
1173
|
+
let optimalRatio = new sdk_core_1.Fraction(v3_sdk_1.SqrtPriceMath.getAmount0Delta(sqrtRatioX96, upperSqrtRatioX96, precision, true), v3_sdk_1.SqrtPriceMath.getAmount1Delta(sqrtRatioX96, lowerSqrtRatioX96, precision, true));
|
|
1174
|
+
if (!zeroForOne)
|
|
1175
|
+
optimalRatio = optimalRatio.invert();
|
|
1176
|
+
return optimalRatio;
|
|
1177
|
+
}
|
|
1178
|
+
async userHasSufficientBalance(fromAddress, tradeType, amount, quote) {
|
|
1179
|
+
try {
|
|
1180
|
+
const neededBalance = tradeType === sdk_core_1.TradeType.EXACT_INPUT ? amount : quote;
|
|
1181
|
+
let balance;
|
|
1182
|
+
if (neededBalance.currency.isNative) {
|
|
1183
|
+
balance = await this.provider.getBalance(fromAddress);
|
|
1184
|
+
}
|
|
1185
|
+
else {
|
|
1186
|
+
const tokenContract = Erc20__factory_1.Erc20__factory.connect(neededBalance.currency.address, this.provider);
|
|
1187
|
+
balance = await tokenContract.balanceOf(fromAddress);
|
|
1188
|
+
}
|
|
1189
|
+
return balance.gte(bignumber_1.BigNumber.from(neededBalance.quotient.toString()));
|
|
1190
|
+
}
|
|
1191
|
+
catch (e) {
|
|
1192
|
+
log_1.log.error(e, 'Error while checking user balance');
|
|
1193
|
+
return false;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
absoluteValue(fraction) {
|
|
1197
|
+
const numeratorAbs = jsbi_1.default.lessThan(fraction.numerator, jsbi_1.default.BigInt(0))
|
|
1198
|
+
? jsbi_1.default.unaryMinus(fraction.numerator)
|
|
1199
|
+
: fraction.numerator;
|
|
1200
|
+
const denominatorAbs = jsbi_1.default.lessThan(fraction.denominator, jsbi_1.default.BigInt(0))
|
|
1201
|
+
? jsbi_1.default.unaryMinus(fraction.denominator)
|
|
1202
|
+
: fraction.denominator;
|
|
1203
|
+
return new sdk_core_1.Fraction(numeratorAbs, denominatorAbs);
|
|
1204
|
+
}
|
|
1205
|
+
getBlockNumberPromise() {
|
|
1206
|
+
return (0, async_retry_1.default)(async (_b, attempt) => {
|
|
1207
|
+
if (attempt > 1) {
|
|
1208
|
+
log_1.log.info(`Get block number attempt ${attempt}`);
|
|
1209
|
+
}
|
|
1210
|
+
return this.provider.getBlockNumber();
|
|
1211
|
+
}, {
|
|
1212
|
+
retries: 2,
|
|
1213
|
+
minTimeout: 100,
|
|
1214
|
+
maxTimeout: 1000,
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
exports.AlphaRouter = AlphaRouter;
|
|
1219
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxwaGEtcm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3JvdXRlcnMvYWxwaGEtcm91dGVyL2FscGhhLXJvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSx3REFBcUQ7QUFDckQsd0RBQXlFO0FBQ3pFLDBEQUE4RTtBQUM5RSxzREFNaUM7QUFDakMsOEVBQTZFO0FBQzdFLGtEQUFnRjtBQUNoRixxRkFBNkQ7QUFFN0QsOERBQWdDO0FBQ2hDLGdEQUF3QjtBQUN4QixvREFBdUI7QUFDdkIsNERBQW1DO0FBRW5DLCtDQWtDeUI7QUFDekIsNkZBR3FEO0FBS3JELHVFQUcwQztBQUUxQyx5RUFBMkU7QUFDM0UsbUVBQStFO0FBQy9FLHVGQUdrRDtBQUNsRCxvRUFHMEM7QUFDMUMsNEVBSThDO0FBQzlDLG9FQUcwQztBQUUxQyxvRkFBb0Y7QUFDcEYsV0FBVztBQUNYLHFCQUFxQjtBQUNyQixvQkFBb0I7QUFDcEIsNkNBQTZDO0FBQzdDLCtFQUE0RTtBQUM1RSxxQ0FPb0I7QUFDcEIsZ0RBQW9EO0FBQ3BELDhDQUkyQjtBQUMzQix3RUFHd0M7QUFDeEMsd0NBQXFDO0FBQ3JDLGtFQUdxQztBQUNyQyw4Q0FBNkQ7QUFDN0Qsd0ZBTWdEO0FBQ2hELHNFQUFtRTtBQUNuRSxzQ0FlbUI7QUFFbkIscUNBR2tCO0FBT2xCLGlFQUE4RTtBQUM5RSxxRkFBK0U7QUFDL0UseUVBU3lDO0FBQ3pDLHNEQUF5RDtBQVN6RCw2R0FBNkc7QUFDN0csbUZBQW9GO0FBQ3BGLG1GQUFvRjtBQUNwRix1RkFBdUY7QUFDdkYsdUNBQTZFO0FBMkk3RSxNQUFhLG1CQUF1QixTQUFRLEdBQWM7SUFDL0MsR0FBRyxDQUFDLEdBQVcsRUFBRSxLQUFRO1FBQ2hDLE9BQU8sS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDN0MsQ0FBQztDQUNGO0FBSkQsa0RB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
|