@ring-protocol/smart-order-router 0.5.0
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 +307 -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 +77 -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 +111 -0
- package/build/main/providers/caching/route/route-caching-provider.js +86 -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 +186 -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 +234 -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 +21 -0
- package/build/main/providers/eth-estimate-gas-provider.js +91 -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/fewV2/ring-caching-pool-provider.d.ts +33 -0
- package/build/main/providers/fewV2/ring-caching-pool-provider.js +89 -0
- package/build/main/providers/fewV2/ring-caching-subgraph-provider.d.ts +19 -0
- package/build/main/providers/fewV2/ring-caching-subgraph-provider.js +24 -0
- package/build/main/providers/fewV2/ring-pool-provider.d.ts +63 -0
- package/build/main/providers/fewV2/ring-pool-provider.js +148 -0
- package/build/main/providers/fewV2/ring-quote-provider.d.ts +34 -0
- package/build/main/providers/fewV2/ring-quote-provider.js +90 -0
- package/build/main/providers/fewV2/ring-static-subgraph-provider.d.ts +24 -0
- package/build/main/providers/fewV2/ring-static-subgraph-provider.js +284 -0
- package/build/main/providers/fewV2/ring-subgraph-provider-with-fallback.d.ts +16 -0
- package/build/main/providers/fewV2/ring-subgraph-provider-with-fallback.js +23 -0
- package/build/main/providers/fewV2/ring-subgraph-provider.d.ts +52 -0
- package/build/main/providers/fewV2/ring-subgraph-provider.js +183 -0
- package/build/main/providers/fewV2/ring-uri-subgraph-provider.d.ts +4 -0
- package/build/main/providers/fewV2/ring-uri-subgraph-provider.js +8 -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 +56 -0
- package/build/main/providers/index.js +73 -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-ringswap-provider.d.ts +35 -0
- package/build/main/providers/multicall-ringswap-provider.js +164 -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 +37 -0
- package/build/main/providers/on-chain-quote-provider.d.ts +260 -0
- package/build/main/providers/on-chain-quote-provider.js +702 -0
- package/build/main/providers/pool-provider.d.ts +45 -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 +46 -0
- package/build/main/providers/simulation-provider.js +138 -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 +56 -0
- package/build/main/providers/subgraph-provider.js +287 -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/tenderly-simulation-provider.d.ts +63 -0
- package/build/main/providers/tenderly-simulation-provider.js +446 -0
- package/build/main/providers/token-fee-fetcher.d.ts +31 -0
- package/build/main/providers/token-fee-fetcher.js +114 -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 +167 -0
- package/build/main/providers/token-provider.js +414 -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 +21 -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 +148 -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 +183 -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 +52 -0
- package/build/main/providers/v2/subgraph-provider.js +334 -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 +229 -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 +45 -0
- package/build/main/providers/v3/subgraph-provider.js +46 -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/providers/v4/caching-pool-provider.d.ts +24 -0
- package/build/main/providers/v4/caching-pool-provider.js +81 -0
- package/build/main/providers/v4/caching-subgraph-provider.d.ts +19 -0
- package/build/main/providers/v4/caching-subgraph-provider.js +24 -0
- package/build/main/providers/v4/euler-swap-hooks-subgraph-provider.d.ts +25 -0
- package/build/main/providers/v4/euler-swap-hooks-subgraph-provider.js +160 -0
- package/build/main/providers/v4/pool-provider.d.ts +58 -0
- package/build/main/providers/v4/pool-provider.js +115 -0
- package/build/main/providers/v4/static-subgraph-provider.d.ts +15 -0
- package/build/main/providers/v4/static-subgraph-provider.js +78 -0
- package/build/main/providers/v4/subgraph-provider-with-fallback.d.ts +5 -0
- package/build/main/providers/v4/subgraph-provider-with-fallback.js +12 -0
- package/build/main/providers/v4/subgraph-provider.d.ts +63 -0
- package/build/main/providers/v4/subgraph-provider.js +63 -0
- package/build/main/providers/v4/uri-subgraph-provider.d.ts +4 -0
- package/build/main/providers/v4/uri-subgraph-provider.js +8 -0
- package/build/main/routers/alpha-router/alpha-router.d.ts +483 -0
- package/build/main/routers/alpha-router/alpha-router.js +2267 -0
- package/build/main/routers/alpha-router/config.d.ts +4 -0
- package/build/main/routers/alpha-router/config.js +129 -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 +329 -0
- package/build/main/routers/alpha-router/entities/route-with-valid-quote.js +319 -0
- package/build/main/routers/alpha-router/functions/best-swap-route.d.ts +25 -0
- package/build/main/routers/alpha-router/functions/best-swap-route.js +597 -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 +16 -0
- package/build/main/routers/alpha-router/functions/compute-all-routes.js +158 -0
- package/build/main/routers/alpha-router/functions/get-candidate-pools.d.ts +192 -0
- package/build/main/routers/alpha-router/functions/get-candidate-pools.js +3025 -0
- package/build/main/routers/alpha-router/gas-models/fewV2/v2-heuristic-gas-model.d.ts +31 -0
- package/build/main/routers/alpha-router/gas-models/fewV2/v2-heuristic-gas-model.js +169 -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 +200 -0
- package/build/main/routers/alpha-router/gas-models/gas-model.d.ts +111 -0
- package/build/main/routers/alpha-router/gas-models/gas-model.js +120 -0
- package/build/main/routers/alpha-router/gas-models/index.d.ts +5 -0
- package/build/main/routers/alpha-router/gas-models/index.js +22 -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/ring-gas-model.d.ts +111 -0
- package/build/main/routers/alpha-router/gas-models/ring-gas-model.js +169 -0
- package/build/main/routers/alpha-router/gas-models/tick-based-heuristic-gas-model.d.ts +21 -0
- package/build/main/routers/alpha-router/gas-models/tick-based-heuristic-gas-model.js +366 -0
- package/build/main/routers/alpha-router/gas-models/uniswapFewV3/v3-heuristic-gas-model.d.ts +26 -0
- package/build/main/routers/alpha-router/gas-models/uniswapFewV3/v3-heuristic-gas-model.js +41 -0
- package/build/main/routers/alpha-router/gas-models/uniswapFewV4/v4-heuristic-gas-model.d.ts +15 -0
- package/build/main/routers/alpha-router/gas-models/uniswapFewV4/v4-heuristic-gas-model.js +40 -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/gas-models/v4/v4-heuristic-gas-model.d.ts +15 -0
- package/build/main/routers/alpha-router/gas-models/v4/v4-heuristic-gas-model.js +40 -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 +78 -0
- package/build/main/routers/alpha-router/quoters/base-quoter.js +77 -0
- package/build/main/routers/alpha-router/quoters/few-v2-quoter.d.ts +24 -0
- package/build/main/routers/alpha-router/quoters/few-v2-quoter.js +141 -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 +34 -0
- package/build/main/routers/alpha-router/quoters/mixed-quoter.js +156 -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/uniswap-few-v3-quoter.d.ts +19 -0
- package/build/main/routers/alpha-router/quoters/uniswap-few-v3-quoter.js +118 -0
- package/build/main/routers/alpha-router/quoters/uniswap-few-v4-quoter.d.ts +18 -0
- package/build/main/routers/alpha-router/quoters/uniswap-few-v4-quoter.js +121 -0
- package/build/main/routers/alpha-router/quoters/v2-quoter.d.ts +24 -0
- package/build/main/routers/alpha-router/quoters/v2-quoter.js +141 -0
- package/build/main/routers/alpha-router/quoters/v3-quoter.d.ts +19 -0
- package/build/main/routers/alpha-router/quoters/v3-quoter.js +125 -0
- package/build/main/routers/alpha-router/quoters/v4-quoter.d.ts +18 -0
- package/build/main/routers/alpha-router/quoters/v4-quoter.js +121 -0
- package/build/main/routers/index.d.ts +4 -0
- package/build/main/routers/index.js +21 -0
- package/build/main/routers/legacy-router/bases.d.ts +225 -0
- package/build/main/routers/legacy-router/bases.js +132 -0
- package/build/main/routers/legacy-router/index.d.ts +1 -0
- package/build/main/routers/legacy-router/index.js +18 -0
- package/build/main/routers/legacy-router/legacy-router.d.ts +41 -0
- package/build/main/routers/legacy-router/legacy-router.js +291 -0
- package/build/main/routers/router.d.ts +195 -0
- package/build/main/routers/router.js +68 -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/StateView__factory.d.ts +32 -0
- package/build/main/types/other/factories/StateView__factory.js +383 -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/other/factories/V4Quoter__factory.d.ts +37 -0
- package/build/main/types/other/factories/V4Quoter__factory.js +312 -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 +34 -0
- package/build/main/util/addresses.js +140 -0
- package/build/main/util/amounts.d.ts +10 -0
- package/build/main/util/amounts.js +94 -0
- package/build/main/util/callData.d.ts +1 -0
- package/build/main/util/callData.js +6 -0
- package/build/main/util/chains.d.ts +75 -0
- package/build/main/util/chains.js +780 -0
- package/build/main/util/defaultBlocksToLive.d.ts +4 -0
- package/build/main/util/defaultBlocksToLive.js +57 -0
- package/build/main/util/fewAddress.d.ts +48 -0
- package/build/main/util/fewAddress.js +624 -0
- package/build/main/util/gas-factory-helpers.d.ts +38 -0
- package/build/main/util/gas-factory-helpers.js +596 -0
- package/build/main/util/hooksOptions.d.ts +5 -0
- package/build/main/util/hooksOptions.js +10 -0
- package/build/main/util/index.d.ts +10 -0
- package/build/main/util/index.js +27 -0
- package/build/main/util/intent.d.ts +6 -0
- package/build/main/util/intent.js +13 -0
- package/build/main/util/l2FeeChains.d.ts +2 -0
- package/build/main/util/l2FeeChains.js +18 -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 +176 -0
- package/build/main/util/metric.d.ts +48 -0
- package/build/main/util/metric.js +59 -0
- package/build/main/util/mixedRouteFilterOutV4Pools.d.ts +3 -0
- package/build/main/util/mixedRouteFilterOutV4Pools.js +17 -0
- package/build/main/util/onchainQuoteProviderConfigs.d.ts +42 -0
- package/build/main/util/onchainQuoteProviderConfigs.js +72 -0
- package/build/main/util/pool.d.ts +5 -0
- package/build/main/util/pool.js +46 -0
- package/build/main/util/protocols.d.ts +2 -0
- package/build/main/util/protocols.js +22 -0
- package/build/main/util/routes.d.ts +11 -0
- package/build/main/util/routes.js +159 -0
- package/build/main/util/serializeRouteIds.d.ts +2 -0
- package/build/main/util/serializeRouteIds.js +12 -0
- package/build/main/util/simple-perf-tracker.d.ts +27 -0
- package/build/main/util/simple-perf-tracker.js +171 -0
- package/build/main/util/tenderlySimulationErrorBreakDown.d.ts +3 -0
- package/build/main/util/tenderlySimulationErrorBreakDown.js +33 -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 +73 -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 +111 -0
- package/build/module/providers/caching/route/route-caching-provider.js +82 -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 +182 -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 +227 -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 +21 -0
- package/build/module/providers/eth-estimate-gas-provider.js +99 -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/fewV2/ring-caching-pool-provider.d.ts +33 -0
- package/build/module/providers/fewV2/ring-caching-pool-provider.js +85 -0
- package/build/module/providers/fewV2/ring-caching-subgraph-provider.d.ts +19 -0
- package/build/module/providers/fewV2/ring-caching-subgraph-provider.js +20 -0
- package/build/module/providers/fewV2/ring-pool-provider.d.ts +63 -0
- package/build/module/providers/fewV2/ring-pool-provider.js +141 -0
- package/build/module/providers/fewV2/ring-quote-provider.d.ts +34 -0
- package/build/module/providers/fewV2/ring-quote-provider.js +86 -0
- package/build/module/providers/fewV2/ring-static-subgraph-provider.d.ts +24 -0
- package/build/module/providers/fewV2/ring-static-subgraph-provider.js +319 -0
- package/build/module/providers/fewV2/ring-subgraph-provider-with-fallback.d.ts +16 -0
- package/build/module/providers/fewV2/ring-subgraph-provider-with-fallback.js +19 -0
- package/build/module/providers/fewV2/ring-subgraph-provider.d.ts +52 -0
- package/build/module/providers/fewV2/ring-subgraph-provider.js +176 -0
- package/build/module/providers/fewV2/ring-uri-subgraph-provider.d.ts +4 -0
- package/build/module/providers/fewV2/ring-uri-subgraph-provider.js +4 -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 +56 -0
- package/build/module/providers/index.js +57 -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-ringswap-provider.d.ts +35 -0
- package/build/module/providers/multicall-ringswap-provider.js +157 -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 +33 -0
- package/build/module/providers/on-chain-quote-provider.d.ts +260 -0
- package/build/module/providers/on-chain-quote-provider.js +696 -0
- package/build/module/providers/pool-provider.d.ts +45 -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 +46 -0
- package/build/module/providers/simulation-provider.js +140 -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 +56 -0
- package/build/module/providers/subgraph-provider.js +284 -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/tenderly-simulation-provider.d.ts +63 -0
- package/build/module/providers/tenderly-simulation-provider.js +444 -0
- package/build/module/providers/token-fee-fetcher.d.ts +31 -0
- package/build/module/providers/token-fee-fetcher.js +110 -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 +167 -0
- package/build/module/providers/token-provider.js +401 -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 +21 -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 +141 -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 +178 -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 +52 -0
- package/build/module/providers/v2/subgraph-provider.js +331 -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 +224 -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 +45 -0
- package/build/module/providers/v3/subgraph-provider.js +42 -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/providers/v4/caching-pool-provider.d.ts +24 -0
- package/build/module/providers/v4/caching-pool-provider.js +74 -0
- package/build/module/providers/v4/caching-subgraph-provider.d.ts +19 -0
- package/build/module/providers/v4/caching-subgraph-provider.js +20 -0
- package/build/module/providers/v4/euler-swap-hooks-subgraph-provider.d.ts +25 -0
- package/build/module/providers/v4/euler-swap-hooks-subgraph-provider.js +153 -0
- package/build/module/providers/v4/pool-provider.d.ts +58 -0
- package/build/module/providers/v4/pool-provider.js +106 -0
- package/build/module/providers/v4/static-subgraph-provider.d.ts +15 -0
- package/build/module/providers/v4/static-subgraph-provider.js +71 -0
- package/build/module/providers/v4/subgraph-provider-with-fallback.d.ts +5 -0
- package/build/module/providers/v4/subgraph-provider-with-fallback.js +8 -0
- package/build/module/providers/v4/subgraph-provider.d.ts +63 -0
- package/build/module/providers/v4/subgraph-provider.js +59 -0
- package/build/module/providers/v4/uri-subgraph-provider.d.ts +4 -0
- package/build/module/providers/v4/uri-subgraph-provider.js +4 -0
- package/build/module/routers/alpha-router/alpha-router.d.ts +483 -0
- package/build/module/routers/alpha-router/alpha-router.js +2280 -0
- package/build/module/routers/alpha-router/config.d.ts +4 -0
- package/build/module/routers/alpha-router/config.js +125 -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 +329 -0
- package/build/module/routers/alpha-router/entities/route-with-valid-quote.js +306 -0
- package/build/module/routers/alpha-router/functions/best-swap-route.d.ts +25 -0
- package/build/module/routers/alpha-router/functions/best-swap-route.js +586 -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 +16 -0
- package/build/module/routers/alpha-router/functions/compute-all-routes.js +147 -0
- package/build/module/routers/alpha-router/functions/get-candidate-pools.d.ts +192 -0
- package/build/module/routers/alpha-router/functions/get-candidate-pools.js +3010 -0
- package/build/module/routers/alpha-router/gas-models/fewV2/v2-heuristic-gas-model.d.ts +31 -0
- package/build/module/routers/alpha-router/gas-models/fewV2/v2-heuristic-gas-model.js +162 -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 +189 -0
- package/build/module/routers/alpha-router/gas-models/gas-model.d.ts +111 -0
- package/build/module/routers/alpha-router/gas-models/gas-model.js +114 -0
- package/build/module/routers/alpha-router/gas-models/index.d.ts +5 -0
- package/build/module/routers/alpha-router/gas-models/index.js +6 -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/ring-gas-model.d.ts +111 -0
- package/build/module/routers/alpha-router/gas-models/ring-gas-model.js +163 -0
- package/build/module/routers/alpha-router/gas-models/tick-based-heuristic-gas-model.d.ts +21 -0
- package/build/module/routers/alpha-router/gas-models/tick-based-heuristic-gas-model.js +362 -0
- package/build/module/routers/alpha-router/gas-models/uniswapFewV3/v3-heuristic-gas-model.d.ts +26 -0
- package/build/module/routers/alpha-router/gas-models/uniswapFewV3/v3-heuristic-gas-model.js +37 -0
- package/build/module/routers/alpha-router/gas-models/uniswapFewV4/v4-heuristic-gas-model.d.ts +15 -0
- package/build/module/routers/alpha-router/gas-models/uniswapFewV4/v4-heuristic-gas-model.js +36 -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/gas-models/v4/v4-heuristic-gas-model.d.ts +15 -0
- package/build/module/routers/alpha-router/gas-models/v4/v4-heuristic-gas-model.js +36 -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 +78 -0
- package/build/module/routers/alpha-router/quoters/base-quoter.js +70 -0
- package/build/module/routers/alpha-router/quoters/few-v2-quoter.d.ts +24 -0
- package/build/module/routers/alpha-router/quoters/few-v2-quoter.js +138 -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 +34 -0
- package/build/module/routers/alpha-router/quoters/mixed-quoter.js +149 -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/uniswap-few-v3-quoter.d.ts +19 -0
- package/build/module/routers/alpha-router/quoters/uniswap-few-v3-quoter.js +111 -0
- package/build/module/routers/alpha-router/quoters/uniswap-few-v4-quoter.d.ts +18 -0
- package/build/module/routers/alpha-router/quoters/uniswap-few-v4-quoter.js +114 -0
- package/build/module/routers/alpha-router/quoters/v2-quoter.d.ts +24 -0
- package/build/module/routers/alpha-router/quoters/v2-quoter.js +138 -0
- package/build/module/routers/alpha-router/quoters/v3-quoter.d.ts +19 -0
- package/build/module/routers/alpha-router/quoters/v3-quoter.js +118 -0
- package/build/module/routers/alpha-router/quoters/v4-quoter.d.ts +18 -0
- package/build/module/routers/alpha-router/quoters/v4-quoter.js +114 -0
- package/build/module/routers/index.d.ts +4 -0
- package/build/module/routers/index.js +5 -0
- package/build/module/routers/legacy-router/bases.d.ts +225 -0
- package/build/module/routers/legacy-router/bases.js +138 -0
- package/build/module/routers/legacy-router/index.d.ts +1 -0
- package/build/module/routers/legacy-router/index.js +2 -0
- package/build/module/routers/legacy-router/legacy-router.d.ts +41 -0
- package/build/module/routers/legacy-router/legacy-router.js +292 -0
- package/build/module/routers/router.d.ts +195 -0
- package/build/module/routers/router.js +58 -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/StateView__factory.d.ts +32 -0
- package/build/module/types/other/factories/StateView__factory.js +379 -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/other/factories/V4Quoter__factory.d.ts +37 -0
- package/build/module/types/other/factories/V4Quoter__factory.js +308 -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 +34 -0
- package/build/module/util/addresses.js +280 -0
- package/build/module/util/amounts.d.ts +10 -0
- package/build/module/util/amounts.js +82 -0
- package/build/module/util/callData.d.ts +1 -0
- package/build/module/util/callData.js +3 -0
- package/build/module/util/chains.d.ts +75 -0
- package/build/module/util/chains.js +772 -0
- package/build/module/util/defaultBlocksToLive.d.ts +4 -0
- package/build/module/util/defaultBlocksToLive.js +54 -0
- package/build/module/util/fewAddress.d.ts +48 -0
- package/build/module/util/fewAddress.js +627 -0
- package/build/module/util/gas-factory-helpers.d.ts +38 -0
- package/build/module/util/gas-factory-helpers.js +575 -0
- package/build/module/util/hooksOptions.d.ts +5 -0
- package/build/module/util/hooksOptions.js +7 -0
- package/build/module/util/index.d.ts +10 -0
- package/build/module/util/index.js +11 -0
- package/build/module/util/intent.d.ts +6 -0
- package/build/module/util/intent.js +10 -0
- package/build/module/util/l2FeeChains.d.ts +2 -0
- package/build/module/util/l2FeeChains.js +15 -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 +176 -0
- package/build/module/util/metric.d.ts +48 -0
- package/build/module/util/metric.js +53 -0
- package/build/module/util/mixedRouteFilterOutV4Pools.d.ts +3 -0
- package/build/module/util/mixedRouteFilterOutV4Pools.js +12 -0
- package/build/module/util/onchainQuoteProviderConfigs.d.ts +42 -0
- package/build/module/util/onchainQuoteProviderConfigs.js +74 -0
- package/build/module/util/pool.d.ts +5 -0
- package/build/module/util/pool.js +43 -0
- package/build/module/util/protocols.d.ts +2 -0
- package/build/module/util/protocols.js +18 -0
- package/build/module/util/routes.d.ts +11 -0
- package/build/module/util/routes.js +147 -0
- package/build/module/util/serializeRouteIds.d.ts +2 -0
- package/build/module/util/serializeRouteIds.js +7 -0
- package/build/module/util/simple-perf-tracker.d.ts +27 -0
- package/build/module/util/simple-perf-tracker.js +161 -0
- package/build/module/util/tenderlySimulationErrorBreakDown.d.ts +3 -0
- package/build/module/util/tenderlySimulationErrorBreakDown.js +29 -0
- package/build/module/util/unsupported-tokens.d.ts +37 -0
- package/build/module/util/unsupported-tokens.js +1116 -0
- package/package.json +127 -0
|
@@ -0,0 +1,2280 @@
|
|
|
1
|
+
import { BigNumber } from '@ethersproject/bignumber';
|
|
2
|
+
import { JsonRpcProvider } from '@ethersproject/providers';
|
|
3
|
+
import DEFAULT_TOKEN_LIST from '@uniswap/default-token-list';
|
|
4
|
+
import { Protocol, SwapRouter, ZERO } from '@ring-protocol/router-sdk';
|
|
5
|
+
import { ChainId, Fraction, Token, TradeType, } from '@ring-protocol/sdk-core';
|
|
6
|
+
import { Pool, Position, SqrtPriceMath, TickMath } from '@ring-protocol/v3-sdk';
|
|
7
|
+
import retry from 'async-retry';
|
|
8
|
+
import JSBI from 'jsbi';
|
|
9
|
+
import _ from 'lodash';
|
|
10
|
+
import NodeCache from 'node-cache';
|
|
11
|
+
import { CachedRoutes, CacheMode, CachingGasStationProvider, CachingTokenProviderWithFallback, CachingV2PoolProvider,
|
|
12
|
+
// CachingV2SubgraphProvider,
|
|
13
|
+
CachingV3PoolProvider,
|
|
14
|
+
// CachingV3SubgraphProvider,
|
|
15
|
+
// CachingV4SubgraphProvider,
|
|
16
|
+
EIP1559GasPriceProvider, ETHGasStationInfoProvider, LegacyGasPriceProvider, NodeJSCache, OnChainGasPriceProvider, OnChainQuoteProvider, RingFewCachingV2PoolProvider,
|
|
17
|
+
// RingFewCachingV2SubgraphProvider,
|
|
18
|
+
RingFewStaticV2SubgraphProvider, RingFewV2SubgraphProviderWithFallBacks, RingswapMulticallProvider, RingV2PoolProvider, RingV2QuoteProvider, SimulationStatus, StaticV2SubgraphProvider, StaticV3SubgraphProvider, StaticV4SubgraphProvider, SwapRouterProvider, TokenPropertiesProvider, UniswapMulticallProvider,
|
|
19
|
+
// URISubgraphProvider,
|
|
20
|
+
V2QuoteProvider, V2SubgraphProviderWithFallBacks, V3SubgraphProviderWithFallBacks, V4SubgraphProviderWithFallBacks, } from '../../providers';
|
|
21
|
+
import { CachingTokenListProvider, } from '../../providers/caching-token-list-provider';
|
|
22
|
+
import { PortionProvider, } from '../../providers/portion-provider';
|
|
23
|
+
import { OnChainTokenFeeFetcher } from '../../providers/token-fee-fetcher';
|
|
24
|
+
import { TokenProvider } from '../../providers/token-provider';
|
|
25
|
+
import { TokenValidatorProvider, } from '../../providers/token-validator-provider';
|
|
26
|
+
import { V2PoolProvider, } from '../../providers/v2/pool-provider';
|
|
27
|
+
import { ArbitrumGasDataProvider, } from '../../providers/v3/gas-data-provider';
|
|
28
|
+
import { V3PoolProvider, } from '../../providers/v3/pool-provider';
|
|
29
|
+
import { CachingV4PoolProvider } from '../../providers/v4/caching-pool-provider';
|
|
30
|
+
import { V4PoolProvider, } from '../../providers/v4/pool-provider';
|
|
31
|
+
import { Erc20__factory } from '../../types/other/factories/Erc20__factory';
|
|
32
|
+
import { getAddress, getAddressLowerCase, getApplicableV4FeesTickspacingsHooks, HooksOptions, MIXED_SUPPORTED, shouldWipeoutCachedRoutes, SWAP_ROUTER_02_ADDRESSES, V4_SUPPORTED, WRAPPED_NATIVE_CURRENCY, } from '../../util';
|
|
33
|
+
import { CurrencyAmount } from '../../util/amounts';
|
|
34
|
+
import { FEW_WRAPPED_NATIVE_CURRENCY, ID_TO_CHAIN_ID,
|
|
35
|
+
// ID_TO_NETWORK_NAME,
|
|
36
|
+
RING_FEW_V2_SUPPORTED, V2_SUPPORTED, } from '../../util/chains';
|
|
37
|
+
import { getHighestLiquidityV3FewTokenUSDPool, getHighestLiquidityV3NativeFewTokenPool, getHighestLiquidityV3NativePool, getHighestLiquidityV3USDPool, } from '../../util/gas-factory-helpers';
|
|
38
|
+
import { log } from '../../util/log';
|
|
39
|
+
import { buildSwapMethodParameters, buildTrade, } from '../../util/methodParameters';
|
|
40
|
+
import { metric, MetricLoggerUnit } from '../../util/metric';
|
|
41
|
+
import { BATCH_PARAMS, BLOCK_NUMBER_CONFIGS, DEFAULT_BATCH_PARAMS, DEFAULT_BLOCK_NUMBER_CONFIGS, DEFAULT_GAS_ERROR_FAILURE_OVERRIDES, DEFAULT_RETRY_OPTIONS, DEFAULT_SUCCESS_RATE_FAILURE_OVERRIDES, GAS_ERROR_FAILURE_OVERRIDES, RETRY_OPTIONS, SUCCESS_RATE_FAILURE_OVERRIDES, } from '../../util/onchainQuoteProviderConfigs';
|
|
42
|
+
import { UNSUPPORTED_TOKENS } from '../../util/unsupported-tokens';
|
|
43
|
+
import { SwapToRatioStatus, SwapType, } from '../router';
|
|
44
|
+
import { UniversalRouterVersion } from '@ring-protocol/universal-router-sdk';
|
|
45
|
+
import { DEFAULT_BLOCKS_TO_LIVE } from '../../util/defaultBlocksToLive';
|
|
46
|
+
import { INTENT } from '../../util/intent';
|
|
47
|
+
import { serializeRouteIds } from '../../util/serializeRouteIds';
|
|
48
|
+
import { DEFAULT_ROUTING_CONFIG_BY_CHAIN, ETH_GAS_STATION_API_URL, } from './config';
|
|
49
|
+
import { getBestSwapRoute } from './functions/best-swap-route';
|
|
50
|
+
import { calculateRatioAmountIn } from './functions/calculate-ratio-amount-in';
|
|
51
|
+
import { getMixedCrossLiquidityCandidatePools, getRingFewV2CandidatePools, getUniswapFewTokenV2CandidatePools, getUniswapFewTokenV3CandidatePools, getUniswapV4FewTokenCandidatePools, getV2CandidatePools, getV3CandidatePools, getV4CandidatePools, } from './functions/get-candidate-pools';
|
|
52
|
+
import { NATIVE_OVERHEAD } from './gas-models/gas-costs';
|
|
53
|
+
import { MixedRouteHeuristicGasModelFactory } from './gas-models/mixedRoute/mixed-route-heuristic-gas-model';
|
|
54
|
+
import { V2HeuristicGasModelFactory } from './gas-models/v2/v2-heuristic-gas-model';
|
|
55
|
+
import { V3HeuristicGasModelFactory } from './gas-models/v3/v3-heuristic-gas-model';
|
|
56
|
+
import { UniswapFewV3HeuristicGasModelFactory } from './gas-models/uniswapFewV3/v3-heuristic-gas-model';
|
|
57
|
+
import { V4HeuristicGasModelFactory } from './gas-models/v4/v4-heuristic-gas-model';
|
|
58
|
+
import { UniswapFewV4HeuristicGasModelFactory } from './gas-models/uniswapFewV4/v4-heuristic-gas-model';
|
|
59
|
+
import { MixedQuoter, V2Quoter, V3Quoter } from './quoters';
|
|
60
|
+
import { V4Quoter } from './quoters/v4-quoter';
|
|
61
|
+
import { UniswapFewV4Quoter } from './quoters/uniswap-few-v4-quoter';
|
|
62
|
+
import { UniswapFewV3Quoter } from './quoters/uniswap-few-v3-quoter';
|
|
63
|
+
import { RingFewV2Quoter } from './quoters/few-v2-quoter';
|
|
64
|
+
import { RingFewV2HeuristicGasModelFactory } from './gas-models/fewV2/v2-heuristic-gas-model';
|
|
65
|
+
import { getFewTokenFromOriginalToken } from '@ring-protocol/few-v2-sdk';
|
|
66
|
+
import { isFewToken } from '../../util/fewAddress';
|
|
67
|
+
import { startTimer, endTimer, getPerfReport, clearPerfData } from '../../util/simple-perf-tracker';
|
|
68
|
+
export class MapWithLowerCaseKey extends Map {
|
|
69
|
+
set(key, value) {
|
|
70
|
+
return super.set(key.toLowerCase(), value);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export class LowerCaseStringArray extends Array {
|
|
74
|
+
constructor(...items) {
|
|
75
|
+
// Convert all items to lowercase before calling the parent constructor
|
|
76
|
+
super(...items.map((item) => item.toLowerCase()));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export class AlphaRouter {
|
|
80
|
+
constructor({ chainId, provider, multicall2Provider, ringFewV2Multicall2Provider, v4SubgraphProvider, v4PoolProvider, v3PoolProvider, onChainQuoteProvider, v2PoolProvider, ringFewV2PoolProvider, v2QuoteProvider, ringFewV2QuoteProvider, v2SubgraphProvider, ringFewV2SubgraphProvider, tokenProvider, blockedTokenListProvider, v3SubgraphProvider, gasPriceProvider, v4GasModelFactory, uniswapFewV4GasModelFactory, v3GasModelFactory, uniswapFewV3GasModelFactory, v2GasModelFactory, ringFewV2GasModelFactory, mixedRouteGasModelFactory, swapRouterProvider, tokenValidatorProvider, arbitrumGasDataProvider, simulator, routeCachingProvider, tokenPropertiesProvider, portionProvider, v2Supported, ringFewV2Supported, v4Supported, mixedSupported, v4PoolParams, cachedRoutesCacheInvalidationFixRolloutPercentage, }) {
|
|
81
|
+
clearPerfData();
|
|
82
|
+
this.chainId = chainId;
|
|
83
|
+
this.provider = provider;
|
|
84
|
+
this.multicall2Provider =
|
|
85
|
+
multicall2Provider !== null && multicall2Provider !== void 0 ? multicall2Provider : new UniswapMulticallProvider(chainId, provider, 375000);
|
|
86
|
+
this.ringFewV2Multicall2Provider =
|
|
87
|
+
ringFewV2Multicall2Provider !== null && ringFewV2Multicall2Provider !== void 0 ? ringFewV2Multicall2Provider : new RingswapMulticallProvider(chainId, provider, 375000);
|
|
88
|
+
this.v4PoolProvider =
|
|
89
|
+
v4PoolProvider !== null && v4PoolProvider !== void 0 ? v4PoolProvider : new CachingV4PoolProvider(this.chainId, new V4PoolProvider(ID_TO_CHAIN_ID(chainId), this.multicall2Provider), new NodeJSCache(new NodeCache({ stdTTL: 360, useClones: false })));
|
|
90
|
+
this.v3PoolProvider =
|
|
91
|
+
v3PoolProvider !== null && v3PoolProvider !== void 0 ? v3PoolProvider : new CachingV3PoolProvider(this.chainId, new V3PoolProvider(ID_TO_CHAIN_ID(chainId), this.multicall2Provider), new NodeJSCache(new NodeCache({ stdTTL: 360, useClones: false })));
|
|
92
|
+
this.simulator = simulator;
|
|
93
|
+
this.routeCachingProvider = routeCachingProvider;
|
|
94
|
+
if (onChainQuoteProvider) {
|
|
95
|
+
this.onChainQuoteProvider = onChainQuoteProvider;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
switch (chainId) {
|
|
99
|
+
case ChainId.OPTIMISM:
|
|
100
|
+
case ChainId.OPTIMISM_GOERLI:
|
|
101
|
+
case ChainId.OPTIMISM_SEPOLIA:
|
|
102
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, this.ringFewV2Multicall2Provider, {
|
|
103
|
+
retries: 2,
|
|
104
|
+
minTimeout: 100,
|
|
105
|
+
maxTimeout: 1000,
|
|
106
|
+
}, (_) => {
|
|
107
|
+
return {
|
|
108
|
+
multicallChunk: 110,
|
|
109
|
+
gasLimitPerCall: 1200000,
|
|
110
|
+
quoteMinSuccessRate: 0.1,
|
|
111
|
+
};
|
|
112
|
+
}, (_) => {
|
|
113
|
+
return {
|
|
114
|
+
gasLimitOverride: 3000000,
|
|
115
|
+
multicallChunk: 45,
|
|
116
|
+
};
|
|
117
|
+
}, (_) => {
|
|
118
|
+
return {
|
|
119
|
+
gasLimitOverride: 3000000,
|
|
120
|
+
multicallChunk: 45,
|
|
121
|
+
};
|
|
122
|
+
}, (_) => {
|
|
123
|
+
return {
|
|
124
|
+
baseBlockOffset: -10,
|
|
125
|
+
rollback: {
|
|
126
|
+
enabled: true,
|
|
127
|
+
attemptsBeforeRollback: 1,
|
|
128
|
+
rollbackBlockOffset: -10,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
break;
|
|
133
|
+
case ChainId.BASE:
|
|
134
|
+
case ChainId.BLAST:
|
|
135
|
+
case ChainId.ZORA:
|
|
136
|
+
case ChainId.WORLDCHAIN:
|
|
137
|
+
case ChainId.UNICHAIN_SEPOLIA:
|
|
138
|
+
case ChainId.MONAD_TESTNET:
|
|
139
|
+
case ChainId.BASE_SEPOLIA:
|
|
140
|
+
case ChainId.UNICHAIN:
|
|
141
|
+
case ChainId.BASE_GOERLI:
|
|
142
|
+
case ChainId.SONEIUM:
|
|
143
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, this.ringFewV2Multicall2Provider, {
|
|
144
|
+
retries: 2,
|
|
145
|
+
minTimeout: 100,
|
|
146
|
+
maxTimeout: 1000,
|
|
147
|
+
}, (_) => {
|
|
148
|
+
return {
|
|
149
|
+
multicallChunk: 80,
|
|
150
|
+
gasLimitPerCall: 1200000,
|
|
151
|
+
quoteMinSuccessRate: 0.1,
|
|
152
|
+
};
|
|
153
|
+
}, (_) => {
|
|
154
|
+
return {
|
|
155
|
+
gasLimitOverride: 3000000,
|
|
156
|
+
multicallChunk: 45,
|
|
157
|
+
};
|
|
158
|
+
}, (_) => {
|
|
159
|
+
return {
|
|
160
|
+
gasLimitOverride: 3000000,
|
|
161
|
+
multicallChunk: 45,
|
|
162
|
+
};
|
|
163
|
+
}, (_) => {
|
|
164
|
+
return {
|
|
165
|
+
baseBlockOffset: -10,
|
|
166
|
+
rollback: {
|
|
167
|
+
enabled: true,
|
|
168
|
+
attemptsBeforeRollback: 1,
|
|
169
|
+
rollbackBlockOffset: -10,
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
break;
|
|
174
|
+
case ChainId.ZKSYNC:
|
|
175
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, this.ringFewV2Multicall2Provider, {
|
|
176
|
+
retries: 2,
|
|
177
|
+
minTimeout: 100,
|
|
178
|
+
maxTimeout: 1000,
|
|
179
|
+
}, (_) => {
|
|
180
|
+
return {
|
|
181
|
+
multicallChunk: 27,
|
|
182
|
+
gasLimitPerCall: 3000000,
|
|
183
|
+
quoteMinSuccessRate: 0.1,
|
|
184
|
+
};
|
|
185
|
+
}, (_) => {
|
|
186
|
+
return {
|
|
187
|
+
gasLimitOverride: 6000000,
|
|
188
|
+
multicallChunk: 13,
|
|
189
|
+
};
|
|
190
|
+
}, (_) => {
|
|
191
|
+
return {
|
|
192
|
+
gasLimitOverride: 6000000,
|
|
193
|
+
multicallChunk: 13,
|
|
194
|
+
};
|
|
195
|
+
}, (_) => {
|
|
196
|
+
return {
|
|
197
|
+
baseBlockOffset: -10,
|
|
198
|
+
rollback: {
|
|
199
|
+
enabled: true,
|
|
200
|
+
attemptsBeforeRollback: 1,
|
|
201
|
+
rollbackBlockOffset: -10,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
break;
|
|
206
|
+
case ChainId.ARBITRUM_ONE:
|
|
207
|
+
case ChainId.ARBITRUM_GOERLI:
|
|
208
|
+
case ChainId.ARBITRUM_SEPOLIA:
|
|
209
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, this.ringFewV2Multicall2Provider, {
|
|
210
|
+
retries: 2,
|
|
211
|
+
minTimeout: 100,
|
|
212
|
+
maxTimeout: 1000,
|
|
213
|
+
}, (_) => {
|
|
214
|
+
return {
|
|
215
|
+
multicallChunk: 10,
|
|
216
|
+
gasLimitPerCall: 12000000,
|
|
217
|
+
quoteMinSuccessRate: 0.1,
|
|
218
|
+
};
|
|
219
|
+
}, (_) => {
|
|
220
|
+
return {
|
|
221
|
+
gasLimitOverride: 30000000,
|
|
222
|
+
multicallChunk: 6,
|
|
223
|
+
};
|
|
224
|
+
}, (_) => {
|
|
225
|
+
return {
|
|
226
|
+
gasLimitOverride: 30000000,
|
|
227
|
+
multicallChunk: 6,
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
break;
|
|
231
|
+
case ChainId.CELO:
|
|
232
|
+
case ChainId.CELO_ALFAJORES:
|
|
233
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, this.ringFewV2Multicall2Provider, {
|
|
234
|
+
retries: 2,
|
|
235
|
+
minTimeout: 100,
|
|
236
|
+
maxTimeout: 1000,
|
|
237
|
+
}, (_) => {
|
|
238
|
+
return {
|
|
239
|
+
multicallChunk: 10,
|
|
240
|
+
gasLimitPerCall: 5000000,
|
|
241
|
+
quoteMinSuccessRate: 0.1,
|
|
242
|
+
};
|
|
243
|
+
}, (_) => {
|
|
244
|
+
return {
|
|
245
|
+
gasLimitOverride: 5000000,
|
|
246
|
+
multicallChunk: 5,
|
|
247
|
+
};
|
|
248
|
+
}, (_) => {
|
|
249
|
+
return {
|
|
250
|
+
gasLimitOverride: 6250000,
|
|
251
|
+
multicallChunk: 4,
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
break;
|
|
255
|
+
case ChainId.POLYGON_MUMBAI:
|
|
256
|
+
case ChainId.SEPOLIA:
|
|
257
|
+
case ChainId.MAINNET:
|
|
258
|
+
case ChainId.POLYGON:
|
|
259
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, this.ringFewV2Multicall2Provider, RETRY_OPTIONS[chainId], (_) => BATCH_PARAMS[chainId], (_) => GAS_ERROR_FAILURE_OVERRIDES[chainId], (_) => SUCCESS_RATE_FAILURE_OVERRIDES[chainId], (_) => BLOCK_NUMBER_CONFIGS[chainId]);
|
|
260
|
+
break;
|
|
261
|
+
default:
|
|
262
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, this.ringFewV2Multicall2Provider, DEFAULT_RETRY_OPTIONS, (_) => DEFAULT_BATCH_PARAMS, (_) => DEFAULT_GAS_ERROR_FAILURE_OVERRIDES, (_) => DEFAULT_SUCCESS_RATE_FAILURE_OVERRIDES, (_) => DEFAULT_BLOCK_NUMBER_CONFIGS);
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (tokenValidatorProvider) {
|
|
267
|
+
this.tokenValidatorProvider = tokenValidatorProvider;
|
|
268
|
+
}
|
|
269
|
+
else if (this.chainId === ChainId.MAINNET) {
|
|
270
|
+
this.tokenValidatorProvider = new TokenValidatorProvider(this.chainId, this.multicall2Provider, new NodeJSCache(new NodeCache({ stdTTL: 30000, useClones: false })));
|
|
271
|
+
}
|
|
272
|
+
if (tokenPropertiesProvider) {
|
|
273
|
+
this.tokenPropertiesProvider = tokenPropertiesProvider;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
this.tokenPropertiesProvider = new TokenPropertiesProvider(this.chainId, new NodeJSCache(new NodeCache({ stdTTL: 86400, useClones: false })), new OnChainTokenFeeFetcher(this.chainId, provider));
|
|
277
|
+
}
|
|
278
|
+
this.v2PoolProvider =
|
|
279
|
+
v2PoolProvider !== null && v2PoolProvider !== void 0 ? v2PoolProvider : new CachingV2PoolProvider(chainId, new V2PoolProvider(chainId, this.multicall2Provider, this.tokenPropertiesProvider), new NodeJSCache(new NodeCache({ stdTTL: 60, useClones: false })));
|
|
280
|
+
this.ringFewV2PoolProvider =
|
|
281
|
+
ringFewV2PoolProvider !== null && ringFewV2PoolProvider !== void 0 ? ringFewV2PoolProvider : new RingFewCachingV2PoolProvider(chainId, new RingV2PoolProvider(chainId, this.multicall2Provider, this.tokenPropertiesProvider), new NodeJSCache(new NodeCache({ stdTTL: 60, useClones: false })));
|
|
282
|
+
this.v2QuoteProvider = v2QuoteProvider !== null && v2QuoteProvider !== void 0 ? v2QuoteProvider : new V2QuoteProvider();
|
|
283
|
+
this.ringFewV2QuoteProvider = ringFewV2QuoteProvider !== null && ringFewV2QuoteProvider !== void 0 ? ringFewV2QuoteProvider : new RingV2QuoteProvider();
|
|
284
|
+
this.blockedTokenListProvider =
|
|
285
|
+
blockedTokenListProvider !== null && blockedTokenListProvider !== void 0 ? blockedTokenListProvider : new CachingTokenListProvider(chainId, UNSUPPORTED_TOKENS, new NodeJSCache(new NodeCache({ stdTTL: 3600, useClones: false })));
|
|
286
|
+
this.tokenProvider =
|
|
287
|
+
tokenProvider !== null && tokenProvider !== void 0 ? tokenProvider : new CachingTokenProviderWithFallback(chainId, new NodeJSCache(new NodeCache({ stdTTL: 3600, useClones: false })), new CachingTokenListProvider(chainId, DEFAULT_TOKEN_LIST, new NodeJSCache(new NodeCache({ stdTTL: 3600, useClones: false }))), new TokenProvider(chainId, this.multicall2Provider));
|
|
288
|
+
this.portionProvider = portionProvider !== null && portionProvider !== void 0 ? portionProvider : new PortionProvider();
|
|
289
|
+
// const chainName = ID_TO_NETWORK_NAME(chainId);
|
|
290
|
+
// ipfs urls in the following format: `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/${protocol}/${chainName}.json`;
|
|
291
|
+
if (v2SubgraphProvider) {
|
|
292
|
+
this.v2SubgraphProvider = v2SubgraphProvider;
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
this.v2SubgraphProvider = new V2SubgraphProviderWithFallBacks([
|
|
296
|
+
// new CachingV2SubgraphProvider(
|
|
297
|
+
// chainId,
|
|
298
|
+
// new URISubgraphProvider(
|
|
299
|
+
// chainId,
|
|
300
|
+
// `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/v2/${chainName}.json`,
|
|
301
|
+
// undefined,
|
|
302
|
+
// 0
|
|
303
|
+
// ),
|
|
304
|
+
// new NodeJSCache(new NodeCache({ stdTTL: 300, useClones: false }))
|
|
305
|
+
// ),
|
|
306
|
+
new StaticV2SubgraphProvider(chainId),
|
|
307
|
+
]);
|
|
308
|
+
}
|
|
309
|
+
if (ringFewV2SubgraphProvider) {
|
|
310
|
+
this.ringFewV2SubgraphProvider = ringFewV2SubgraphProvider;
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
this.ringFewV2SubgraphProvider = new RingFewV2SubgraphProviderWithFallBacks([
|
|
314
|
+
// new RingFewCachingV2SubgraphProvider(
|
|
315
|
+
// chainId,
|
|
316
|
+
// new URISubgraphProvider(
|
|
317
|
+
// chainId,
|
|
318
|
+
// `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/v2/${chainName}.json`,
|
|
319
|
+
// undefined,
|
|
320
|
+
// 0
|
|
321
|
+
// ),
|
|
322
|
+
// new NodeJSCache(new NodeCache({ stdTTL: 300, useClones: false }))
|
|
323
|
+
// ),
|
|
324
|
+
new RingFewStaticV2SubgraphProvider(chainId),
|
|
325
|
+
]);
|
|
326
|
+
}
|
|
327
|
+
if (v3SubgraphProvider) {
|
|
328
|
+
this.v3SubgraphProvider = v3SubgraphProvider;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
this.v3SubgraphProvider = new V3SubgraphProviderWithFallBacks([
|
|
332
|
+
// new CachingV3SubgraphProvider(
|
|
333
|
+
// chainId,
|
|
334
|
+
// new URISubgraphProvider(
|
|
335
|
+
// chainId,
|
|
336
|
+
// `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/v3/${chainName}.json`,
|
|
337
|
+
// undefined,
|
|
338
|
+
// 0
|
|
339
|
+
// ),
|
|
340
|
+
// new NodeJSCache(new NodeCache({ stdTTL: 300, useClones: false }))
|
|
341
|
+
// ),
|
|
342
|
+
new StaticV3SubgraphProvider(chainId, this.v3PoolProvider),
|
|
343
|
+
]);
|
|
344
|
+
}
|
|
345
|
+
this.v4PoolParams =
|
|
346
|
+
v4PoolParams !== null && v4PoolParams !== void 0 ? v4PoolParams : getApplicableV4FeesTickspacingsHooks(chainId);
|
|
347
|
+
if (v4SubgraphProvider) {
|
|
348
|
+
this.v4SubgraphProvider = v4SubgraphProvider;
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
this.v4SubgraphProvider = new V4SubgraphProviderWithFallBacks([
|
|
352
|
+
// new CachingV4SubgraphProvider(
|
|
353
|
+
// chainId,
|
|
354
|
+
// new URISubgraphProvider(
|
|
355
|
+
// chainId,
|
|
356
|
+
// `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/v4/${chainName}.json`,
|
|
357
|
+
// undefined,
|
|
358
|
+
// 0
|
|
359
|
+
// ),
|
|
360
|
+
// new NodeJSCache(new NodeCache({ stdTTL: 300, useClones: false }))
|
|
361
|
+
// ),
|
|
362
|
+
new StaticV4SubgraphProvider(chainId, this.v4PoolProvider, this.v4PoolParams),
|
|
363
|
+
]);
|
|
364
|
+
}
|
|
365
|
+
let gasPriceProviderInstance;
|
|
366
|
+
if (JsonRpcProvider.isProvider(this.provider)) {
|
|
367
|
+
gasPriceProviderInstance = new OnChainGasPriceProvider(chainId, new EIP1559GasPriceProvider(this.provider), new LegacyGasPriceProvider(this.provider));
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
gasPriceProviderInstance = new ETHGasStationInfoProvider(ETH_GAS_STATION_API_URL);
|
|
371
|
+
}
|
|
372
|
+
this.gasPriceProvider =
|
|
373
|
+
gasPriceProvider !== null && gasPriceProvider !== void 0 ? gasPriceProvider : new CachingGasStationProvider(chainId, gasPriceProviderInstance, new NodeJSCache(new NodeCache({ stdTTL: 7, useClones: false })));
|
|
374
|
+
this.v4GasModelFactory =
|
|
375
|
+
v4GasModelFactory !== null && v4GasModelFactory !== void 0 ? v4GasModelFactory : new V4HeuristicGasModelFactory(this.provider);
|
|
376
|
+
this.uniswapFewV4GasModelFactory =
|
|
377
|
+
uniswapFewV4GasModelFactory !== null && uniswapFewV4GasModelFactory !== void 0 ? uniswapFewV4GasModelFactory : new UniswapFewV4HeuristicGasModelFactory(this.provider);
|
|
378
|
+
this.v3GasModelFactory =
|
|
379
|
+
v3GasModelFactory !== null && v3GasModelFactory !== void 0 ? v3GasModelFactory : new V3HeuristicGasModelFactory(this.provider);
|
|
380
|
+
this.uniswapFewV3GasModelFactory =
|
|
381
|
+
uniswapFewV3GasModelFactory !== null && uniswapFewV3GasModelFactory !== void 0 ? uniswapFewV3GasModelFactory : new UniswapFewV3HeuristicGasModelFactory(this.provider);
|
|
382
|
+
this.v2GasModelFactory =
|
|
383
|
+
v2GasModelFactory !== null && v2GasModelFactory !== void 0 ? v2GasModelFactory : new V2HeuristicGasModelFactory(this.provider);
|
|
384
|
+
this.ringFewV2GasModelFactory =
|
|
385
|
+
ringFewV2GasModelFactory !== null && ringFewV2GasModelFactory !== void 0 ? ringFewV2GasModelFactory : new RingFewV2HeuristicGasModelFactory(this.provider);
|
|
386
|
+
this.mixedRouteGasModelFactory =
|
|
387
|
+
mixedRouteGasModelFactory !== null && mixedRouteGasModelFactory !== void 0 ? mixedRouteGasModelFactory : new MixedRouteHeuristicGasModelFactory();
|
|
388
|
+
this.swapRouterProvider =
|
|
389
|
+
swapRouterProvider !== null && swapRouterProvider !== void 0 ? swapRouterProvider : new SwapRouterProvider(this.multicall2Provider, this.chainId);
|
|
390
|
+
if (chainId === ChainId.ARBITRUM_ONE ||
|
|
391
|
+
chainId === ChainId.ARBITRUM_GOERLI) {
|
|
392
|
+
this.l2GasDataProvider =
|
|
393
|
+
arbitrumGasDataProvider !== null && arbitrumGasDataProvider !== void 0 ? arbitrumGasDataProvider : new ArbitrumGasDataProvider(chainId, this.provider);
|
|
394
|
+
}
|
|
395
|
+
// Initialize the Quoters.
|
|
396
|
+
// Quoters are an abstraction encapsulating the business logic of fetching routes and quotes.
|
|
397
|
+
this.v2Quoter = new V2Quoter(this.v2SubgraphProvider, this.v2PoolProvider, this.v2QuoteProvider, this.v2GasModelFactory, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider, this.l2GasDataProvider);
|
|
398
|
+
this.ringFewV2Quoter = new RingFewV2Quoter(this.ringFewV2SubgraphProvider, this.ringFewV2PoolProvider, this.ringFewV2QuoteProvider, this.ringFewV2GasModelFactory, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider, this.l2GasDataProvider);
|
|
399
|
+
this.v3Quoter = new V3Quoter(this.v3SubgraphProvider, this.v3PoolProvider, this.onChainQuoteProvider, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
400
|
+
this.uniswapFewV3Quoter = new UniswapFewV3Quoter(this.v3SubgraphProvider, this.v3PoolProvider, this.onChainQuoteProvider, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
401
|
+
this.v4Quoter = new V4Quoter(this.v4SubgraphProvider, this.v4PoolProvider, this.onChainQuoteProvider, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
402
|
+
this.uniswapFewV4Quoter = new UniswapFewV4Quoter(this.v4SubgraphProvider, this.v4PoolProvider, this.onChainQuoteProvider, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
403
|
+
this.mixedQuoter = new MixedQuoter(this.v4SubgraphProvider, this.v4PoolProvider, this.v3SubgraphProvider, this.v3PoolProvider, this.v2SubgraphProvider, this.v2PoolProvider, this.onChainQuoteProvider, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
404
|
+
this.v2Supported = v2Supported !== null && v2Supported !== void 0 ? v2Supported : V2_SUPPORTED;
|
|
405
|
+
this.ringFewV2Supported = ringFewV2Supported !== null && ringFewV2Supported !== void 0 ? ringFewV2Supported : RING_FEW_V2_SUPPORTED;
|
|
406
|
+
this.v4Supported = v4Supported !== null && v4Supported !== void 0 ? v4Supported : V4_SUPPORTED;
|
|
407
|
+
this.mixedSupported = mixedSupported !== null && mixedSupported !== void 0 ? mixedSupported : MIXED_SUPPORTED;
|
|
408
|
+
this.cachedRoutesCacheInvalidationFixRolloutPercentage =
|
|
409
|
+
cachedRoutesCacheInvalidationFixRolloutPercentage;
|
|
410
|
+
}
|
|
411
|
+
async routeToRatio(token0Balance, token1Balance, position, swapAndAddConfig, swapAndAddOptions, routingConfig = DEFAULT_ROUTING_CONFIG_BY_CHAIN(this.chainId)) {
|
|
412
|
+
if (token1Balance.currency.wrapped.sortsBefore(token0Balance.currency.wrapped)) {
|
|
413
|
+
[token0Balance, token1Balance] = [token1Balance, token0Balance];
|
|
414
|
+
}
|
|
415
|
+
let preSwapOptimalRatio = this.calculateOptimalRatio(position, position.pool.sqrtRatioX96, true);
|
|
416
|
+
// set up parameters according to which token will be swapped
|
|
417
|
+
let zeroForOne;
|
|
418
|
+
if (position.pool.tickCurrent > position.tickUpper) {
|
|
419
|
+
zeroForOne = true;
|
|
420
|
+
}
|
|
421
|
+
else if (position.pool.tickCurrent < position.tickLower) {
|
|
422
|
+
zeroForOne = false;
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
zeroForOne = new Fraction(token0Balance.quotient, token1Balance.quotient).greaterThan(preSwapOptimalRatio);
|
|
426
|
+
if (!zeroForOne)
|
|
427
|
+
preSwapOptimalRatio = preSwapOptimalRatio.invert();
|
|
428
|
+
}
|
|
429
|
+
const [inputBalance, outputBalance] = zeroForOne
|
|
430
|
+
? [token0Balance, token1Balance]
|
|
431
|
+
: [token1Balance, token0Balance];
|
|
432
|
+
let optimalRatio = preSwapOptimalRatio;
|
|
433
|
+
let postSwapTargetPool = position.pool;
|
|
434
|
+
let exchangeRate = zeroForOne
|
|
435
|
+
? position.pool.token0Price
|
|
436
|
+
: position.pool.token1Price;
|
|
437
|
+
let swap = null;
|
|
438
|
+
let ratioAchieved = false;
|
|
439
|
+
let n = 0;
|
|
440
|
+
// iterate until we find a swap with a sufficient ratio or return null
|
|
441
|
+
while (!ratioAchieved) {
|
|
442
|
+
n++;
|
|
443
|
+
if (n > swapAndAddConfig.maxIterations) {
|
|
444
|
+
log.info('max iterations exceeded');
|
|
445
|
+
return {
|
|
446
|
+
status: SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
447
|
+
error: 'max iterations exceeded',
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
const amountToSwap = calculateRatioAmountIn(optimalRatio, exchangeRate, inputBalance, outputBalance);
|
|
451
|
+
if (amountToSwap.equalTo(0)) {
|
|
452
|
+
log.info(`no swap needed: amountToSwap = 0`);
|
|
453
|
+
return {
|
|
454
|
+
status: SwapToRatioStatus.NO_SWAP_NEEDED,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
swap = await this.route(amountToSwap, outputBalance.currency, TradeType.EXACT_INPUT, undefined, {
|
|
458
|
+
...DEFAULT_ROUTING_CONFIG_BY_CHAIN(this.chainId),
|
|
459
|
+
...routingConfig,
|
|
460
|
+
/// @dev We do not want to query for mixedRoutes for routeToRatio as they are not supported
|
|
461
|
+
/// [Protocol.V3, Protocol.V2] will make sure we only query for V3 and V2
|
|
462
|
+
protocols: [Protocol.V3, Protocol.V2],
|
|
463
|
+
});
|
|
464
|
+
if (!swap) {
|
|
465
|
+
log.info('no route found from this.route()');
|
|
466
|
+
return {
|
|
467
|
+
status: SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
468
|
+
error: 'no route found',
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
const inputBalanceUpdated = inputBalance.subtract(swap.trade.inputAmount);
|
|
472
|
+
const outputBalanceUpdated = outputBalance.add(swap.trade.outputAmount);
|
|
473
|
+
const newRatio = inputBalanceUpdated.divide(outputBalanceUpdated);
|
|
474
|
+
let targetPoolPriceUpdate;
|
|
475
|
+
swap.route.forEach((route) => {
|
|
476
|
+
if (route.protocol === Protocol.V3) {
|
|
477
|
+
const v3Route = route;
|
|
478
|
+
v3Route.route.pools.forEach((pool, i) => {
|
|
479
|
+
if (pool.token0.equals(position.pool.token0) &&
|
|
480
|
+
pool.token1.equals(position.pool.token1) &&
|
|
481
|
+
pool.fee === position.pool.fee) {
|
|
482
|
+
targetPoolPriceUpdate = JSBI.BigInt(v3Route.sqrtPriceX96AfterList[i].toString());
|
|
483
|
+
optimalRatio = this.calculateOptimalRatio(position, JSBI.BigInt(targetPoolPriceUpdate.toString()), zeroForOne);
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
if (!targetPoolPriceUpdate) {
|
|
489
|
+
optimalRatio = preSwapOptimalRatio;
|
|
490
|
+
}
|
|
491
|
+
ratioAchieved =
|
|
492
|
+
newRatio.equalTo(optimalRatio) ||
|
|
493
|
+
this.absoluteValue(newRatio.asFraction.divide(optimalRatio).subtract(1)).lessThan(swapAndAddConfig.ratioErrorTolerance);
|
|
494
|
+
if (ratioAchieved && targetPoolPriceUpdate) {
|
|
495
|
+
postSwapTargetPool = new Pool(position.pool.token0, position.pool.token1, position.pool.fee, targetPoolPriceUpdate, position.pool.liquidity, TickMath.getTickAtSqrtRatio(targetPoolPriceUpdate), position.pool.tickDataProvider);
|
|
496
|
+
}
|
|
497
|
+
exchangeRate = swap.trade.outputAmount.divide(swap.trade.inputAmount);
|
|
498
|
+
log.info({
|
|
499
|
+
exchangeRate: exchangeRate.asFraction.toFixed(18),
|
|
500
|
+
optimalRatio: optimalRatio.asFraction.toFixed(18),
|
|
501
|
+
newRatio: newRatio.asFraction.toFixed(18),
|
|
502
|
+
inputBalanceUpdated: inputBalanceUpdated.asFraction.toFixed(18),
|
|
503
|
+
outputBalanceUpdated: outputBalanceUpdated.asFraction.toFixed(18),
|
|
504
|
+
ratioErrorTolerance: swapAndAddConfig.ratioErrorTolerance.toFixed(18),
|
|
505
|
+
iterationN: n.toString(),
|
|
506
|
+
}, 'QuoteToRatio Iteration Parameters');
|
|
507
|
+
if (exchangeRate.equalTo(0)) {
|
|
508
|
+
log.info('exchangeRate to 0');
|
|
509
|
+
return {
|
|
510
|
+
status: SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
511
|
+
error: 'insufficient liquidity to swap to optimal ratio',
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (!swap) {
|
|
516
|
+
return {
|
|
517
|
+
status: SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
518
|
+
error: 'no route found',
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
let methodParameters;
|
|
522
|
+
if (swapAndAddOptions) {
|
|
523
|
+
methodParameters = await this.buildSwapAndAddMethodParameters(swap.trade, swapAndAddOptions, {
|
|
524
|
+
initialBalanceTokenIn: inputBalance,
|
|
525
|
+
initialBalanceTokenOut: outputBalance,
|
|
526
|
+
preLiquidityPosition: position,
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
return {
|
|
530
|
+
status: SwapToRatioStatus.SUCCESS,
|
|
531
|
+
result: { ...swap, methodParameters, optimalRatio, postSwapTargetPool },
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* @inheritdoc IRouter
|
|
536
|
+
*/
|
|
537
|
+
async route(amount, quoteCurrency, tradeType, swapConfig, partialRoutingConfig = {}) {
|
|
538
|
+
var _a, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
|
|
539
|
+
const originalAmount = amount;
|
|
540
|
+
const fewAmountToken = getFewTokenFromOriginalToken(originalAmount.currency.wrapped, this.chainId);
|
|
541
|
+
let fewAmount = CurrencyAmount.fromRawAmount(fewAmountToken, originalAmount.quotient); // 在 Blast 网络需要注意 origin token 和 fewtoken 的 decimals 差异
|
|
542
|
+
// const originalFewAmount = fewAmount;
|
|
543
|
+
const { currencyIn, currencyOut } = this.determineCurrencyInOutFromTradeType(tradeType, amount, quoteCurrency);
|
|
544
|
+
const fewTokenIn = currencyIn instanceof Token
|
|
545
|
+
? getFewTokenFromOriginalToken(currencyIn, this.chainId)
|
|
546
|
+
: currencyIn.isNative
|
|
547
|
+
? getFewTokenFromOriginalToken(currencyIn.wrapped, this.chainId)
|
|
548
|
+
: null;
|
|
549
|
+
const fewTokenOut = currencyOut instanceof Token
|
|
550
|
+
? getFewTokenFromOriginalToken(currencyOut, this.chainId)
|
|
551
|
+
: currencyOut.isNative
|
|
552
|
+
? getFewTokenFromOriginalToken(currencyOut.wrapped, this.chainId)
|
|
553
|
+
: null;
|
|
554
|
+
const fewQuoteToken = quoteCurrency instanceof Token
|
|
555
|
+
? getFewTokenFromOriginalToken(quoteCurrency, this.chainId)
|
|
556
|
+
: quoteCurrency.isNative
|
|
557
|
+
? getFewTokenFromOriginalToken(quoteCurrency.wrapped, this.chainId)
|
|
558
|
+
: null;
|
|
559
|
+
const tokenOutProperties = await this.tokenPropertiesProvider.getTokensProperties([currencyOut], partialRoutingConfig);
|
|
560
|
+
const feeTakenOnTransfer = (_c = (_a = tokenOutProperties[getAddressLowerCase(currencyOut)]) === null || _a === void 0 ? void 0 : _a.tokenFeeResult) === null || _c === void 0 ? void 0 : _c.feeTakenOnTransfer;
|
|
561
|
+
const externalTransferFailed = (_e = (_d = tokenOutProperties[getAddressLowerCase(currencyOut)]) === null || _d === void 0 ? void 0 : _d.tokenFeeResult) === null || _e === void 0 ? void 0 : _e.externalTransferFailed;
|
|
562
|
+
// We want to log the fee on transfer output tokens that we are taking fee or not
|
|
563
|
+
// Ideally the trade size (normalized in USD) would be ideal to log here, but we don't have spot price of output tokens here.
|
|
564
|
+
// We have to make sure token out is FOT with either buy/sell fee bps > 0
|
|
565
|
+
if (((_h = (_g = (_f = tokenOutProperties[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)) ||
|
|
566
|
+
((_l = (_k = (_j = tokenOutProperties[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))) {
|
|
567
|
+
if (feeTakenOnTransfer || externalTransferFailed) {
|
|
568
|
+
// also to be extra safe, in case of FOT with feeTakenOnTransfer or externalTransferFailed,
|
|
569
|
+
// we nullify the fee and flat fee to avoid any potential issues.
|
|
570
|
+
// although neither web nor wallet should use the calldata returned from routing/SOR
|
|
571
|
+
if ((swapConfig === null || swapConfig === void 0 ? void 0 : swapConfig.type) === SwapType.UNIVERSAL_ROUTER) {
|
|
572
|
+
swapConfig.fee = undefined;
|
|
573
|
+
swapConfig.flatFee = undefined;
|
|
574
|
+
}
|
|
575
|
+
metric.putMetric('TokenOutFeeOnTransferNotTakingFee', 1, MetricLoggerUnit.Count);
|
|
576
|
+
}
|
|
577
|
+
else {
|
|
578
|
+
metric.putMetric('TokenOutFeeOnTransferTakingFee', 1, MetricLoggerUnit.Count);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
if (tradeType === TradeType.EXACT_OUTPUT) {
|
|
582
|
+
const portionAmount = this.portionProvider.getPortionAmount(amount, tradeType, feeTakenOnTransfer, externalTransferFailed, swapConfig);
|
|
583
|
+
if (portionAmount && portionAmount.greaterThan(ZERO)) {
|
|
584
|
+
// In case of exact out swap, before we route, we need to make sure that the
|
|
585
|
+
// token out amount accounts for flat portion, and token in amount after the best swap route contains the token in equivalent of portion.
|
|
586
|
+
// 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.
|
|
587
|
+
// This is because instead of the swapper being responsible for the portion,
|
|
588
|
+
// the pool instead gets responsible for the portion.
|
|
589
|
+
// The addition below avoids that situation.
|
|
590
|
+
amount = amount.add(portionAmount);
|
|
591
|
+
}
|
|
592
|
+
const portionFewAmount = this.portionProvider.getPortionAmount(fewAmount, tradeType, feeTakenOnTransfer, externalTransferFailed, swapConfig);
|
|
593
|
+
if (portionFewAmount && portionFewAmount.greaterThan(ZERO)) {
|
|
594
|
+
// In case of exact out swap, before we route, we need to make sure that the
|
|
595
|
+
// token out few amount accounts for flat portion, and token in few amount after the best swap route contains the token in equivalent of portion.
|
|
596
|
+
// 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.
|
|
597
|
+
// This is because instead of the swapper being responsible for the portion,
|
|
598
|
+
// the pool instead gets responsible for the portion.
|
|
599
|
+
// The addition below avoids that situation.
|
|
600
|
+
fewAmount = fewAmount.add(portionFewAmount.wrapped);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
metric.setProperty('chainId', this.chainId);
|
|
604
|
+
metric.setProperty('pair', `${currencyIn.symbol}/${currencyOut.symbol}`);
|
|
605
|
+
metric.setProperty('tokenIn', getAddress(currencyIn));
|
|
606
|
+
metric.setProperty('tokenOut', getAddress(currencyOut));
|
|
607
|
+
metric.setProperty('tradeType', tradeType === TradeType.EXACT_INPUT ? 'ExactIn' : 'ExactOut');
|
|
608
|
+
metric.putMetric(`QuoteRequestedForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
609
|
+
// Get a block number to specify in all our calls. Ensures data we fetch from chain is
|
|
610
|
+
// from the same block.
|
|
611
|
+
const blockNumber = (_m = partialRoutingConfig.blockNumber) !== null && _m !== void 0 ? _m : this.getBlockNumberPromise();
|
|
612
|
+
const routingConfig = _.merge({
|
|
613
|
+
// These settings could be changed by the partialRoutingConfig
|
|
614
|
+
useCachedRoutes: true,
|
|
615
|
+
writeToCachedRoutes: true,
|
|
616
|
+
optimisticCachedRoutes: false,
|
|
617
|
+
}, DEFAULT_ROUTING_CONFIG_BY_CHAIN(this.chainId), partialRoutingConfig, { blockNumber });
|
|
618
|
+
if (routingConfig.debugRouting) {
|
|
619
|
+
log.warn(`Finalized routing config is ${JSON.stringify(routingConfig)}`);
|
|
620
|
+
}
|
|
621
|
+
const gasPriceWei = await this.getGasPriceWei(await blockNumber, await partialRoutingConfig.blockNumber);
|
|
622
|
+
// const gasTokenAccessor = await this.tokenProvider.getTokens([routingConfig.gasToken!]);
|
|
623
|
+
const gasToken = routingConfig.gasToken
|
|
624
|
+
? (await this.tokenProvider.getTokens([routingConfig.gasToken])).getTokenByAddress(routingConfig.gasToken)
|
|
625
|
+
: undefined;
|
|
626
|
+
const providerConfig = {
|
|
627
|
+
...routingConfig,
|
|
628
|
+
blockNumber,
|
|
629
|
+
additionalGasOverhead: NATIVE_OVERHEAD(this.chainId, amount.currency, quoteCurrency),
|
|
630
|
+
gasToken,
|
|
631
|
+
externalTransferFailed,
|
|
632
|
+
feeTakenOnTransfer,
|
|
633
|
+
};
|
|
634
|
+
startTimer('alpha-router.route.getGasModels');
|
|
635
|
+
const { ringFewV2GasModel: ringFewV2GasModel, v2GasModel: v2GasModel, fewV2GasModel: fewV2GasModel, v3GasModel: v3GasModel, fewV3GasModel: fewV3GasModel, v4GasModel: v4GasModel, fewV4GasModel: fewV4GasModel, mixedRouteGasModel: mixedRouteGasModel, } = await this.getGasModels(gasPriceWei, amount.currency.wrapped, quoteCurrency.wrapped, providerConfig);
|
|
636
|
+
endTimer('alpha-router.route.getGasModels');
|
|
637
|
+
// Create a Set to sanitize the protocols input, a Set of undefined becomes an empty set,
|
|
638
|
+
// Then create an Array from the values of that Set.
|
|
639
|
+
const protocols = Array.from(new Set(routingConfig.protocols).values());
|
|
640
|
+
startTimer('alpha-router.route.getCacheMode');
|
|
641
|
+
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, quoteCurrency, tradeType, protocols)));
|
|
642
|
+
endTimer('alpha-router.route.getCacheMode');
|
|
643
|
+
// const fewCacheMode =
|
|
644
|
+
// routingConfig.overwriteCacheMode ??
|
|
645
|
+
// (await this.routeCachingProvider?.getCacheMode(
|
|
646
|
+
// this.chainId,
|
|
647
|
+
// fewAmount,
|
|
648
|
+
// fewQuoteToken!,
|
|
649
|
+
// tradeType,
|
|
650
|
+
// protocols
|
|
651
|
+
// ));
|
|
652
|
+
// Fetch CachedRoutes
|
|
653
|
+
let cachedRoutes;
|
|
654
|
+
// Fetch fewCachedRoutes
|
|
655
|
+
let fewCachedRoutes;
|
|
656
|
+
// Decide whether to use cached routes or not - If |enabledAndRequestedProtocolsMatch| is true we are good to use cached routes.
|
|
657
|
+
// In order to use cached routes, we need to have all enabled protocols specified in the request.
|
|
658
|
+
// By default, all protocols are enabled but for UniversalRouterVersion.V1_2, V4 is not.
|
|
659
|
+
// - ref: https://github.com/Uniswap/routing-api/blob/663b607d80d9249f85e7ab0925a611ec3701da2a/lib/util/supportedProtocolVersions.ts#L15
|
|
660
|
+
// So we take this into account when deciding whether to use cached routes or not.
|
|
661
|
+
// We only want to use cache if all enabled protocols are specified (V2,V3,V4? + MIXED). In any other case, use onchain path.
|
|
662
|
+
// - Cache is optimized for global search, not for specific protocol(s) search.
|
|
663
|
+
// For legacy systems (SWAP_ROUTER_02) or missing swapConfig, follow UniversalRouterVersion.V1_2 logic.
|
|
664
|
+
const availableProtocolsSet = new Set(Object.values(Protocol));
|
|
665
|
+
const requestedProtocolsSet = new Set(protocols);
|
|
666
|
+
const swapRouter = !swapConfig ||
|
|
667
|
+
swapConfig.type === SwapType.SWAP_ROUTER_02 ||
|
|
668
|
+
(swapConfig.type === SwapType.UNIVERSAL_ROUTER &&
|
|
669
|
+
swapConfig.version === UniversalRouterVersion.V1_2);
|
|
670
|
+
if (swapRouter) {
|
|
671
|
+
availableProtocolsSet.delete(Protocol.V4);
|
|
672
|
+
if (requestedProtocolsSet.has(Protocol.V4)) {
|
|
673
|
+
requestedProtocolsSet.delete(Protocol.V4);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
const enabledAndRequestedProtocolsMatch = availableProtocolsSet.size === requestedProtocolsSet.size &&
|
|
677
|
+
[...availableProtocolsSet].every((protocol) => requestedProtocolsSet.has(protocol));
|
|
678
|
+
// If the requested protocols do not match the enabled protocols, we need to set the hooks options to NO_HOOKS.
|
|
679
|
+
if (!requestedProtocolsSet.has(Protocol.V4)) {
|
|
680
|
+
routingConfig.hooksOptions = HooksOptions.NO_HOOKS;
|
|
681
|
+
}
|
|
682
|
+
// If hooksOptions not specified and it's not a swapRouter (i.e. Universal Router it is),
|
|
683
|
+
// we should also set it to HOOKS_INCLUSIVE, as this is default behavior even without hooksOptions.
|
|
684
|
+
if (!routingConfig.hooksOptions) {
|
|
685
|
+
routingConfig.hooksOptions = HooksOptions.HOOKS_INCLUSIVE;
|
|
686
|
+
}
|
|
687
|
+
log.debug('UniversalRouterVersion_CacheGate_Check', {
|
|
688
|
+
availableProtocolsSet: Array.from(availableProtocolsSet),
|
|
689
|
+
requestedProtocolsSet: Array.from(requestedProtocolsSet),
|
|
690
|
+
enabledAndRequestedProtocolsMatch,
|
|
691
|
+
swapConfigType: swapConfig === null || swapConfig === void 0 ? void 0 : swapConfig.type,
|
|
692
|
+
swapConfigUniversalRouterVersion: (swapConfig === null || swapConfig === void 0 ? void 0 : swapConfig.type) === SwapType.UNIVERSAL_ROUTER
|
|
693
|
+
? swapConfig === null || swapConfig === void 0 ? void 0 : swapConfig.version
|
|
694
|
+
: 'N/A',
|
|
695
|
+
});
|
|
696
|
+
startTimer('alpha-router.route.isAllowedToEnterCachedRoutes');
|
|
697
|
+
const isAllowedToEnterCachedRoutes = AlphaRouter.isAllowedToEnterCachedRoutes(routingConfig.intent, routingConfig.hooksOptions, swapRouter);
|
|
698
|
+
if (routingConfig.useCachedRoutes &&
|
|
699
|
+
cacheMode !== CacheMode.Darkmode &&
|
|
700
|
+
isAllowedToEnterCachedRoutes) {
|
|
701
|
+
if (enabledAndRequestedProtocolsMatch) {
|
|
702
|
+
if (protocols.includes(Protocol.V4) &&
|
|
703
|
+
(currencyIn.isNative || currencyOut.isNative)) {
|
|
704
|
+
const [wrappedNativeCachedRoutes, nativeCachedRoutes] = await Promise.all([
|
|
705
|
+
(_q = this.routeCachingProvider) === null || _q === void 0 ? void 0 : _q.getCachedRoute(this.chainId, CurrencyAmount.fromRawAmount(amount.currency.wrapped, amount.quotient), quoteCurrency.wrapped, tradeType, protocols, await blockNumber, routingConfig.optimisticCachedRoutes),
|
|
706
|
+
(_r = this.routeCachingProvider) === null || _r === void 0 ? void 0 : _r.getCachedRoute(this.chainId, amount, quoteCurrency, tradeType, [Protocol.V4], await blockNumber, routingConfig.optimisticCachedRoutes),
|
|
707
|
+
]);
|
|
708
|
+
if ((wrappedNativeCachedRoutes &&
|
|
709
|
+
(wrappedNativeCachedRoutes === null || wrappedNativeCachedRoutes === void 0 ? void 0 : wrappedNativeCachedRoutes.routes.length) > 0) ||
|
|
710
|
+
(nativeCachedRoutes && (nativeCachedRoutes === null || nativeCachedRoutes === void 0 ? void 0 : nativeCachedRoutes.routes.length) > 0)) {
|
|
711
|
+
cachedRoutes = new CachedRoutes({
|
|
712
|
+
routes: [
|
|
713
|
+
...((_s = nativeCachedRoutes === null || nativeCachedRoutes === void 0 ? void 0 : nativeCachedRoutes.routes) !== null && _s !== void 0 ? _s : []),
|
|
714
|
+
...((_t = wrappedNativeCachedRoutes === null || wrappedNativeCachedRoutes === void 0 ? void 0 : wrappedNativeCachedRoutes.routes) !== null && _t !== void 0 ? _t : []),
|
|
715
|
+
],
|
|
716
|
+
chainId: this.chainId,
|
|
717
|
+
currencyIn: currencyIn,
|
|
718
|
+
currencyOut: currencyOut,
|
|
719
|
+
protocolsCovered: protocols,
|
|
720
|
+
blockNumber: await blockNumber,
|
|
721
|
+
tradeType: tradeType,
|
|
722
|
+
originalAmount: (_v = (_u = wrappedNativeCachedRoutes === null || wrappedNativeCachedRoutes === void 0 ? void 0 : wrappedNativeCachedRoutes.originalAmount) !== null && _u !== void 0 ? _u : nativeCachedRoutes === null || nativeCachedRoutes === void 0 ? void 0 : nativeCachedRoutes.originalAmount) !== null && _v !== void 0 ? _v : amount.quotient.toString(),
|
|
723
|
+
blocksToLive: (_x = (_w = wrappedNativeCachedRoutes === null || wrappedNativeCachedRoutes === void 0 ? void 0 : wrappedNativeCachedRoutes.blocksToLive) !== null && _w !== void 0 ? _w : nativeCachedRoutes === null || nativeCachedRoutes === void 0 ? void 0 : nativeCachedRoutes.blocksToLive) !== null && _x !== void 0 ? _x : DEFAULT_BLOCKS_TO_LIVE[this.chainId],
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
else {
|
|
728
|
+
cachedRoutes = await ((_y = this.routeCachingProvider) === null || _y === void 0 ? void 0 : _y.getCachedRoute(this.chainId, amount, quoteCurrency, tradeType, protocols, await blockNumber, routingConfig.optimisticCachedRoutes));
|
|
729
|
+
fewCachedRoutes = await ((_z = this.routeCachingProvider) === null || _z === void 0 ? void 0 : _z.getCachedRoute(this.chainId, fewAmount, fewQuoteToken, tradeType, protocols, await blockNumber, routingConfig.optimisticCachedRoutes));
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
endTimer('alpha-router.route.isAllowedToEnterCachedRoutes');
|
|
734
|
+
if (shouldWipeoutCachedRoutes(cachedRoutes, routingConfig)) {
|
|
735
|
+
cachedRoutes = undefined;
|
|
736
|
+
}
|
|
737
|
+
if (shouldWipeoutCachedRoutes(fewCachedRoutes, routingConfig)) {
|
|
738
|
+
fewCachedRoutes = undefined;
|
|
739
|
+
}
|
|
740
|
+
metric.putMetric(routingConfig.useCachedRoutes
|
|
741
|
+
? 'GetQuoteUsingCachedRoutes'
|
|
742
|
+
: 'GetQuoteNotUsingCachedRoutes', 1, MetricLoggerUnit.Count);
|
|
743
|
+
startTimer('alpha-router.route.getCachedRoute');
|
|
744
|
+
if (cacheMode &&
|
|
745
|
+
routingConfig.useCachedRoutes &&
|
|
746
|
+
cacheMode !== CacheMode.Darkmode &&
|
|
747
|
+
!cachedRoutes) {
|
|
748
|
+
metric.putMetric(`GetCachedRoute_miss_${cacheMode}`, 1, MetricLoggerUnit.Count);
|
|
749
|
+
log.info({
|
|
750
|
+
currencyIn: currencyIn.symbol,
|
|
751
|
+
currencyInAddress: getAddress(currencyIn),
|
|
752
|
+
currencyOut: currencyOut.symbol,
|
|
753
|
+
currencyOutAddress: getAddress(currencyOut),
|
|
754
|
+
cacheMode,
|
|
755
|
+
amount: amount.toExact(),
|
|
756
|
+
chainId: this.chainId,
|
|
757
|
+
tradeType: this.tradeTypeStr(tradeType),
|
|
758
|
+
}, `GetCachedRoute miss ${cacheMode} for ${this.tokenPairSymbolTradeTypeChainId(currencyIn, currencyOut, tradeType)}`);
|
|
759
|
+
}
|
|
760
|
+
else if (cachedRoutes && routingConfig.useCachedRoutes) {
|
|
761
|
+
metric.putMetric(`GetCachedRoute_hit_${cacheMode}`, 1, MetricLoggerUnit.Count);
|
|
762
|
+
log.info({
|
|
763
|
+
currencyIn: currencyIn.symbol,
|
|
764
|
+
currencyInAddress: getAddress(currencyIn),
|
|
765
|
+
currencyOut: currencyOut.symbol,
|
|
766
|
+
currencyOutAddress: getAddress(currencyOut),
|
|
767
|
+
cacheMode,
|
|
768
|
+
amount: amount.toExact(),
|
|
769
|
+
chainId: this.chainId,
|
|
770
|
+
tradeType: this.tradeTypeStr(tradeType),
|
|
771
|
+
}, `GetCachedRoute hit ${cacheMode} for ${this.tokenPairSymbolTradeTypeChainId(currencyIn, currencyOut, tradeType)}`);
|
|
772
|
+
}
|
|
773
|
+
endTimer('alpha-router.route.getCachedRoute');
|
|
774
|
+
startTimer('alpha-router.route.getSwapRouteFromCache');
|
|
775
|
+
let swapRouteFromCachePromise = Promise.resolve(null);
|
|
776
|
+
if (cachedRoutes) {
|
|
777
|
+
swapRouteFromCachePromise = this.getSwapRouteFromCache(currencyIn, currencyOut, cachedRoutes, await blockNumber, amount, fewAmount, quoteCurrency, fewQuoteToken, tradeType, routingConfig, v3GasModel, v4GasModel, mixedRouteGasModel, gasPriceWei, v2GasModel, swapConfig, providerConfig);
|
|
778
|
+
}
|
|
779
|
+
endTimer('alpha-router.route.getSwapRouteFromCache');
|
|
780
|
+
startTimer('alpha-router.route.getUniswapFewTokenSwapRouteFromCache');
|
|
781
|
+
let uniswapFewSwapRouteFromCachePromise = Promise.resolve(null);
|
|
782
|
+
if (fewCachedRoutes) {
|
|
783
|
+
uniswapFewSwapRouteFromCachePromise = this.getUniswapFewTokenSwapRouteFromCache(fewTokenIn, fewTokenOut, fewCachedRoutes, await blockNumber, amount, fewAmount, quoteCurrency, fewQuoteToken, tradeType, routingConfig, v3GasModel, v4GasModel, mixedRouteGasModel, gasPriceWei, v2GasModel, swapConfig, providerConfig);
|
|
784
|
+
}
|
|
785
|
+
endTimer('alpha-router.route.getUniswapFewTokenSwapRouteFromCache');
|
|
786
|
+
startTimer('alpha-router.route.getSwapRouteFromChain');
|
|
787
|
+
let swapRouteFromChainPromise = Promise.resolve(null);
|
|
788
|
+
if (!cachedRoutes || cacheMode !== CacheMode.Livemode) {
|
|
789
|
+
swapRouteFromChainPromise = this.getSwapRouteFromChain(amount, fewAmount, currencyIn, fewTokenIn, currencyOut, fewTokenOut, protocols, quoteCurrency, fewQuoteToken, tradeType, routingConfig, v3GasModel, v4GasModel, mixedRouteGasModel, gasPriceWei, v2GasModel, ringFewV2GasModel, swapConfig, providerConfig);
|
|
790
|
+
}
|
|
791
|
+
endTimer('alpha-router.route.getSwapRouteFromChain');
|
|
792
|
+
startTimer('alpha-router.route.getUniswapFewTokenSwapRouteFromChain');
|
|
793
|
+
let uniswapFewSwapRouteFromChainPromise = Promise.resolve(null);
|
|
794
|
+
if (!cachedRoutes || cacheMode !== CacheMode.Livemode) {
|
|
795
|
+
//cachedRoutes is undefined
|
|
796
|
+
uniswapFewSwapRouteFromChainPromise = this.getUniswapFewTokenSwapRouteFromChain(amount, fewAmount, currencyIn, fewTokenIn, currencyOut, fewTokenOut, protocols, quoteCurrency, fewQuoteToken, tradeType, routingConfig,
|
|
797
|
+
// v3GasModel,
|
|
798
|
+
fewV3GasModel,
|
|
799
|
+
// v4GasModel,
|
|
800
|
+
fewV4GasModel, mixedRouteGasModel, gasPriceWei, v2GasModel, fewV2GasModel,
|
|
801
|
+
// ringFewV2GasModel,
|
|
802
|
+
providerConfig);
|
|
803
|
+
}
|
|
804
|
+
endTimer('alpha-router.route.getUniswapFewTokenSwapRouteFromChain');
|
|
805
|
+
// let swapRouteFromRingFewChainPromise: Promise<BestSwapRoute | null> =
|
|
806
|
+
// Promise.resolve(null);
|
|
807
|
+
// if (!fewCachedRoutes || cacheMode !== CacheMode.Livemode) {
|
|
808
|
+
// swapRouteFromRingFewChainPromise = this.getSwapRouteFromChain(
|
|
809
|
+
// fewAmount!,
|
|
810
|
+
// fewTokenIn!,
|
|
811
|
+
// fewTokenOut!,
|
|
812
|
+
// protocols,
|
|
813
|
+
// fewQuoteToken!,
|
|
814
|
+
// tradeType,
|
|
815
|
+
// routingConfig,
|
|
816
|
+
// v3GasModel,
|
|
817
|
+
// v4GasModel,
|
|
818
|
+
// mixedRouteGasModel,
|
|
819
|
+
// gasPriceWei,
|
|
820
|
+
// ringFewV2GasModel,
|
|
821
|
+
// swapConfig,
|
|
822
|
+
// providerConfig
|
|
823
|
+
// );
|
|
824
|
+
// }
|
|
825
|
+
startTimer('alpha-router.route.getSwapRouteFromCache_Chain');
|
|
826
|
+
const [swapRouteFromCache, uniswapFewSwapRouteFromCache,] = await Promise.all([
|
|
827
|
+
swapRouteFromCachePromise,
|
|
828
|
+
uniswapFewSwapRouteFromCachePromise
|
|
829
|
+
]);
|
|
830
|
+
const [swapRouteFromChainRaw, uniswapFewSwapRouteFromChainRaw,] = await Promise.all([
|
|
831
|
+
swapRouteFromChainPromise,
|
|
832
|
+
uniswapFewSwapRouteFromChainPromise
|
|
833
|
+
]);
|
|
834
|
+
const [percents] = this.getAmountDistribution(amount, routingConfig);
|
|
835
|
+
const allRoutesWithValidQuotes = [...(swapRouteFromChainRaw || []), ...(uniswapFewSwapRouteFromChainRaw || [])];
|
|
836
|
+
const swapRouteFromChain = await getBestSwapRoute(amount, percents, allRoutesWithValidQuotes, tradeType, this.chainId, routingConfig, this.portionProvider, v2GasModel, v3GasModel, v4GasModel, swapConfig, providerConfig);
|
|
837
|
+
if (swapRouteFromChain) {
|
|
838
|
+
// this.emitPoolSelectionMetrics(
|
|
839
|
+
// swapRouteFromChain,
|
|
840
|
+
// [],
|
|
841
|
+
// currencyIn,
|
|
842
|
+
// currencyOut
|
|
843
|
+
// );
|
|
844
|
+
}
|
|
845
|
+
endTimer('alpha-router.route.getSwapRouteFromCache_Chain');
|
|
846
|
+
let swapRouteRaw;
|
|
847
|
+
let hitsCachedRoute = false;
|
|
848
|
+
if (cacheMode === CacheMode.Livemode && swapRouteFromCache) {
|
|
849
|
+
log.info(`CacheMode is ${cacheMode}, and we are using swapRoute from cache`);
|
|
850
|
+
hitsCachedRoute = true;
|
|
851
|
+
swapRouteRaw = swapRouteFromCache;
|
|
852
|
+
}
|
|
853
|
+
else {
|
|
854
|
+
log.info(`CacheMode is ${cacheMode}, and we are using materialized swapRoute`);
|
|
855
|
+
swapRouteRaw = swapRouteFromChain;
|
|
856
|
+
}
|
|
857
|
+
let uniswapFewSwapRouteRaw;
|
|
858
|
+
if (cacheMode === CacheMode.Livemode && uniswapFewSwapRouteFromCache) {
|
|
859
|
+
log.info(`CacheMode is ${cacheMode}, and we are using swapRoute from cache`);
|
|
860
|
+
hitsCachedRoute = true;
|
|
861
|
+
uniswapFewSwapRouteRaw = uniswapFewSwapRouteFromCache;
|
|
862
|
+
}
|
|
863
|
+
else {
|
|
864
|
+
log.info(`CacheMode is ${cacheMode}, and we are using materialized swapRoute`);
|
|
865
|
+
uniswapFewSwapRouteRaw = swapRouteFromChain;
|
|
866
|
+
}
|
|
867
|
+
// let ringFewSwapRouteRaw: BestSwapRoute | null;
|
|
868
|
+
// let hitsCachedRingFewSRoute = false;
|
|
869
|
+
// if (cacheMode === CacheMode.Livemode && swapRouteFromRingFewCache) {
|
|
870
|
+
// log.info(
|
|
871
|
+
// `CacheMode is ${cacheMode}, and we are using swapRoute from cache`
|
|
872
|
+
// );
|
|
873
|
+
// hitsCachedRingFewSRoute = true;
|
|
874
|
+
// ringFewSwapRouteRaw = swapRouteFromRingFewCache;
|
|
875
|
+
// } else {
|
|
876
|
+
// log.info(
|
|
877
|
+
// `CacheMode is ${cacheMode}, and we are using materialized swapRoute`
|
|
878
|
+
// );
|
|
879
|
+
// ringFewSwapRouteRaw = swapRouteFromRingFewChain;
|
|
880
|
+
// }
|
|
881
|
+
startTimer('alpha-router.route.tapcompareCachedRoute');
|
|
882
|
+
if (cacheMode === CacheMode.Tapcompare &&
|
|
883
|
+
swapRouteFromCache &&
|
|
884
|
+
swapRouteFromChain) {
|
|
885
|
+
const quoteDiff = swapRouteFromChain.quote.subtract(swapRouteFromCache.quote);
|
|
886
|
+
const quoteGasAdjustedDiff = swapRouteFromChain.quoteGasAdjusted.subtract(swapRouteFromCache.quoteGasAdjusted);
|
|
887
|
+
const gasUsedDiff = swapRouteFromChain.estimatedGasUsed.sub(swapRouteFromCache.estimatedGasUsed);
|
|
888
|
+
// Only log if quoteDiff is different from 0, or if quoteGasAdjustedDiff and gasUsedDiff are both different from 0
|
|
889
|
+
if (!quoteDiff.equalTo(0) ||
|
|
890
|
+
!(quoteGasAdjustedDiff.equalTo(0) || gasUsedDiff.eq(0))) {
|
|
891
|
+
try {
|
|
892
|
+
// Calculates the percentage of the difference with respect to the quoteFromChain (not from cache)
|
|
893
|
+
const misquotePercent = quoteGasAdjustedDiff
|
|
894
|
+
.divide(swapRouteFromChain.quoteGasAdjusted)
|
|
895
|
+
.multiply(100);
|
|
896
|
+
metric.putMetric(`TapcompareCachedRoute_quoteGasAdjustedDiffPercent`, Number(misquotePercent.toExact()), MetricLoggerUnit.Percent);
|
|
897
|
+
log.warn({
|
|
898
|
+
quoteFromChain: swapRouteFromChain.quote.toExact(),
|
|
899
|
+
quoteFromCache: swapRouteFromCache.quote.toExact(),
|
|
900
|
+
quoteDiff: quoteDiff.toExact(),
|
|
901
|
+
quoteGasAdjustedFromChain: swapRouteFromChain.quoteGasAdjusted.toExact(),
|
|
902
|
+
quoteGasAdjustedFromCache: swapRouteFromCache.quoteGasAdjusted.toExact(),
|
|
903
|
+
quoteGasAdjustedDiff: quoteGasAdjustedDiff.toExact(),
|
|
904
|
+
gasUsedFromChain: swapRouteFromChain.estimatedGasUsed.toString(),
|
|
905
|
+
gasUsedFromCache: swapRouteFromCache.estimatedGasUsed.toString(),
|
|
906
|
+
gasUsedDiff: gasUsedDiff.toString(),
|
|
907
|
+
routesFromChain: swapRouteFromChain.routes.toString(),
|
|
908
|
+
routesFromCache: swapRouteFromCache.routes.toString(),
|
|
909
|
+
amount: amount.toExact(),
|
|
910
|
+
originalAmount: cachedRoutes === null || cachedRoutes === void 0 ? void 0 : cachedRoutes.originalAmount,
|
|
911
|
+
pair: this.tokenPairSymbolTradeTypeChainId(currencyIn, currencyOut, tradeType),
|
|
912
|
+
blockNumber,
|
|
913
|
+
}, `Comparing quotes between Chain and Cache for ${this.tokenPairSymbolTradeTypeChainId(currencyIn, currencyOut, tradeType)}`);
|
|
914
|
+
}
|
|
915
|
+
catch (error) {
|
|
916
|
+
// This is in response to the 'division by zero' error
|
|
917
|
+
// during https://uniswapteam.slack.com/archives/C059TGEC57W/p1723997015399579
|
|
918
|
+
if (error instanceof RangeError &&
|
|
919
|
+
error.message.includes('Division by zero')) {
|
|
920
|
+
log.error({
|
|
921
|
+
quoteGasAdjustedDiff: quoteGasAdjustedDiff.toExact(),
|
|
922
|
+
swapRouteFromChainQuoteGasAdjusted: swapRouteFromChain.quoteGasAdjusted.toExact(),
|
|
923
|
+
}, 'Error calculating misquote percent');
|
|
924
|
+
metric.putMetric(`TapcompareCachedRoute_quoteGasAdjustedDiffPercent_divzero`, 1, MetricLoggerUnit.Count);
|
|
925
|
+
}
|
|
926
|
+
// Log but don't throw here - this is only for logging.
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
endTimer('alpha-router.route.tapcompareCachedRoute');
|
|
931
|
+
if (!swapRouteRaw && !uniswapFewSwapRouteRaw) {
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
// Use either swapRouteRaw or uniswapFewSwapRouteRaw as the source of route data
|
|
935
|
+
// We already checked above that at least one is non-null, so we can safely assert non-null
|
|
936
|
+
const routeSource = swapRouteRaw;
|
|
937
|
+
// Now we can safely destructure since routeSource is guaranteed to be non-null
|
|
938
|
+
const { quote, quoteGasAdjusted, estimatedGasUsed, routes: routeAmounts, estimatedGasUsedQuoteToken, estimatedGasUsedUSD, estimatedGasUsedGasToken, } = routeSource;
|
|
939
|
+
metric.putMetric(`QuoteFoundForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
940
|
+
// Build Trade object that represents the optimal swap.
|
|
941
|
+
const trade = buildTrade(currencyIn, fewTokenIn, currencyOut, fewTokenOut, tradeType, routeAmounts);
|
|
942
|
+
let methodParameters;
|
|
943
|
+
// If user provided recipient, deadline etc. we also generate the calldata required to execute
|
|
944
|
+
// the swap and return it too.
|
|
945
|
+
if (swapConfig) {
|
|
946
|
+
methodParameters = buildSwapMethodParameters(trade, swapConfig, this.chainId);
|
|
947
|
+
}
|
|
948
|
+
const tokenOutAmount = tradeType === TradeType.EXACT_OUTPUT
|
|
949
|
+
? originalAmount // we need to pass in originalAmount instead of amount, because amount already added portionAmount in case of exact out swap
|
|
950
|
+
: quote;
|
|
951
|
+
const portionAmount = this.portionProvider.getPortionAmount(tokenOutAmount, tradeType, feeTakenOnTransfer, externalTransferFailed, swapConfig);
|
|
952
|
+
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
|
|
953
|
+
portionAmount);
|
|
954
|
+
// we need to correct quote and quote gas adjusted for exact output when portion is part of the exact out swap
|
|
955
|
+
const correctedQuote = this.portionProvider.getQuote(tradeType, quote, portionQuoteAmount);
|
|
956
|
+
const correctedQuoteGasAdjusted = this.portionProvider.getQuoteGasAdjusted(tradeType, quoteGasAdjusted, portionQuoteAmount);
|
|
957
|
+
const quoteGasAndPortionAdjusted = this.portionProvider.getQuoteGasAndPortionAdjusted(tradeType, quoteGasAdjusted, portionAmount);
|
|
958
|
+
const swapRoute = {
|
|
959
|
+
quote: correctedQuote,
|
|
960
|
+
quoteGasAdjusted: correctedQuoteGasAdjusted,
|
|
961
|
+
estimatedGasUsed,
|
|
962
|
+
estimatedGasUsedQuoteToken,
|
|
963
|
+
estimatedGasUsedUSD,
|
|
964
|
+
estimatedGasUsedGasToken,
|
|
965
|
+
gasPriceWei,
|
|
966
|
+
route: routeAmounts,
|
|
967
|
+
trade,
|
|
968
|
+
methodParameters,
|
|
969
|
+
blockNumber: BigNumber.from(await blockNumber),
|
|
970
|
+
hitsCachedRoute: hitsCachedRoute,
|
|
971
|
+
portionAmount: portionAmount,
|
|
972
|
+
quoteGasAndPortionAdjusted: quoteGasAndPortionAdjusted,
|
|
973
|
+
};
|
|
974
|
+
if (swapConfig &&
|
|
975
|
+
swapConfig.simulate &&
|
|
976
|
+
methodParameters &&
|
|
977
|
+
methodParameters.calldata) {
|
|
978
|
+
if (!this.simulator) {
|
|
979
|
+
throw new Error('Simulator not initialized!');
|
|
980
|
+
}
|
|
981
|
+
log.info(JSON.stringify({ swapConfig, methodParameters, providerConfig }, null, 2), `Starting simulation`);
|
|
982
|
+
const fromAddress = swapConfig.simulate.fromAddress;
|
|
983
|
+
const beforeSimulate = Date.now();
|
|
984
|
+
const swapRouteWithSimulation = await this.simulator.simulate(fromAddress, swapConfig, swapRoute, amount,
|
|
985
|
+
// Quote will be in WETH even if quoteCurrency is ETH
|
|
986
|
+
// So we init a new CurrencyAmount object here
|
|
987
|
+
CurrencyAmount.fromRawAmount(quoteCurrency, quote.quotient.toString()), providerConfig);
|
|
988
|
+
metric.putMetric('SimulateTransaction', Date.now() - beforeSimulate, MetricLoggerUnit.Milliseconds);
|
|
989
|
+
if (routingConfig.intent === INTENT.CACHING) {
|
|
990
|
+
if (swapRouteWithSimulation.simulationStatus) {
|
|
991
|
+
await this.performCachingIntention(currencyIn, currencyOut, tradeType, amount, protocols, await blockNumber, routingConfig, swapRouteWithSimulation.simulationStatus, swapRouteWithSimulation.route);
|
|
992
|
+
}
|
|
993
|
+
else {
|
|
994
|
+
log.info('Simulation status is null');
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return swapRouteWithSimulation;
|
|
998
|
+
}
|
|
999
|
+
getPerfReport();
|
|
1000
|
+
return swapRoute;
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Performs the caching intention for the given simulation status and route.
|
|
1004
|
+
*
|
|
1005
|
+
* @param currencyIn the currency in
|
|
1006
|
+
* @param currencyOut the currency out
|
|
1007
|
+
* @param tradeType the trade type
|
|
1008
|
+
* @param amount the amount
|
|
1009
|
+
* @param protocols the protocols
|
|
1010
|
+
* @param blockNumber the block number
|
|
1011
|
+
* @param routingConfig the routing config
|
|
1012
|
+
* @param simulationStatus the simulation status
|
|
1013
|
+
* @param simulationRoute the simulation route
|
|
1014
|
+
*/
|
|
1015
|
+
async performCachingIntention(currencyIn, currencyOut, tradeType, amount, protocols, blockNumber, routingConfig, simulationStatus, simulationRoute) {
|
|
1016
|
+
// due to fire and forget nature, we already take note that we should set new cached routes during the new path
|
|
1017
|
+
metric.putMetric(`SetCachedRoute_NewPath`, 1, MetricLoggerUnit.Count);
|
|
1018
|
+
log.info(simulationStatus, 'Simulation status');
|
|
1019
|
+
if (this.shouldCacheRoute(simulationStatus)) {
|
|
1020
|
+
const routesToCache = CachedRoutes.fromRoutesWithValidQuotes(simulationRoute, this.chainId, currencyIn, currencyOut, protocols.sort(), blockNumber, tradeType, amount.toExact());
|
|
1021
|
+
await this.setCachedRoutesAndLog(amount, currencyIn, currencyOut, tradeType, 'SetCachedRoute_NewPath', routesToCache, routingConfig.cachedRoutesRouteIds);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* @param simulationStatus the status of the simulation
|
|
1026
|
+
* @returns true if the route should be cached, false otherwise
|
|
1027
|
+
*/
|
|
1028
|
+
shouldCacheRoute(simulationStatus) {
|
|
1029
|
+
// Do not cache the route for the following reasons:
|
|
1030
|
+
// 1. failed when tenderly sim failed for unknown reason
|
|
1031
|
+
// 2. slippage since we know swap is bound to fail
|
|
1032
|
+
// 3. transfer from failed since we know swap is bound to fail
|
|
1033
|
+
return (simulationStatus !== SimulationStatus.Failed &&
|
|
1034
|
+
simulationStatus !== SimulationStatus.SlippageTooLow &&
|
|
1035
|
+
simulationStatus !== SimulationStatus.TransferFromFailed);
|
|
1036
|
+
}
|
|
1037
|
+
async setCachedRoutesAndLog(amount, currencyIn, currencyOut, tradeType, metricsPrefix, routesToCache, cachedRoutesRouteIds) {
|
|
1038
|
+
var _a;
|
|
1039
|
+
if (routesToCache) {
|
|
1040
|
+
const cachedRoutesChanged = cachedRoutesRouteIds !== undefined &&
|
|
1041
|
+
// it's possible that top cached routes may be split routes,
|
|
1042
|
+
// so that we always serialize all the top 8 retrieved cached routes vs the top routes.
|
|
1043
|
+
!cachedRoutesRouteIds.startsWith(serializeRouteIds(routesToCache.routes.map((r) => r.routeId)));
|
|
1044
|
+
if (cachedRoutesChanged) {
|
|
1045
|
+
metric.putMetric('cachedRoutesChanged', 1, MetricLoggerUnit.Count);
|
|
1046
|
+
metric.putMetric(`cachedRoutesChanged_chainId${currencyIn.chainId}`, 1, MetricLoggerUnit.Count);
|
|
1047
|
+
metric.putMetric(`cachedRoutesChanged_chainId${currencyOut.chainId}_pair${currencyIn.symbol}${currencyOut.symbol}`, 1, MetricLoggerUnit.Count);
|
|
1048
|
+
}
|
|
1049
|
+
else {
|
|
1050
|
+
metric.putMetric('cachedRoutesNotChanged', 1, MetricLoggerUnit.Count);
|
|
1051
|
+
metric.putMetric(`cachedRoutesNotChanged_chainId${currencyIn.chainId}`, 1, MetricLoggerUnit.Count);
|
|
1052
|
+
metric.putMetric(`cachedRoutesNotChanged_chainId${currencyOut.chainId}_pair${currencyIn.symbol}${currencyOut.symbol}`, 1, MetricLoggerUnit.Count);
|
|
1053
|
+
}
|
|
1054
|
+
await ((_a = this.routeCachingProvider) === null || _a === void 0 ? void 0 : _a.setCachedRoute(routesToCache, amount).then((success) => {
|
|
1055
|
+
const status = success ? 'success' : 'rejected';
|
|
1056
|
+
metric.putMetric(`${metricsPrefix}_${status}`, 1, MetricLoggerUnit.Count);
|
|
1057
|
+
}).catch((reason) => {
|
|
1058
|
+
log.error({
|
|
1059
|
+
reason: reason,
|
|
1060
|
+
tokenPair: this.tokenPairSymbolTradeTypeChainId(currencyIn, currencyOut, tradeType),
|
|
1061
|
+
}, `SetCachedRoute failure`);
|
|
1062
|
+
metric.putMetric(`${metricsPrefix}_failure`, 1, MetricLoggerUnit.Count);
|
|
1063
|
+
}));
|
|
1064
|
+
}
|
|
1065
|
+
else {
|
|
1066
|
+
metric.putMetric(`${metricsPrefix}_unnecessary`, 1, MetricLoggerUnit.Count);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
async getSwapRouteFromCache(currencyIn, currencyOut, cachedRoutes, blockNumber, amount, fewAmount, quoteCurrency, fewQuoteToken, tradeType, routingConfig, v3GasModel, v4GasModel, mixedRouteGasModel, gasPriceWei, v2GasModel, swapConfig, providerConfig) {
|
|
1070
|
+
var _a, _c, _d, _e, _f, _g;
|
|
1071
|
+
const tokenPairProperties = await this.tokenPropertiesProvider.getTokensProperties([currencyIn, currencyOut], providerConfig);
|
|
1072
|
+
const sellTokenIsFot = (_d = (_c = (_a = tokenPairProperties[getAddressLowerCase(currencyIn)]) === 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);
|
|
1073
|
+
const buyTokenIsFot = (_g = (_f = (_e = tokenPairProperties[getAddressLowerCase(currencyOut)]) === 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);
|
|
1074
|
+
const fotInDirectSwap = sellTokenIsFot || buyTokenIsFot;
|
|
1075
|
+
log.info({
|
|
1076
|
+
protocols: cachedRoutes.protocolsCovered,
|
|
1077
|
+
tradeType: cachedRoutes.tradeType,
|
|
1078
|
+
cachedBlockNumber: cachedRoutes.blockNumber,
|
|
1079
|
+
quoteBlockNumber: blockNumber,
|
|
1080
|
+
}, 'Routing across CachedRoute');
|
|
1081
|
+
const quotePromises = [];
|
|
1082
|
+
const v4Routes = cachedRoutes.routes.filter((route) => route.protocol === Protocol.V4);
|
|
1083
|
+
const v3Routes = cachedRoutes.routes.filter((route) => route.protocol === Protocol.V3);
|
|
1084
|
+
const v2Routes = cachedRoutes.routes.filter((route) => route.protocol === Protocol.V2);
|
|
1085
|
+
const ringFewV2Routes = cachedRoutes.routes.filter((route) => route.protocol === Protocol.FEWV2);
|
|
1086
|
+
const mixedRoutes = cachedRoutes.routes.filter((route) => route.protocol === Protocol.MIXED);
|
|
1087
|
+
let percents;
|
|
1088
|
+
let amounts;
|
|
1089
|
+
if (cachedRoutes.routes.length > 1) {
|
|
1090
|
+
// If we have more than 1 route, we will quote the different percents for it, following the regular process
|
|
1091
|
+
[percents, amounts] = this.getAmountDistribution(amount, routingConfig);
|
|
1092
|
+
}
|
|
1093
|
+
else if (cachedRoutes.routes.length == 1) {
|
|
1094
|
+
[percents, amounts] = [[100], [amount]];
|
|
1095
|
+
}
|
|
1096
|
+
else {
|
|
1097
|
+
// In this case this means that there's no route, so we return null
|
|
1098
|
+
return Promise.resolve(null);
|
|
1099
|
+
}
|
|
1100
|
+
let fewPercents;
|
|
1101
|
+
let fewAmounts;
|
|
1102
|
+
if (cachedRoutes.routes.length > 1) {
|
|
1103
|
+
// If we have more than 1 route, we will quote the different percents for it, following the regular process
|
|
1104
|
+
[fewPercents, fewAmounts] = this.getAmountDistribution(fewAmount, routingConfig);
|
|
1105
|
+
}
|
|
1106
|
+
else if (cachedRoutes.routes.length == 1) {
|
|
1107
|
+
[fewPercents, fewAmounts] = [[100], [fewAmount]];
|
|
1108
|
+
}
|
|
1109
|
+
else {
|
|
1110
|
+
// In this case this means that there's no route, so we return null
|
|
1111
|
+
return Promise.resolve(null);
|
|
1112
|
+
}
|
|
1113
|
+
if (v4Routes.length > 0) {
|
|
1114
|
+
const v4RoutesFromCache = v4Routes.map((cachedRoute) => cachedRoute.route);
|
|
1115
|
+
metric.putMetric('SwapRouteFromCache_V4_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1116
|
+
const beforeGetQuotes = Date.now();
|
|
1117
|
+
quotePromises.push(this.v4Quoter
|
|
1118
|
+
.getQuotes(v4RoutesFromCache, amounts, percents, quoteCurrency, tradeType, routingConfig, undefined, v4GasModel)
|
|
1119
|
+
.then((result) => {
|
|
1120
|
+
metric.putMetric(`SwapRouteFromCache_V4_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1121
|
+
return result;
|
|
1122
|
+
}));
|
|
1123
|
+
}
|
|
1124
|
+
if (!fotInDirectSwap) {
|
|
1125
|
+
if (v3Routes.length > 0) {
|
|
1126
|
+
const v3RoutesFromCache = v3Routes.map((cachedRoute) => cachedRoute.route);
|
|
1127
|
+
metric.putMetric('SwapRouteFromCache_V3_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1128
|
+
const beforeGetQuotes = Date.now();
|
|
1129
|
+
quotePromises.push(this.v3Quoter
|
|
1130
|
+
.getQuotes(v3RoutesFromCache, amounts, percents, quoteCurrency.wrapped, tradeType, routingConfig, undefined, v3GasModel)
|
|
1131
|
+
.then((result) => {
|
|
1132
|
+
metric.putMetric(`SwapRouteFromCache_V3_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1133
|
+
return result;
|
|
1134
|
+
}));
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
if (v2Routes.length > 0) {
|
|
1138
|
+
const v2RoutesFromCache = v2Routes.map((cachedRoute) => cachedRoute.route);
|
|
1139
|
+
metric.putMetric('SwapRouteFromCache_V2_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1140
|
+
const beforeGetQuotes = Date.now();
|
|
1141
|
+
quotePromises.push(this.v2Quoter
|
|
1142
|
+
.refreshRoutesThenGetQuotes(cachedRoutes.currencyIn.wrapped, cachedRoutes.currencyOut.wrapped, v2RoutesFromCache, amounts, percents, quoteCurrency.wrapped, tradeType, routingConfig, gasPriceWei)
|
|
1143
|
+
.then((result) => {
|
|
1144
|
+
metric.putMetric(`SwapRouteFromCache_V2_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1145
|
+
return result;
|
|
1146
|
+
}));
|
|
1147
|
+
}
|
|
1148
|
+
if (ringFewV2Routes.length > 0) {
|
|
1149
|
+
const ringFewV2RoutesFromCache = ringFewV2Routes.map((cachedRoute) => cachedRoute.route);
|
|
1150
|
+
metric.putMetric('SwapRouteFromCache_RingFewV2_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1151
|
+
const beforeGetQuotes = Date.now();
|
|
1152
|
+
quotePromises.push(this.ringFewV2Quoter
|
|
1153
|
+
.refreshRoutesThenGetQuotes(cachedRoutes.currencyIn.wrapped, cachedRoutes.currencyOut.wrapped, ringFewV2RoutesFromCache, fewAmounts, fewPercents, fewQuoteToken.wrapped, tradeType, routingConfig, gasPriceWei)
|
|
1154
|
+
.then((result) => {
|
|
1155
|
+
metric.putMetric(`SwapRouteFromCache_RingFewV2_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1156
|
+
return result;
|
|
1157
|
+
}));
|
|
1158
|
+
}
|
|
1159
|
+
if (!fotInDirectSwap) {
|
|
1160
|
+
if (mixedRoutes.length > 0) {
|
|
1161
|
+
const mixedRoutesFromCache = mixedRoutes.map((cachedRoute) => cachedRoute.route);
|
|
1162
|
+
metric.putMetric('SwapRouteFromCache_Mixed_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1163
|
+
const beforeGetQuotes = Date.now();
|
|
1164
|
+
quotePromises.push(this.mixedQuoter
|
|
1165
|
+
.getQuotes(mixedRoutesFromCache, amounts, percents, quoteCurrency.wrapped, tradeType, routingConfig, undefined, mixedRouteGasModel)
|
|
1166
|
+
.then((result) => {
|
|
1167
|
+
metric.putMetric(`SwapRouteFromCache_Mixed_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1168
|
+
return result;
|
|
1169
|
+
}));
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
const getQuotesResults = await Promise.all(quotePromises);
|
|
1173
|
+
const allRoutesWithValidQuotes = _.flatMap(getQuotesResults, (quoteResult) => quoteResult.routesWithValidQuotes);
|
|
1174
|
+
return getBestSwapRoute(amount, percents, allRoutesWithValidQuotes, tradeType, this.chainId, routingConfig, this.portionProvider, v2GasModel, v3GasModel, v4GasModel, swapConfig, providerConfig);
|
|
1175
|
+
}
|
|
1176
|
+
async getUniswapFewTokenSwapRouteFromCache(fewTokenIn, fewTokenOut, fewCachedRoutes, blockNumber, amount, fewAmount, quoteCurrency, fewQuoteToken, tradeType, routingConfig, v3GasModel, v4GasModel, mixedRouteGasModel, gasPriceWei, v2GasModel, swapConfig, providerConfig) {
|
|
1177
|
+
var _a, _c, _d, _e, _f, _g;
|
|
1178
|
+
const tokenPairProperties = await this.tokenPropertiesProvider.getTokensProperties([fewTokenIn, fewTokenOut], providerConfig);
|
|
1179
|
+
const sellTokenIsFot = (_d = (_c = (_a = tokenPairProperties[getAddressLowerCase(fewTokenIn)]) === 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);
|
|
1180
|
+
const buyTokenIsFot = (_g = (_f = (_e = tokenPairProperties[getAddressLowerCase(fewTokenOut)]) === 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);
|
|
1181
|
+
const fotInDirectSwap = sellTokenIsFot || buyTokenIsFot;
|
|
1182
|
+
log.info({
|
|
1183
|
+
protocols: fewCachedRoutes.protocolsCovered,
|
|
1184
|
+
tradeType: fewCachedRoutes.tradeType,
|
|
1185
|
+
cachedBlockNumber: fewCachedRoutes.blockNumber,
|
|
1186
|
+
quoteBlockNumber: blockNumber,
|
|
1187
|
+
}, 'Routing across CachedRoute');
|
|
1188
|
+
const quotePromises = [];
|
|
1189
|
+
const v4Routes = fewCachedRoutes.routes.filter((route) => route.protocol === Protocol.V4);
|
|
1190
|
+
const v3Routes = fewCachedRoutes.routes.filter((route) => route.protocol === Protocol.V3);
|
|
1191
|
+
const v2Routes = fewCachedRoutes.routes.filter((route) => route.protocol === Protocol.V2);
|
|
1192
|
+
const ringFewV2Routes = fewCachedRoutes.routes.filter((route) => route.protocol === Protocol.FEWV2);
|
|
1193
|
+
const mixedRoutes = fewCachedRoutes.routes.filter((route) => route.protocol === Protocol.MIXED);
|
|
1194
|
+
let percents;
|
|
1195
|
+
let amounts;
|
|
1196
|
+
if (fewCachedRoutes.routes.length > 1) {
|
|
1197
|
+
// If we have more than 1 route, we will quote the different percents for it, following the regular process
|
|
1198
|
+
[percents, amounts] = this.getAmountDistribution(amount, routingConfig);
|
|
1199
|
+
}
|
|
1200
|
+
else if (fewCachedRoutes.routes.length == 1) {
|
|
1201
|
+
[percents, amounts] = [[100], [amount]];
|
|
1202
|
+
}
|
|
1203
|
+
else {
|
|
1204
|
+
// In this case this means that there's no route, so we return null
|
|
1205
|
+
return Promise.resolve(null);
|
|
1206
|
+
}
|
|
1207
|
+
let fewPercents;
|
|
1208
|
+
let fewAmounts;
|
|
1209
|
+
if (fewCachedRoutes.routes.length > 1) {
|
|
1210
|
+
// If we have more than 1 route, we will quote the different percents for it, following the regular process
|
|
1211
|
+
[fewPercents, fewAmounts] = this.getAmountDistribution(fewAmount, routingConfig);
|
|
1212
|
+
}
|
|
1213
|
+
else if (fewCachedRoutes.routes.length == 1) {
|
|
1214
|
+
[fewPercents, fewAmounts] = [[100], [fewAmount]];
|
|
1215
|
+
}
|
|
1216
|
+
else {
|
|
1217
|
+
// In this case this means that there's no route, so we return null
|
|
1218
|
+
return Promise.resolve(null);
|
|
1219
|
+
}
|
|
1220
|
+
if (v4Routes.length > 0) {
|
|
1221
|
+
const v4RoutesFromCache = v4Routes.map((cachedRoute) => cachedRoute.route);
|
|
1222
|
+
metric.putMetric('SwapRouteFromCache_V4_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1223
|
+
const beforeGetQuotes = Date.now();
|
|
1224
|
+
quotePromises.push(this.v4Quoter
|
|
1225
|
+
.getQuotes(v4RoutesFromCache, amounts, percents, quoteCurrency, tradeType, routingConfig, undefined, v4GasModel)
|
|
1226
|
+
.then((result) => {
|
|
1227
|
+
metric.putMetric(`SwapRouteFromCache_V4_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1228
|
+
return result;
|
|
1229
|
+
}));
|
|
1230
|
+
}
|
|
1231
|
+
if (!fotInDirectSwap) {
|
|
1232
|
+
if (v3Routes.length > 0) {
|
|
1233
|
+
const v3RoutesFromCache = v3Routes.map((cachedRoute) => cachedRoute.route);
|
|
1234
|
+
metric.putMetric('SwapRouteFromCache_V3_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1235
|
+
const beforeGetQuotes = Date.now();
|
|
1236
|
+
quotePromises.push(this.v3Quoter
|
|
1237
|
+
.getQuotes(v3RoutesFromCache, amounts, percents, quoteCurrency.wrapped, tradeType, routingConfig, undefined, v3GasModel)
|
|
1238
|
+
.then((result) => {
|
|
1239
|
+
metric.putMetric(`SwapRouteFromCache_V3_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1240
|
+
return result;
|
|
1241
|
+
}));
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
if (v2Routes.length > 0) {
|
|
1245
|
+
const v2RoutesFromCache = v2Routes.map((cachedRoute) => cachedRoute.route);
|
|
1246
|
+
metric.putMetric('SwapRouteFromCache_V2_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1247
|
+
const beforeGetQuotes = Date.now();
|
|
1248
|
+
quotePromises.push(this.v2Quoter
|
|
1249
|
+
.refreshRoutesThenGetQuotes(fewCachedRoutes.currencyIn.wrapped, fewCachedRoutes.currencyOut.wrapped, v2RoutesFromCache, amounts, percents, quoteCurrency.wrapped, tradeType, routingConfig, gasPriceWei)
|
|
1250
|
+
.then((result) => {
|
|
1251
|
+
metric.putMetric(`SwapRouteFromCache_V2_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1252
|
+
return result;
|
|
1253
|
+
}));
|
|
1254
|
+
}
|
|
1255
|
+
if (ringFewV2Routes.length > 0) {
|
|
1256
|
+
const ringFewV2RoutesFromCache = ringFewV2Routes.map((cachedRoute) => cachedRoute.route);
|
|
1257
|
+
metric.putMetric('SwapRouteFromCache_RingFewV2_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1258
|
+
const beforeGetQuotes = Date.now();
|
|
1259
|
+
quotePromises.push(this.ringFewV2Quoter
|
|
1260
|
+
.refreshRoutesThenGetQuotes(fewCachedRoutes.currencyIn.wrapped, fewCachedRoutes.currencyOut.wrapped, ringFewV2RoutesFromCache, fewAmounts, fewPercents, fewQuoteToken.wrapped, tradeType, routingConfig, gasPriceWei)
|
|
1261
|
+
.then((result) => {
|
|
1262
|
+
metric.putMetric(`SwapRouteFromCache_RingFewV2_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1263
|
+
return result;
|
|
1264
|
+
}));
|
|
1265
|
+
}
|
|
1266
|
+
if (!fotInDirectSwap) {
|
|
1267
|
+
if (mixedRoutes.length > 0) {
|
|
1268
|
+
const mixedRoutesFromCache = mixedRoutes.map((cachedRoute) => cachedRoute.route);
|
|
1269
|
+
metric.putMetric('SwapRouteFromCache_Mixed_GetQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1270
|
+
const beforeGetQuotes = Date.now();
|
|
1271
|
+
quotePromises.push(this.mixedQuoter
|
|
1272
|
+
.getQuotes(mixedRoutesFromCache, amounts, percents, quoteCurrency.wrapped, tradeType, routingConfig, undefined, mixedRouteGasModel)
|
|
1273
|
+
.then((result) => {
|
|
1274
|
+
metric.putMetric(`SwapRouteFromCache_Mixed_GetQuotes_Load`, Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
|
|
1275
|
+
return result;
|
|
1276
|
+
}));
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
const getQuotesResults = await Promise.all(quotePromises);
|
|
1280
|
+
const allRoutesWithValidQuotes = _.flatMap(getQuotesResults, (quoteResult) => quoteResult.routesWithValidQuotes);
|
|
1281
|
+
return getBestSwapRoute(amount, percents, allRoutesWithValidQuotes, tradeType, this.chainId, routingConfig, this.portionProvider, v2GasModel, v3GasModel, v4GasModel, swapConfig, providerConfig);
|
|
1282
|
+
}
|
|
1283
|
+
async getSwapRouteFromChain(amount, fewAmount, currencyIn, fewTokenIn, currencyOut, fewTokenOut, protocols, quoteCurrency, fewQuoteToken, tradeType, routingConfig, v3GasModel, v4GasModel, mixedRouteGasModel, gasPriceWei, v2GasModel, ringFewV2GasModel, swapConfig, providerConfig) {
|
|
1284
|
+
var _a, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
1285
|
+
const tokenPairProperties = await this.tokenPropertiesProvider.getTokensProperties([currencyIn, currencyOut], providerConfig);
|
|
1286
|
+
if (!swapConfig) {
|
|
1287
|
+
//
|
|
1288
|
+
}
|
|
1289
|
+
// const fewTokenPairProperties =
|
|
1290
|
+
// await this.tokenPropertiesProvider.getTokensProperties(
|
|
1291
|
+
// [fewTokenIn, fewTokenOut],
|
|
1292
|
+
// providerConfig
|
|
1293
|
+
// );
|
|
1294
|
+
const sellTokenIsFot = (_d = (_c = (_a = tokenPairProperties[getAddressLowerCase(currencyIn)]) === 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);
|
|
1295
|
+
const buyTokenIsFot = (_g = (_f = (_e = tokenPairProperties[getAddressLowerCase(currencyOut)]) === 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);
|
|
1296
|
+
const fotInDirectSwap = sellTokenIsFot || buyTokenIsFot;
|
|
1297
|
+
// const sellTokenIsFewFot =
|
|
1298
|
+
// fewTokenPairProperties[
|
|
1299
|
+
// getAddressLowerCase(fewTokenIn)
|
|
1300
|
+
// ]?.tokenFeeResult?.sellFeeBps?.gt(0);
|
|
1301
|
+
// const buyTokenIsFewFot =
|
|
1302
|
+
// fewTokenPairProperties[
|
|
1303
|
+
// getAddressLowerCase(fewTokenOut)
|
|
1304
|
+
// ]?.tokenFeeResult?.buyFeeBps?.gt(0);
|
|
1305
|
+
// const fewFotInDirectSwap = sellTokenIsFewFot || buyTokenIsFewFot;
|
|
1306
|
+
// Generate our distribution of amounts, i.e. fractions of the input amount.
|
|
1307
|
+
// We will get quotes for fractions of the input amount for different routes, then
|
|
1308
|
+
// combine to generate split routes.
|
|
1309
|
+
const [percents, amounts] = this.getAmountDistribution(amount, routingConfig);
|
|
1310
|
+
const [fewPercents, fewAmounts] = this.getAmountDistribution(fewAmount, routingConfig);
|
|
1311
|
+
const noProtocolsSpecified = protocols.length === 0;
|
|
1312
|
+
const v4ProtocolSpecified = protocols.includes(Protocol.V4);
|
|
1313
|
+
const v3ProtocolSpecified = protocols.includes(Protocol.V3);
|
|
1314
|
+
const v2ProtocolSpecified = protocols.includes(Protocol.V2);
|
|
1315
|
+
const ringFewV2ProtocolSpecified = protocols.includes(Protocol.FEWV2);
|
|
1316
|
+
const v2SupportedInChain = (_h = this.v2Supported) === null || _h === void 0 ? void 0 : _h.includes(this.chainId);
|
|
1317
|
+
const ringFewV2SupportedInChain = (_j = this.ringFewV2Supported) === null || _j === void 0 ? void 0 : _j.includes(this.chainId);
|
|
1318
|
+
const v4SupportedInChain = (_k = this.v4Supported) === null || _k === void 0 ? void 0 : _k.includes(this.chainId);
|
|
1319
|
+
const shouldQueryMixedProtocol = protocols.includes(Protocol.MIXED) ||
|
|
1320
|
+
(noProtocolsSpecified && v2SupportedInChain && ringFewV2SupportedInChain && v4SupportedInChain);
|
|
1321
|
+
// const shouldQueryRingFewV2Protocol =
|
|
1322
|
+
// protocols.includes(Protocol.FEWV2) ||
|
|
1323
|
+
// (noProtocolsSpecified && ringFewV2SupportedInChain);
|
|
1324
|
+
const mixedProtocolAllowed = ((_l = this.mixedSupported) === null || _l === void 0 ? void 0 : _l.includes(this.chainId)) &&
|
|
1325
|
+
tradeType === TradeType.EXACT_INPUT;
|
|
1326
|
+
const beforeGetCandidates = Date.now();
|
|
1327
|
+
let v4CandidatePoolsPromise = Promise.resolve(undefined);
|
|
1328
|
+
// we are explicitly requiring people to specify v4 for now
|
|
1329
|
+
if (v4SupportedInChain && (v4ProtocolSpecified || noProtocolsSpecified)) {
|
|
1330
|
+
// if (v4ProtocolSpecified || noProtocolsSpecified) {
|
|
1331
|
+
v4CandidatePoolsPromise = getV4CandidatePools({
|
|
1332
|
+
currencyIn: currencyIn,
|
|
1333
|
+
currencyOut: currencyOut,
|
|
1334
|
+
tokenProvider: this.tokenProvider,
|
|
1335
|
+
blockedTokenListProvider: this.blockedTokenListProvider,
|
|
1336
|
+
poolProvider: this.v4PoolProvider,
|
|
1337
|
+
routeType: tradeType,
|
|
1338
|
+
subgraphProvider: this.v4SubgraphProvider,
|
|
1339
|
+
routingConfig,
|
|
1340
|
+
chainId: this.chainId,
|
|
1341
|
+
v4PoolParams: this.v4PoolParams,
|
|
1342
|
+
}).then((candidatePools) => {
|
|
1343
|
+
metric.putMetric('GetV4CandidatePools', Date.now() - beforeGetCandidates, MetricLoggerUnit.Milliseconds);
|
|
1344
|
+
return candidatePools;
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
let v3CandidatePoolsPromise = Promise.resolve(undefined);
|
|
1348
|
+
if (!fotInDirectSwap) {
|
|
1349
|
+
if (v3ProtocolSpecified || noProtocolsSpecified) {
|
|
1350
|
+
const tokenIn = currencyIn.wrapped;
|
|
1351
|
+
const tokenOut = currencyOut.wrapped;
|
|
1352
|
+
v3CandidatePoolsPromise = getV3CandidatePools({
|
|
1353
|
+
tokenIn,
|
|
1354
|
+
tokenOut,
|
|
1355
|
+
tokenProvider: this.tokenProvider,
|
|
1356
|
+
blockedTokenListProvider: this.blockedTokenListProvider,
|
|
1357
|
+
poolProvider: this.v3PoolProvider,
|
|
1358
|
+
routeType: tradeType,
|
|
1359
|
+
subgraphProvider: this.v3SubgraphProvider,
|
|
1360
|
+
routingConfig,
|
|
1361
|
+
chainId: this.chainId,
|
|
1362
|
+
}).then((candidatePools) => {
|
|
1363
|
+
metric.putMetric('GetV3CandidatePools', Date.now() - beforeGetCandidates, MetricLoggerUnit.Milliseconds);
|
|
1364
|
+
return candidatePools;
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
let v2CandidatePoolsPromise = Promise.resolve(undefined);
|
|
1369
|
+
if (v2SupportedInChain && (v2ProtocolSpecified || noProtocolsSpecified)) {
|
|
1370
|
+
const tokenIn = currencyIn.wrapped;
|
|
1371
|
+
const tokenOut = currencyOut.wrapped;
|
|
1372
|
+
// Fetch all the pools that we will consider routing via. There are thousands
|
|
1373
|
+
// of pools, so we filter them to a set of candidate pools that we expect will
|
|
1374
|
+
// result in good prices.
|
|
1375
|
+
v2CandidatePoolsPromise = getV2CandidatePools({
|
|
1376
|
+
tokenIn,
|
|
1377
|
+
tokenOut,
|
|
1378
|
+
tokenProvider: this.tokenProvider,
|
|
1379
|
+
blockedTokenListProvider: this.blockedTokenListProvider,
|
|
1380
|
+
poolProvider: this.v2PoolProvider,
|
|
1381
|
+
routeType: tradeType,
|
|
1382
|
+
subgraphProvider: this.v2SubgraphProvider,
|
|
1383
|
+
routingConfig,
|
|
1384
|
+
chainId: this.chainId,
|
|
1385
|
+
}).then((candidatePools) => {
|
|
1386
|
+
metric.putMetric('GetV2CandidatePools', Date.now() - beforeGetCandidates, MetricLoggerUnit.Milliseconds);
|
|
1387
|
+
return candidatePools;
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
let ringFewV2CandidatePoolsPromise = Promise.resolve(undefined);
|
|
1391
|
+
if (ringFewV2SupportedInChain && (ringFewV2ProtocolSpecified || noProtocolsSpecified)) {
|
|
1392
|
+
const tokenIn = fewTokenIn;
|
|
1393
|
+
const tokenOut = fewTokenOut;
|
|
1394
|
+
ringFewV2CandidatePoolsPromise = getRingFewV2CandidatePools({
|
|
1395
|
+
tokenIn,
|
|
1396
|
+
tokenOut,
|
|
1397
|
+
tokenProvider: this.tokenProvider,
|
|
1398
|
+
blockedTokenListProvider: this.blockedTokenListProvider,
|
|
1399
|
+
poolProvider: this.ringFewV2PoolProvider,
|
|
1400
|
+
routeType: tradeType,
|
|
1401
|
+
subgraphProvider: this.ringFewV2SubgraphProvider,
|
|
1402
|
+
routingConfig,
|
|
1403
|
+
chainId: this.chainId,
|
|
1404
|
+
}).then((candidatePools) => {
|
|
1405
|
+
metric.putMetric('GetRingFewV2CandidatePools', Date.now() - beforeGetCandidates, MetricLoggerUnit.Milliseconds);
|
|
1406
|
+
return candidatePools;
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
const quotePromises = [];
|
|
1410
|
+
// for v4, for now we explicitly require people to specify
|
|
1411
|
+
if (v4SupportedInChain && v4ProtocolSpecified) {
|
|
1412
|
+
log.info({ protocols, tradeType }, 'Routing across V4');
|
|
1413
|
+
metric.putMetric('SwapRouteFromChain_V4_GetRoutesThenQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1414
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
1415
|
+
quotePromises.push(v4CandidatePoolsPromise.then((v4CandidatePools) => this.v4Quoter
|
|
1416
|
+
.getRoutesThenQuotes(currencyIn, currencyOut, amount, amounts, percents, quoteCurrency, v4CandidatePools, tradeType, routingConfig, v4GasModel)
|
|
1417
|
+
.then((result) => {
|
|
1418
|
+
metric.putMetric(`SwapRouteFromChain_V4_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, MetricLoggerUnit.Milliseconds);
|
|
1419
|
+
return result;
|
|
1420
|
+
})));
|
|
1421
|
+
}
|
|
1422
|
+
if (!fotInDirectSwap) {
|
|
1423
|
+
// Maybe Quote V3 - if V3 is specified, or no protocol is specified
|
|
1424
|
+
if (v3ProtocolSpecified || noProtocolsSpecified) {
|
|
1425
|
+
log.info({ protocols, tradeType }, 'Routing across V3');
|
|
1426
|
+
metric.putMetric('SwapRouteFromChain_V3_GetRoutesThenQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1427
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
1428
|
+
const tokenIn = currencyIn.wrapped;
|
|
1429
|
+
const tokenOut = currencyOut.wrapped;
|
|
1430
|
+
quotePromises.push(v3CandidatePoolsPromise.then((v3CandidatePools) => this.v3Quoter
|
|
1431
|
+
.getRoutesThenQuotes(tokenIn, tokenOut, amount, amounts, percents, quoteCurrency.wrapped, v3CandidatePools, tradeType, routingConfig, v3GasModel)
|
|
1432
|
+
.then((result) => {
|
|
1433
|
+
metric.putMetric(`SwapRouteFromChain_V3_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, MetricLoggerUnit.Milliseconds);
|
|
1434
|
+
return result;
|
|
1435
|
+
})));
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
// Maybe Quote V2 - if V2 is specified, or no protocol is specified AND v2 is supported in this chain
|
|
1439
|
+
if (v2SupportedInChain && (v2ProtocolSpecified || noProtocolsSpecified)) {
|
|
1440
|
+
log.info({ protocols, tradeType }, 'Routing across V2');
|
|
1441
|
+
metric.putMetric('SwapRouteFromChain_V2_GetRoutesThenQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1442
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
1443
|
+
const tokenIn = currencyIn.wrapped;
|
|
1444
|
+
const tokenOut = currencyOut.wrapped;
|
|
1445
|
+
quotePromises.push(v2CandidatePoolsPromise.then((v2CandidatePools) => this.v2Quoter
|
|
1446
|
+
.getRoutesThenQuotes(tokenIn, tokenOut, amount, amounts, percents, quoteCurrency.wrapped, v2CandidatePools, tradeType, routingConfig, v2GasModel, gasPriceWei)
|
|
1447
|
+
.then((result) => {
|
|
1448
|
+
metric.putMetric(`SwapRouteFromChain_V2_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, MetricLoggerUnit.Milliseconds);
|
|
1449
|
+
return result;
|
|
1450
|
+
})));
|
|
1451
|
+
}
|
|
1452
|
+
// Maybe Quote RingFewV2 - if RingFewV2 is specified, or no protocol is specified AND ringFewV2 is supported in this chain
|
|
1453
|
+
if (ringFewV2SupportedInChain && (ringFewV2ProtocolSpecified || noProtocolsSpecified)) {
|
|
1454
|
+
log.info({ protocols, tradeType }, 'Routing across RingFewV2');
|
|
1455
|
+
metric.putMetric('SwapRouteFromChain_RingFewV2_GetRoutesThenQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1456
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
1457
|
+
const tokenIn = fewTokenIn;
|
|
1458
|
+
const tokenOut = fewTokenOut;
|
|
1459
|
+
quotePromises.push(ringFewV2CandidatePoolsPromise.then((ringFewV2CandidatePools) => this.ringFewV2Quoter
|
|
1460
|
+
.getRoutesThenQuotes(tokenIn, tokenOut, fewAmount, fewAmounts, fewPercents, fewQuoteToken.wrapped, ringFewV2CandidatePools, tradeType, routingConfig, ringFewV2GasModel, gasPriceWei)
|
|
1461
|
+
.then((result) => {
|
|
1462
|
+
metric.putMetric(`SwapRouteFromChain_RingFewV2_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, MetricLoggerUnit.Milliseconds);
|
|
1463
|
+
return result;
|
|
1464
|
+
})));
|
|
1465
|
+
}
|
|
1466
|
+
if (!fotInDirectSwap) {
|
|
1467
|
+
// Maybe Quote mixed routes
|
|
1468
|
+
// if MixedProtocol is specified or no protocol is specified and v2 is supported AND tradeType is ExactIn
|
|
1469
|
+
// AND is Mainnet or Gorli
|
|
1470
|
+
// Also make sure there are at least 2 protocols provided besides MIXED, before entering mixed quoter
|
|
1471
|
+
if (shouldQueryMixedProtocol &&
|
|
1472
|
+
mixedProtocolAllowed &&
|
|
1473
|
+
protocols.filter((protocol) => protocol !== Protocol.MIXED).length >= 2) {
|
|
1474
|
+
log.info({ protocols, tradeType }, 'Routing across MixedRoutes');
|
|
1475
|
+
metric.putMetric('SwapRouteFromChain_Mixed_GetRoutesThenQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1476
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
1477
|
+
quotePromises.push(Promise.all([
|
|
1478
|
+
v4CandidatePoolsPromise,
|
|
1479
|
+
v3CandidatePoolsPromise,
|
|
1480
|
+
v2CandidatePoolsPromise,
|
|
1481
|
+
ringFewV2CandidatePoolsPromise,
|
|
1482
|
+
]).then(async ([v4CandidatePools, v3CandidatePools, v2CandidatePools, ringFewV2CandidatePools]) => {
|
|
1483
|
+
const tokenIn = currencyIn.wrapped;
|
|
1484
|
+
const tokenOut = currencyOut.wrapped;
|
|
1485
|
+
const crossLiquidityPools = await getMixedCrossLiquidityCandidatePools({
|
|
1486
|
+
tokenIn,
|
|
1487
|
+
tokenOut,
|
|
1488
|
+
blockNumber: routingConfig.blockNumber,
|
|
1489
|
+
v2SubgraphProvider: this.v2SubgraphProvider,
|
|
1490
|
+
v3SubgraphProvider: this.v3SubgraphProvider,
|
|
1491
|
+
v2Candidates: v2CandidatePools,
|
|
1492
|
+
v3Candidates: v3CandidatePools,
|
|
1493
|
+
v4Candidates: v4CandidatePools,
|
|
1494
|
+
});
|
|
1495
|
+
return this.mixedQuoter
|
|
1496
|
+
.getRoutesThenQuotes(tokenIn, tokenOut, amount, amounts, percents, quoteCurrency.wrapped, [
|
|
1497
|
+
v4CandidatePools,
|
|
1498
|
+
v3CandidatePools,
|
|
1499
|
+
v2CandidatePools,
|
|
1500
|
+
ringFewV2CandidatePools,
|
|
1501
|
+
crossLiquidityPools,
|
|
1502
|
+
], tradeType, routingConfig, mixedRouteGasModel)
|
|
1503
|
+
.then((result) => {
|
|
1504
|
+
metric.putMetric(`SwapRouteFromChain_Mixed_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, MetricLoggerUnit.Milliseconds);
|
|
1505
|
+
return result;
|
|
1506
|
+
});
|
|
1507
|
+
}));
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
const getQuotesResults = await Promise.all(quotePromises);
|
|
1511
|
+
const allRoutesWithValidQuotes = [];
|
|
1512
|
+
const allCandidatePools = [];
|
|
1513
|
+
getQuotesResults.forEach((getQuoteResult) => {
|
|
1514
|
+
allRoutesWithValidQuotes.push(...getQuoteResult.routesWithValidQuotes);
|
|
1515
|
+
if (getQuoteResult.candidatePools) {
|
|
1516
|
+
allCandidatePools.push(getQuoteResult.candidatePools);
|
|
1517
|
+
}
|
|
1518
|
+
});
|
|
1519
|
+
if (allRoutesWithValidQuotes.length === 0) {
|
|
1520
|
+
log.info({ allRoutesWithValidQuotes }, 'Received no valid quotes');
|
|
1521
|
+
return null;
|
|
1522
|
+
}
|
|
1523
|
+
return allRoutesWithValidQuotes;
|
|
1524
|
+
/*
|
|
1525
|
+
// Given all the quotes for all the amounts for all the routes, find the best combination.
|
|
1526
|
+
const bestSwapRoute = await getBestSwapRoute(
|
|
1527
|
+
amount,
|
|
1528
|
+
percents,
|
|
1529
|
+
allRoutesWithValidQuotes,
|
|
1530
|
+
tradeType,
|
|
1531
|
+
this.chainId,
|
|
1532
|
+
routingConfig,
|
|
1533
|
+
this.portionProvider,
|
|
1534
|
+
v2GasModel,
|
|
1535
|
+
v3GasModel,
|
|
1536
|
+
v4GasModel,
|
|
1537
|
+
swapConfig,
|
|
1538
|
+
providerConfig
|
|
1539
|
+
);
|
|
1540
|
+
|
|
1541
|
+
if (bestSwapRoute) {
|
|
1542
|
+
this.emitPoolSelectionMetrics(
|
|
1543
|
+
bestSwapRoute,
|
|
1544
|
+
allCandidatePools,
|
|
1545
|
+
currencyIn,
|
|
1546
|
+
currencyOut
|
|
1547
|
+
);
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
return bestSwapRoute;
|
|
1551
|
+
*/
|
|
1552
|
+
}
|
|
1553
|
+
// for uniswap fewToken
|
|
1554
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1555
|
+
async getUniswapFewTokenSwapRouteFromChain(amount, fewAmount, currencyIn, fewTokenIn, currencyOut, fewTokenOut, protocols, _quoteCurrency, fewQuoteToken, tradeType, routingConfig,
|
|
1556
|
+
// v3GasModel: IGasModel<V3RouteWithValidQuote>,
|
|
1557
|
+
fewV3GasModel,
|
|
1558
|
+
// v4GasModel: IGasModel<V4RouteWithValidQuote>,
|
|
1559
|
+
fewV4GasModel, _mixedRouteGasModel, gasPriceWei, _v2GasModel, fewV2GasModel,
|
|
1560
|
+
// ringFewV2GasModel?: IGasModel<RingFewV2RouteWithValidQuote>,
|
|
1561
|
+
providerConfig) {
|
|
1562
|
+
var _a, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
1563
|
+
const tokenPairProperties = await this.tokenPropertiesProvider.getTokensProperties([currencyIn, currencyOut], providerConfig);
|
|
1564
|
+
const sellTokenIsFot = (_d = (_c = (_a = tokenPairProperties[getAddressLowerCase(currencyIn)]) === 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);
|
|
1565
|
+
const buyTokenIsFot = (_g = (_f = (_e = tokenPairProperties[getAddressLowerCase(currencyOut)]) === 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);
|
|
1566
|
+
const fotInDirectSwap = sellTokenIsFot || buyTokenIsFot;
|
|
1567
|
+
// Generate our distribution of amounts, i.e. fractions of the input amount.
|
|
1568
|
+
// We will get quotes for fractions of the input amount for different routes, then
|
|
1569
|
+
// combine to generate split routes.
|
|
1570
|
+
const [_amounts] = this.getAmountDistribution(amount, routingConfig);
|
|
1571
|
+
const [fewPercents, fewAmounts] = this.getAmountDistribution(fewAmount, routingConfig);
|
|
1572
|
+
// const tokenIn = fewTokenIn;
|
|
1573
|
+
// const tokenOut = fewTokenOut;
|
|
1574
|
+
const noProtocolsSpecified = protocols.length === 0;
|
|
1575
|
+
const v4ProtocolSpecified = protocols.includes(Protocol.V4);
|
|
1576
|
+
const v3ProtocolSpecified = protocols.includes(Protocol.V3);
|
|
1577
|
+
const v2ProtocolSpecified = protocols.includes(Protocol.V2);
|
|
1578
|
+
//@ts-ignore
|
|
1579
|
+
const _ringFewV2ProtocolSpecified = protocols.includes(Protocol.FEWV2);
|
|
1580
|
+
const v2SupportedInChain = (_h = this.v2Supported) === null || _h === void 0 ? void 0 : _h.includes(this.chainId);
|
|
1581
|
+
const ringFewV2SupportedInChain = (_j = this.ringFewV2Supported) === null || _j === void 0 ? void 0 : _j.includes(this.chainId);
|
|
1582
|
+
const v4SupportedInChain = (_k = this.v4Supported) === null || _k === void 0 ? void 0 : _k.includes(this.chainId);
|
|
1583
|
+
//@ts-ignore
|
|
1584
|
+
const _shouldQueryMixedProtocol = protocols.includes(Protocol.MIXED) ||
|
|
1585
|
+
(noProtocolsSpecified && v2SupportedInChain && ringFewV2SupportedInChain && v4SupportedInChain);
|
|
1586
|
+
//@ts-ignore
|
|
1587
|
+
const _mixedProtocolAllowed = ((_l = this.mixedSupported) === null || _l === void 0 ? void 0 : _l.includes(this.chainId)) &&
|
|
1588
|
+
tradeType === TradeType.EXACT_INPUT;
|
|
1589
|
+
const beforeGetCandidates = Date.now();
|
|
1590
|
+
let v4CandidatePoolsPromise = Promise.resolve(undefined);
|
|
1591
|
+
// we are explicitly requiring people to specify v4 for now
|
|
1592
|
+
if (v4SupportedInChain && (v4ProtocolSpecified || noProtocolsSpecified)) {
|
|
1593
|
+
// if (v4ProtocolSpecified || noProtocolsSpecified) {
|
|
1594
|
+
v4CandidatePoolsPromise = getUniswapV4FewTokenCandidatePools({
|
|
1595
|
+
currencyIn: fewTokenIn,
|
|
1596
|
+
currencyOut: fewTokenOut,
|
|
1597
|
+
tokenProvider: this.tokenProvider,
|
|
1598
|
+
blockedTokenListProvider: this.blockedTokenListProvider,
|
|
1599
|
+
poolProvider: this.v4PoolProvider,
|
|
1600
|
+
routeType: tradeType,
|
|
1601
|
+
subgraphProvider: this.v4SubgraphProvider,
|
|
1602
|
+
routingConfig,
|
|
1603
|
+
chainId: this.chainId,
|
|
1604
|
+
v4PoolParams: this.v4PoolParams,
|
|
1605
|
+
}).then((candidatePools) => {
|
|
1606
|
+
metric.putMetric('GetV4CandidatePools', Date.now() - beforeGetCandidates, MetricLoggerUnit.Milliseconds);
|
|
1607
|
+
return candidatePools;
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1610
|
+
let v3CandidatePoolsPromise = Promise.resolve(undefined);
|
|
1611
|
+
if (!fotInDirectSwap) {
|
|
1612
|
+
if (v3ProtocolSpecified || noProtocolsSpecified) {
|
|
1613
|
+
v3CandidatePoolsPromise = getUniswapFewTokenV3CandidatePools({
|
|
1614
|
+
tokenIn: fewTokenIn,
|
|
1615
|
+
tokenOut: fewTokenOut,
|
|
1616
|
+
tokenProvider: this.tokenProvider,
|
|
1617
|
+
blockedTokenListProvider: this.blockedTokenListProvider,
|
|
1618
|
+
poolProvider: this.v3PoolProvider,
|
|
1619
|
+
routeType: tradeType,
|
|
1620
|
+
subgraphProvider: this.v3SubgraphProvider,
|
|
1621
|
+
routingConfig,
|
|
1622
|
+
chainId: this.chainId,
|
|
1623
|
+
}).then((candidatePools) => {
|
|
1624
|
+
metric.putMetric('GetV3CandidatePools', Date.now() - beforeGetCandidates, MetricLoggerUnit.Milliseconds);
|
|
1625
|
+
return candidatePools;
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
let v2CandidatePoolsPromise = Promise.resolve(undefined);
|
|
1630
|
+
if (v2SupportedInChain && (v2ProtocolSpecified || noProtocolsSpecified)) {
|
|
1631
|
+
// Fetch all the pools that we will consider routing via. There are thousands
|
|
1632
|
+
// of pools, so we filter them to a set of candidate pools that we expect will
|
|
1633
|
+
// result in good prices.
|
|
1634
|
+
v2CandidatePoolsPromise = getUniswapFewTokenV2CandidatePools({
|
|
1635
|
+
tokenIn: fewTokenIn,
|
|
1636
|
+
tokenOut: fewTokenOut,
|
|
1637
|
+
tokenProvider: this.tokenProvider,
|
|
1638
|
+
blockedTokenListProvider: this.blockedTokenListProvider,
|
|
1639
|
+
poolProvider: this.v2PoolProvider,
|
|
1640
|
+
routeType: tradeType,
|
|
1641
|
+
subgraphProvider: this.v2SubgraphProvider,
|
|
1642
|
+
routingConfig,
|
|
1643
|
+
chainId: this.chainId,
|
|
1644
|
+
}).then((candidatePools) => {
|
|
1645
|
+
metric.putMetric('getUniswapFewTokenV2CandidatePools', Date.now() - beforeGetCandidates, MetricLoggerUnit.Milliseconds);
|
|
1646
|
+
return candidatePools;
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1649
|
+
// FEWV2 这里查询的是 origin token 的 pool
|
|
1650
|
+
// let ringFewV2CandidatePoolsPromise: Promise<RingFewV2CandidatePools | undefined> =
|
|
1651
|
+
// Promise.resolve(undefined);
|
|
1652
|
+
// if (ringFewV2SupportedInChain && (ringFewV2ProtocolSpecified || noProtocolsSpecified)) {
|
|
1653
|
+
// const tokenIn = currencyIn.wrapped;
|
|
1654
|
+
// const tokenOut = currencyOut.wrapped;
|
|
1655
|
+
// ringFewV2CandidatePoolsPromise = getRingFewV2CandidatePools({
|
|
1656
|
+
// tokenIn,
|
|
1657
|
+
// tokenOut,
|
|
1658
|
+
// tokenProvider: this.tokenProvider,
|
|
1659
|
+
// blockedTokenListProvider: this.blockedTokenListProvider,
|
|
1660
|
+
// poolProvider: this.ringFewV2PoolProvider,
|
|
1661
|
+
// routeType: tradeType,
|
|
1662
|
+
// subgraphProvider: this.ringFewV2SubgraphProvider,
|
|
1663
|
+
// routingConfig,
|
|
1664
|
+
// chainId: this.chainId,
|
|
1665
|
+
// }).then((candidatePools) => {
|
|
1666
|
+
// metric.putMetric(
|
|
1667
|
+
// 'GetRingFewV2CandidatePools',
|
|
1668
|
+
// Date.now() - beforeGetCandidates,
|
|
1669
|
+
// MetricLoggerUnit.Milliseconds
|
|
1670
|
+
// );
|
|
1671
|
+
// return candidatePools;
|
|
1672
|
+
// });
|
|
1673
|
+
// }
|
|
1674
|
+
const quotePromises = [];
|
|
1675
|
+
// for v4, for now we explicitly require people to specify
|
|
1676
|
+
if (v4SupportedInChain && v4ProtocolSpecified) {
|
|
1677
|
+
log.info({ protocols, tradeType }, 'Routing across V4');
|
|
1678
|
+
metric.putMetric('SwapRouteFromChain_V4_GetRoutesThenQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1679
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
1680
|
+
quotePromises.push(v4CandidatePoolsPromise.then((v4CandidatePools) => this.uniswapFewV4Quoter
|
|
1681
|
+
.getRoutesThenQuotes(fewTokenIn, fewTokenOut, fewAmount, fewAmounts, fewPercents, fewQuoteToken, v4CandidatePools, tradeType, routingConfig, fewV4GasModel)
|
|
1682
|
+
.then((result) => {
|
|
1683
|
+
metric.putMetric(`SwapRouteFromChain_V4_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, MetricLoggerUnit.Milliseconds);
|
|
1684
|
+
return result;
|
|
1685
|
+
})));
|
|
1686
|
+
}
|
|
1687
|
+
if (!fotInDirectSwap) {
|
|
1688
|
+
// Maybe Quote V3 - if V3 is specified, or no protocol is specified
|
|
1689
|
+
if (v3ProtocolSpecified || noProtocolsSpecified) {
|
|
1690
|
+
log.info({ protocols, tradeType }, 'Routing across V3');
|
|
1691
|
+
metric.putMetric('SwapRouteFromChain_V3_GetRoutesThenQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1692
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
1693
|
+
quotePromises.push(v3CandidatePoolsPromise.then((v3CandidatePools) => this.uniswapFewV3Quoter
|
|
1694
|
+
.getRoutesThenQuotes(fewTokenIn, fewTokenOut, fewAmount, fewAmounts, fewPercents, fewQuoteToken, v3CandidatePools, tradeType, routingConfig, fewV3GasModel)
|
|
1695
|
+
.then((result) => {
|
|
1696
|
+
metric.putMetric(`SwapRouteFromChain_V3_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, MetricLoggerUnit.Milliseconds);
|
|
1697
|
+
return result;
|
|
1698
|
+
})));
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
// Maybe Quote V2 - if V2 is specified, or no protocol is specified AND v2 is supported in this chain
|
|
1702
|
+
if (v2SupportedInChain && (v2ProtocolSpecified || noProtocolsSpecified)) {
|
|
1703
|
+
log.info({ protocols, tradeType }, 'Routing across V2');
|
|
1704
|
+
metric.putMetric('SwapRouteFromChain_V2_GetRoutesThenQuotes_Request', 1, MetricLoggerUnit.Count);
|
|
1705
|
+
const beforeGetRoutesThenQuotes = Date.now();
|
|
1706
|
+
quotePromises.push(v2CandidatePoolsPromise.then((v2CandidatePools) => this.v2Quoter
|
|
1707
|
+
.getRoutesThenQuotes(fewTokenIn, fewTokenOut, fewAmount, fewAmounts, fewPercents, fewQuoteToken, v2CandidatePools, tradeType, routingConfig, fewV2GasModel, gasPriceWei)
|
|
1708
|
+
.then((result) => {
|
|
1709
|
+
metric.putMetric(`SwapRouteFromChain_V2_GetRoutesThenQuotes_Load`, Date.now() - beforeGetRoutesThenQuotes, MetricLoggerUnit.Milliseconds);
|
|
1710
|
+
return result;
|
|
1711
|
+
})));
|
|
1712
|
+
}
|
|
1713
|
+
// Maybe Quote RingFewV2 - if RingFewV2 is specified, or no protocol is specified AND ringFewV2 is supported in this chain
|
|
1714
|
+
// if (ringFewV2SupportedInChain && (ringFewV2ProtocolSpecified || noProtocolsSpecified)) {
|
|
1715
|
+
// log.info({ protocols, tradeType }, 'Routing across RingFewV2');
|
|
1716
|
+
// metric.putMetric(
|
|
1717
|
+
// 'SwapRouteFromChain_RingFewV2_GetRoutesThenQuotes_Request',
|
|
1718
|
+
// 1,
|
|
1719
|
+
// MetricLoggerUnit.Count
|
|
1720
|
+
// );
|
|
1721
|
+
// const beforeGetRoutesThenQuotes = Date.now();
|
|
1722
|
+
// const tokenIn = currencyIn.wrapped;
|
|
1723
|
+
// const tokenOut = currencyOut.wrapped;
|
|
1724
|
+
// quotePromises.push(
|
|
1725
|
+
// ringFewV2CandidatePoolsPromise.then((ringFewV2CandidatePools) =>
|
|
1726
|
+
// this.ringFewV2Quoter
|
|
1727
|
+
// .getRoutesThenQuotes(
|
|
1728
|
+
// tokenIn,
|
|
1729
|
+
// tokenOut,
|
|
1730
|
+
// amount,
|
|
1731
|
+
// amounts,
|
|
1732
|
+
// percents,
|
|
1733
|
+
// quoteCurrency.wrapped,
|
|
1734
|
+
// ringFewV2CandidatePools!,
|
|
1735
|
+
// tradeType,
|
|
1736
|
+
// routingConfig,
|
|
1737
|
+
// v2GasModel,
|
|
1738
|
+
// gasPriceWei
|
|
1739
|
+
// )
|
|
1740
|
+
// .then((result) => {
|
|
1741
|
+
// metric.putMetric(
|
|
1742
|
+
// `SwapRouteFromChain_RingFewV2_GetRoutesThenQuotes_Load`,
|
|
1743
|
+
// Date.now() - beforeGetRoutesThenQuotes,
|
|
1744
|
+
// MetricLoggerUnit.Milliseconds
|
|
1745
|
+
// );
|
|
1746
|
+
// return result;
|
|
1747
|
+
// })
|
|
1748
|
+
// )
|
|
1749
|
+
// );
|
|
1750
|
+
// }
|
|
1751
|
+
// if (!fotInDirectSwap) {
|
|
1752
|
+
// // Maybe Quote mixed routes
|
|
1753
|
+
// // if MixedProtocol is specified or no protocol is specified and v2 is supported AND tradeType is ExactIn
|
|
1754
|
+
// // AND is Mainnet or Gorli
|
|
1755
|
+
// // Also make sure there are at least 2 protocols provided besides MIXED, before entering mixed quoter
|
|
1756
|
+
// if (
|
|
1757
|
+
// shouldQueryMixedProtocol &&
|
|
1758
|
+
// mixedProtocolAllowed &&
|
|
1759
|
+
// protocols.filter((protocol) => protocol !== Protocol.MIXED).length >= 2
|
|
1760
|
+
// ) {
|
|
1761
|
+
// log.info({ protocols, tradeType }, 'Routing across MixedRoutes');
|
|
1762
|
+
// metric.putMetric(
|
|
1763
|
+
// 'SwapRouteFromChain_Mixed_GetRoutesThenQuotes_Request',
|
|
1764
|
+
// 1,
|
|
1765
|
+
// MetricLoggerUnit.Count
|
|
1766
|
+
// );
|
|
1767
|
+
// const beforeGetRoutesThenQuotes = Date.now();
|
|
1768
|
+
// quotePromises.push(
|
|
1769
|
+
// Promise.all([
|
|
1770
|
+
// v4CandidatePoolsPromise,
|
|
1771
|
+
// v3CandidatePoolsPromise,
|
|
1772
|
+
// v2CandidatePoolsPromise,
|
|
1773
|
+
// ringFewV2CandidatePoolsPromise,
|
|
1774
|
+
// ]).then(
|
|
1775
|
+
// async ([v4CandidatePools, v3CandidatePools, v2CandidatePools, ringFewV2CandidatePools]) => {
|
|
1776
|
+
// const tokenIn = currencyIn.wrapped;
|
|
1777
|
+
// const tokenOut = currencyOut.wrapped;
|
|
1778
|
+
// const crossLiquidityPools =
|
|
1779
|
+
// await getMixedCrossLiquidityCandidatePools({
|
|
1780
|
+
// tokenIn,
|
|
1781
|
+
// tokenOut,
|
|
1782
|
+
// blockNumber: routingConfig.blockNumber,
|
|
1783
|
+
// v2SubgraphProvider: this.v2SubgraphProvider,
|
|
1784
|
+
// v3SubgraphProvider: this.v3SubgraphProvider,
|
|
1785
|
+
// v2Candidates: v2CandidatePools,
|
|
1786
|
+
// v3Candidates: v3CandidatePools,
|
|
1787
|
+
// v4Candidates: v4CandidatePools,
|
|
1788
|
+
// });
|
|
1789
|
+
// return this.mixedQuoter
|
|
1790
|
+
// .getRoutesThenQuotes(
|
|
1791
|
+
// tokenIn,
|
|
1792
|
+
// tokenOut,
|
|
1793
|
+
// amount,
|
|
1794
|
+
// amounts,
|
|
1795
|
+
// percents,
|
|
1796
|
+
// quoteCurrency.wrapped,
|
|
1797
|
+
// [
|
|
1798
|
+
// v4CandidatePools,
|
|
1799
|
+
// v3CandidatePools,
|
|
1800
|
+
// v2CandidatePools,
|
|
1801
|
+
// ringFewV2CandidatePools,
|
|
1802
|
+
// crossLiquidityPools,
|
|
1803
|
+
// ],
|
|
1804
|
+
// tradeType,
|
|
1805
|
+
// routingConfig,
|
|
1806
|
+
// mixedRouteGasModel
|
|
1807
|
+
// )
|
|
1808
|
+
// .then((result) => {
|
|
1809
|
+
// metric.putMetric(
|
|
1810
|
+
// `SwapRouteFromChain_Mixed_GetRoutesThenQuotes_Load`,
|
|
1811
|
+
// Date.now() - beforeGetRoutesThenQuotes,
|
|
1812
|
+
// MetricLoggerUnit.Milliseconds
|
|
1813
|
+
// );
|
|
1814
|
+
// return result;
|
|
1815
|
+
// });
|
|
1816
|
+
// }
|
|
1817
|
+
// )
|
|
1818
|
+
// );
|
|
1819
|
+
// }
|
|
1820
|
+
// }
|
|
1821
|
+
const getQuotesResults = await Promise.all(quotePromises);
|
|
1822
|
+
const allRoutesWithValidQuotes = [];
|
|
1823
|
+
const allCandidatePools = [];
|
|
1824
|
+
getQuotesResults.forEach((getQuoteResult) => {
|
|
1825
|
+
allRoutesWithValidQuotes.push(...getQuoteResult.routesWithValidQuotes);
|
|
1826
|
+
if (getQuoteResult.candidatePools) {
|
|
1827
|
+
allCandidatePools.push(getQuoteResult.candidatePools);
|
|
1828
|
+
}
|
|
1829
|
+
});
|
|
1830
|
+
if (allRoutesWithValidQuotes.length === 0) {
|
|
1831
|
+
log.info({ allRoutesWithValidQuotes }, 'Received no valid fewtokens quotes');
|
|
1832
|
+
return null;
|
|
1833
|
+
}
|
|
1834
|
+
return allRoutesWithValidQuotes;
|
|
1835
|
+
/*
|
|
1836
|
+
// Given all the quotes for all the amounts for all the routes, find the best combination.
|
|
1837
|
+
const bestSwapRoute = await getBestSwapRoute(
|
|
1838
|
+
amount,
|
|
1839
|
+
percents,
|
|
1840
|
+
allRoutesWithValidQuotes,
|
|
1841
|
+
tradeType,
|
|
1842
|
+
this.chainId,
|
|
1843
|
+
routingConfig,
|
|
1844
|
+
this.portionProvider,
|
|
1845
|
+
fewV2GasModel,
|
|
1846
|
+
fewV3GasModel,
|
|
1847
|
+
fewV4GasModel,
|
|
1848
|
+
swapConfig,
|
|
1849
|
+
providerConfig
|
|
1850
|
+
);
|
|
1851
|
+
|
|
1852
|
+
if (bestSwapRoute) {
|
|
1853
|
+
this.emitPoolSelectionMetrics(
|
|
1854
|
+
bestSwapRoute,
|
|
1855
|
+
allCandidatePools,
|
|
1856
|
+
currencyIn,
|
|
1857
|
+
currencyOut
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
return bestSwapRoute;
|
|
1862
|
+
*/
|
|
1863
|
+
}
|
|
1864
|
+
tradeTypeStr(tradeType) {
|
|
1865
|
+
return tradeType === TradeType.EXACT_INPUT ? 'ExactIn' : 'ExactOut';
|
|
1866
|
+
}
|
|
1867
|
+
tokenPairSymbolTradeTypeChainId(currencyIn, currencyOut, tradeType) {
|
|
1868
|
+
return `${currencyIn.symbol}/${currencyOut.symbol}/${this.tradeTypeStr(tradeType)}/${this.chainId}`;
|
|
1869
|
+
}
|
|
1870
|
+
determineCurrencyInOutFromTradeType(tradeType, amount, quoteCurrency) {
|
|
1871
|
+
if (tradeType === TradeType.EXACT_INPUT) {
|
|
1872
|
+
return {
|
|
1873
|
+
currencyIn: amount.currency,
|
|
1874
|
+
currencyOut: quoteCurrency,
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
else {
|
|
1878
|
+
return {
|
|
1879
|
+
currencyIn: quoteCurrency,
|
|
1880
|
+
currencyOut: amount.currency,
|
|
1881
|
+
};
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
async getGasPriceWei(latestBlockNumber, requestBlockNumber) {
|
|
1885
|
+
// Track how long it takes to resolve this async call.
|
|
1886
|
+
const beforeGasTimestamp = Date.now();
|
|
1887
|
+
// Get an estimate of the gas price to use when estimating gas cost of different routes.
|
|
1888
|
+
const { gasPriceWei } = await this.gasPriceProvider.getGasPrice(latestBlockNumber, requestBlockNumber);
|
|
1889
|
+
metric.putMetric('GasPriceLoad', Date.now() - beforeGasTimestamp, MetricLoggerUnit.Milliseconds);
|
|
1890
|
+
return gasPriceWei;
|
|
1891
|
+
}
|
|
1892
|
+
async getGasModels(gasPriceWei, amountToken, quoteToken, providerConfig) {
|
|
1893
|
+
var _a, _c, _d;
|
|
1894
|
+
const beforeGasModel = Date.now();
|
|
1895
|
+
const fewQuoteToken = isFewToken(quoteToken)
|
|
1896
|
+
? quoteToken
|
|
1897
|
+
: getFewTokenFromOriginalToken(quoteToken, this.chainId);
|
|
1898
|
+
const fewAmountToken = isFewToken(amountToken)
|
|
1899
|
+
? amountToken
|
|
1900
|
+
: getFewTokenFromOriginalToken(amountToken, this.chainId);
|
|
1901
|
+
const usdPoolPromise = getHighestLiquidityV3USDPool(this.chainId, this.v3PoolProvider, providerConfig);
|
|
1902
|
+
const fewUsdPoolPromise = getHighestLiquidityV3FewTokenUSDPool(this.chainId, this.v3PoolProvider, providerConfig);
|
|
1903
|
+
const nativeCurrency = WRAPPED_NATIVE_CURRENCY[this.chainId];
|
|
1904
|
+
const fewNativeCurrency = FEW_WRAPPED_NATIVE_CURRENCY[this.chainId];
|
|
1905
|
+
const nativeAndQuoteTokenV3PoolPromise = !quoteToken.equals(nativeCurrency)
|
|
1906
|
+
? getHighestLiquidityV3NativePool(quoteToken, this.v3PoolProvider, providerConfig)
|
|
1907
|
+
: Promise.resolve(null);
|
|
1908
|
+
const nativeAndAmountTokenV3PoolPromise = !amountToken.equals(nativeCurrency)
|
|
1909
|
+
? getHighestLiquidityV3NativePool(amountToken, this.v3PoolProvider, providerConfig)
|
|
1910
|
+
: Promise.resolve(null);
|
|
1911
|
+
const fewNativeAndQuoteTokenV3PoolPromise = !fewQuoteToken.equals(fewNativeCurrency)
|
|
1912
|
+
? getHighestLiquidityV3NativeFewTokenPool(fewQuoteToken, this.v3PoolProvider, providerConfig)
|
|
1913
|
+
: Promise.resolve(null);
|
|
1914
|
+
const fewNativeAndAmountTokenV3PoolPromise = !fewAmountToken.equals(fewNativeCurrency)
|
|
1915
|
+
? getHighestLiquidityV3NativeFewTokenPool(fewAmountToken, this.v3PoolProvider, providerConfig)
|
|
1916
|
+
: Promise.resolve(null);
|
|
1917
|
+
// If a specific gas token is specified in the provider config
|
|
1918
|
+
// fetch the highest liq V3 pool with it and the native currency
|
|
1919
|
+
const nativeAndSpecifiedGasTokenV3PoolPromise = (providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.gasToken) &&
|
|
1920
|
+
!(providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.gasToken.equals(nativeCurrency))
|
|
1921
|
+
? getHighestLiquidityV3NativePool(providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.gasToken, this.v3PoolProvider, providerConfig)
|
|
1922
|
+
: Promise.resolve(null);
|
|
1923
|
+
// If a specific gas token is specified in the provider config
|
|
1924
|
+
// fetch the highest liq V3 pool with it and the native currency
|
|
1925
|
+
const fewNativeAndSpecifiedGasTokenV3PoolPromise = (providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.gasToken) &&
|
|
1926
|
+
!(providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.gasToken.equals(fewNativeCurrency))
|
|
1927
|
+
? getHighestLiquidityV3NativeFewTokenPool(providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.gasToken, this.v3PoolProvider, providerConfig)
|
|
1928
|
+
: Promise.resolve(null);
|
|
1929
|
+
const [usdPool, fewUsdPool, nativeAndQuoteTokenV3Pool, fewNativeAndQuoteTokenV3Pool, nativeAndAmountTokenV3Pool, fewNativeAndAmountTokenV3Pool, nativeAndSpecifiedGasTokenV3Pool, fewNativeAndSpecifiedGasTokenV3Pool,] = await Promise.all([
|
|
1930
|
+
usdPoolPromise,
|
|
1931
|
+
fewUsdPoolPromise,
|
|
1932
|
+
nativeAndQuoteTokenV3PoolPromise,
|
|
1933
|
+
fewNativeAndQuoteTokenV3PoolPromise,
|
|
1934
|
+
nativeAndAmountTokenV3PoolPromise,
|
|
1935
|
+
fewNativeAndAmountTokenV3PoolPromise,
|
|
1936
|
+
nativeAndSpecifiedGasTokenV3PoolPromise,
|
|
1937
|
+
fewNativeAndSpecifiedGasTokenV3PoolPromise,
|
|
1938
|
+
]);
|
|
1939
|
+
const pools = {
|
|
1940
|
+
usdPool: usdPool,
|
|
1941
|
+
nativeAndQuoteTokenV3Pool: nativeAndQuoteTokenV3Pool,
|
|
1942
|
+
nativeAndAmountTokenV3Pool: nativeAndAmountTokenV3Pool,
|
|
1943
|
+
nativeAndSpecifiedGasTokenV3Pool: nativeAndSpecifiedGasTokenV3Pool,
|
|
1944
|
+
};
|
|
1945
|
+
const fewPools = {
|
|
1946
|
+
usdPool: fewUsdPool,
|
|
1947
|
+
nativeAndQuoteTokenV3Pool: fewNativeAndQuoteTokenV3Pool,
|
|
1948
|
+
nativeAndAmountTokenV3Pool: fewNativeAndAmountTokenV3Pool,
|
|
1949
|
+
nativeAndSpecifiedGasTokenV3Pool: fewNativeAndSpecifiedGasTokenV3Pool,
|
|
1950
|
+
};
|
|
1951
|
+
const v2GasModelPromise = ((_a = this.v2Supported) === null || _a === void 0 ? void 0 : _a.includes(this.chainId))
|
|
1952
|
+
? this.v2GasModelFactory
|
|
1953
|
+
.buildGasModel({
|
|
1954
|
+
chainId: this.chainId,
|
|
1955
|
+
gasPriceWei,
|
|
1956
|
+
poolProvider: this.v2PoolProvider,
|
|
1957
|
+
token: quoteToken,
|
|
1958
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
1959
|
+
providerConfig: providerConfig,
|
|
1960
|
+
})
|
|
1961
|
+
.catch((_) => undefined) // If v2 model throws uncaught exception, we return undefined v2 gas model, so there's a chance v3 route can go through
|
|
1962
|
+
: Promise.resolve(undefined);
|
|
1963
|
+
// uniswap fewtoken
|
|
1964
|
+
const fewV2GasModelPromise = ((_c = this.v2Supported) === null || _c === void 0 ? void 0 : _c.includes(this.chainId))
|
|
1965
|
+
? this.v2GasModelFactory
|
|
1966
|
+
.buildGasModel({
|
|
1967
|
+
chainId: this.chainId,
|
|
1968
|
+
gasPriceWei,
|
|
1969
|
+
poolProvider: this.v2PoolProvider,
|
|
1970
|
+
token: fewQuoteToken,
|
|
1971
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
1972
|
+
providerConfig: providerConfig,
|
|
1973
|
+
})
|
|
1974
|
+
.catch((_) => undefined) // If v2 model throws uncaught exception, we return undefined v2 gas model, so there's a chance v3 route can go through
|
|
1975
|
+
: Promise.resolve(undefined);
|
|
1976
|
+
const ringFewV2GasModelPromise = ((_d = this.ringFewV2Supported) === null || _d === void 0 ? void 0 : _d.includes(this.chainId))
|
|
1977
|
+
? this.ringFewV2GasModelFactory
|
|
1978
|
+
.buildGasModel({
|
|
1979
|
+
chainId: this.chainId,
|
|
1980
|
+
gasPriceWei,
|
|
1981
|
+
poolProvider: this.ringFewV2PoolProvider,
|
|
1982
|
+
token: quoteToken,
|
|
1983
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
1984
|
+
providerConfig: providerConfig,
|
|
1985
|
+
})
|
|
1986
|
+
.catch((_) => undefined) // If v2 model throws uncaught exception, we return undefined v2 gas model, so there's a chance v3 route can go through
|
|
1987
|
+
: Promise.resolve(undefined);
|
|
1988
|
+
const v3GasModelPromise = this.v3GasModelFactory.buildGasModel({
|
|
1989
|
+
chainId: this.chainId,
|
|
1990
|
+
gasPriceWei,
|
|
1991
|
+
pools,
|
|
1992
|
+
amountToken,
|
|
1993
|
+
quoteToken,
|
|
1994
|
+
v2poolProvider: this.v2PoolProvider,
|
|
1995
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
1996
|
+
providerConfig: providerConfig,
|
|
1997
|
+
});
|
|
1998
|
+
const fewV3GasModelPromise = this.uniswapFewV3GasModelFactory.buildGasModel({
|
|
1999
|
+
chainId: this.chainId,
|
|
2000
|
+
gasPriceWei,
|
|
2001
|
+
pools: fewPools,
|
|
2002
|
+
amountToken: fewAmountToken,
|
|
2003
|
+
quoteToken: fewQuoteToken,
|
|
2004
|
+
v2poolProvider: this.v2PoolProvider,
|
|
2005
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
2006
|
+
providerConfig: providerConfig,
|
|
2007
|
+
});
|
|
2008
|
+
const v4GasModelPromise = this.v4GasModelFactory.buildGasModel({
|
|
2009
|
+
chainId: this.chainId,
|
|
2010
|
+
gasPriceWei,
|
|
2011
|
+
pools,
|
|
2012
|
+
amountToken,
|
|
2013
|
+
quoteToken,
|
|
2014
|
+
v2poolProvider: this.v2PoolProvider,
|
|
2015
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
2016
|
+
providerConfig: providerConfig,
|
|
2017
|
+
});
|
|
2018
|
+
const fewV4GasModelPromise = this.uniswapFewV4GasModelFactory.buildGasModel({
|
|
2019
|
+
chainId: this.chainId,
|
|
2020
|
+
gasPriceWei,
|
|
2021
|
+
pools: fewPools,
|
|
2022
|
+
amountToken: fewAmountToken,
|
|
2023
|
+
quoteToken: fewQuoteToken,
|
|
2024
|
+
v2poolProvider: this.v2PoolProvider,
|
|
2025
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
2026
|
+
providerConfig: providerConfig,
|
|
2027
|
+
});
|
|
2028
|
+
const mixedRouteGasModelPromise = this.mixedRouteGasModelFactory.buildGasModel({
|
|
2029
|
+
chainId: this.chainId,
|
|
2030
|
+
gasPriceWei,
|
|
2031
|
+
pools,
|
|
2032
|
+
amountToken,
|
|
2033
|
+
quoteToken,
|
|
2034
|
+
v2poolProvider: this.v2PoolProvider,
|
|
2035
|
+
providerConfig: providerConfig,
|
|
2036
|
+
});
|
|
2037
|
+
const [ringFewV2GasModel, v2GasModel, fewV2GasModel, v3GasModel, fewV3GasModel, v4GasModel, fewV4GasModel, mixedRouteGasModel] = await Promise.all([
|
|
2038
|
+
ringFewV2GasModelPromise,
|
|
2039
|
+
v2GasModelPromise,
|
|
2040
|
+
fewV2GasModelPromise,
|
|
2041
|
+
v3GasModelPromise,
|
|
2042
|
+
fewV3GasModelPromise,
|
|
2043
|
+
v4GasModelPromise,
|
|
2044
|
+
fewV4GasModelPromise,
|
|
2045
|
+
mixedRouteGasModelPromise,
|
|
2046
|
+
]);
|
|
2047
|
+
metric.putMetric('GasModelCreation', Date.now() - beforeGasModel, MetricLoggerUnit.Milliseconds);
|
|
2048
|
+
return {
|
|
2049
|
+
ringFewV2GasModel: ringFewV2GasModel,
|
|
2050
|
+
v2GasModel: v2GasModel,
|
|
2051
|
+
fewV2GasModel: fewV2GasModel,
|
|
2052
|
+
v3GasModel: v3GasModel,
|
|
2053
|
+
fewV3GasModel: fewV3GasModel,
|
|
2054
|
+
v4GasModel: v4GasModel,
|
|
2055
|
+
fewV4GasModel: fewV4GasModel,
|
|
2056
|
+
mixedRouteGasModel: mixedRouteGasModel,
|
|
2057
|
+
};
|
|
2058
|
+
}
|
|
2059
|
+
// Note multiplications here can result in a loss of precision in the amounts (e.g. taking 50% of 101)
|
|
2060
|
+
// This is reconcilled at the end of the algorithm by adding any lost precision to one of
|
|
2061
|
+
// the splits in the route.
|
|
2062
|
+
getAmountDistribution(amount, routingConfig) {
|
|
2063
|
+
const { distributionPercent } = routingConfig;
|
|
2064
|
+
const percents = [];
|
|
2065
|
+
const amounts = [];
|
|
2066
|
+
for (let i = 1; i <= 100 / distributionPercent; i++) {
|
|
2067
|
+
percents.push(i * distributionPercent);
|
|
2068
|
+
amounts.push(amount.multiply(new Fraction(i * distributionPercent, 100)));
|
|
2069
|
+
}
|
|
2070
|
+
return [percents, amounts];
|
|
2071
|
+
}
|
|
2072
|
+
async buildSwapAndAddMethodParameters(trade, swapAndAddOptions, swapAndAddParameters) {
|
|
2073
|
+
const { swapOptions: { recipient, slippageTolerance, deadline, inputTokenPermit }, addLiquidityOptions: addLiquidityConfig, } = swapAndAddOptions;
|
|
2074
|
+
const preLiquidityPosition = swapAndAddParameters.preLiquidityPosition;
|
|
2075
|
+
const finalBalanceTokenIn = swapAndAddParameters.initialBalanceTokenIn.subtract(trade.inputAmount);
|
|
2076
|
+
const finalBalanceTokenOut = swapAndAddParameters.initialBalanceTokenOut.add(trade.outputAmount);
|
|
2077
|
+
const approvalTypes = await this.swapRouterProvider.getApprovalType(finalBalanceTokenIn, finalBalanceTokenOut);
|
|
2078
|
+
const zeroForOne = finalBalanceTokenIn.currency.wrapped.sortsBefore(finalBalanceTokenOut.currency.wrapped);
|
|
2079
|
+
return {
|
|
2080
|
+
...SwapRouter.swapAndAddCallParameters(trade, {
|
|
2081
|
+
recipient,
|
|
2082
|
+
slippageTolerance,
|
|
2083
|
+
deadlineOrPreviousBlockhash: deadline,
|
|
2084
|
+
inputTokenPermit,
|
|
2085
|
+
}, Position.fromAmounts({
|
|
2086
|
+
pool: preLiquidityPosition.pool,
|
|
2087
|
+
tickLower: preLiquidityPosition.tickLower,
|
|
2088
|
+
tickUpper: preLiquidityPosition.tickUpper,
|
|
2089
|
+
amount0: zeroForOne
|
|
2090
|
+
? finalBalanceTokenIn.quotient.toString()
|
|
2091
|
+
: finalBalanceTokenOut.quotient.toString(),
|
|
2092
|
+
amount1: zeroForOne
|
|
2093
|
+
? finalBalanceTokenOut.quotient.toString()
|
|
2094
|
+
: finalBalanceTokenIn.quotient.toString(),
|
|
2095
|
+
useFullPrecision: false,
|
|
2096
|
+
}), addLiquidityConfig, approvalTypes.approvalTokenIn, approvalTypes.approvalTokenOut),
|
|
2097
|
+
to: SWAP_ROUTER_02_ADDRESSES(this.chainId),
|
|
2098
|
+
};
|
|
2099
|
+
}
|
|
2100
|
+
// @ts-ignore
|
|
2101
|
+
emitPoolSelectionMetrics(swapRouteRaw, allPoolsBySelection, currencyIn, currencyOut) {
|
|
2102
|
+
const poolAddressesUsed = new Set();
|
|
2103
|
+
const { routes: routeAmounts } = swapRouteRaw;
|
|
2104
|
+
_(routeAmounts)
|
|
2105
|
+
.flatMap((routeAmount) => {
|
|
2106
|
+
const { poolIdentifiers: poolAddresses } = routeAmount;
|
|
2107
|
+
return poolAddresses;
|
|
2108
|
+
})
|
|
2109
|
+
.forEach((address) => {
|
|
2110
|
+
poolAddressesUsed.add(address.toLowerCase());
|
|
2111
|
+
});
|
|
2112
|
+
for (const poolsBySelection of allPoolsBySelection) {
|
|
2113
|
+
const { protocol } = poolsBySelection;
|
|
2114
|
+
_.forIn(poolsBySelection.selections, (pools, topNSelection) => {
|
|
2115
|
+
const topNUsed = _.findLastIndex(pools, (pool) => poolAddressesUsed.has(pool.id.toLowerCase())) + 1;
|
|
2116
|
+
metric.putMetric(_.capitalize(`${protocol}${topNSelection}`), topNUsed, MetricLoggerUnit.Count);
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
let hasV4Route = false;
|
|
2120
|
+
let hasV3Route = false;
|
|
2121
|
+
let hasV2Route = false;
|
|
2122
|
+
let hasMixedRoute = false;
|
|
2123
|
+
for (const routeAmount of routeAmounts) {
|
|
2124
|
+
if (routeAmount.protocol === Protocol.V4) {
|
|
2125
|
+
hasV4Route = true;
|
|
2126
|
+
}
|
|
2127
|
+
if (routeAmount.protocol === Protocol.V3) {
|
|
2128
|
+
hasV3Route = true;
|
|
2129
|
+
}
|
|
2130
|
+
if (routeAmount.protocol === Protocol.V2) {
|
|
2131
|
+
hasV2Route = true;
|
|
2132
|
+
}
|
|
2133
|
+
if (routeAmount.protocol === Protocol.MIXED) {
|
|
2134
|
+
hasMixedRoute = true;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
if (hasMixedRoute && (hasV4Route || hasV3Route || hasV2Route)) {
|
|
2138
|
+
let metricsPrefix = 'Mixed';
|
|
2139
|
+
if (hasV4Route) {
|
|
2140
|
+
metricsPrefix += 'AndV4';
|
|
2141
|
+
}
|
|
2142
|
+
if (hasV3Route) {
|
|
2143
|
+
metricsPrefix += 'AndV3';
|
|
2144
|
+
}
|
|
2145
|
+
if (hasV2Route) {
|
|
2146
|
+
metricsPrefix += 'AndV2';
|
|
2147
|
+
}
|
|
2148
|
+
metric.putMetric(`${metricsPrefix}SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
2149
|
+
metric.putMetric(`${metricsPrefix}SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2150
|
+
if (hasV4Route && (currencyIn.isNative || currencyOut.isNative)) {
|
|
2151
|
+
// Keep track of this edge case https://linear.app/uniswap/issue/ROUTE-303/tech-debt-split-route-can-have-different-ethweth-input-or-output#comment-bba53758
|
|
2152
|
+
metric.putMetric(`${metricsPrefix}SplitRouteWithNativeToken`, 1, MetricLoggerUnit.Count);
|
|
2153
|
+
metric.putMetric(`${metricsPrefix}SplitRouteWithNativeTokenForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
else if (hasV4Route && hasV3Route && hasV2Route) {
|
|
2157
|
+
metric.putMetric(`V4AndV3AndV2SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
2158
|
+
metric.putMetric(`V4AndV3AndV2SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2159
|
+
if (currencyIn.isNative || currencyOut.isNative) {
|
|
2160
|
+
// Keep track of this edge case https://linear.app/uniswap/issue/ROUTE-303/tech-debt-split-route-can-have-different-ethweth-input-or-output#comment-bba53758
|
|
2161
|
+
metric.putMetric(`V4AndV3AndV2SplitRouteWithNativeToken`, 1, MetricLoggerUnit.Count);
|
|
2162
|
+
metric.putMetric(`V4AndV3AndV2SplitRouteWithNativeTokenForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
else if (hasMixedRoute) {
|
|
2166
|
+
if (routeAmounts.length > 1) {
|
|
2167
|
+
metric.putMetric(`MixedSplitRoute`, 1, MetricLoggerUnit.Count);
|
|
2168
|
+
metric.putMetric(`MixedSplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2169
|
+
}
|
|
2170
|
+
else {
|
|
2171
|
+
metric.putMetric(`MixedRoute`, 1, MetricLoggerUnit.Count);
|
|
2172
|
+
metric.putMetric(`MixedRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
else if (hasV4Route) {
|
|
2176
|
+
if (routeAmounts.length > 1) {
|
|
2177
|
+
metric.putMetric(`V4SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
2178
|
+
metric.putMetric(`V4SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
else if (hasV3Route) {
|
|
2182
|
+
if (routeAmounts.length > 1) {
|
|
2183
|
+
metric.putMetric(`V3SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
2184
|
+
metric.putMetric(`V3SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2185
|
+
}
|
|
2186
|
+
else {
|
|
2187
|
+
metric.putMetric(`V3Route`, 1, MetricLoggerUnit.Count);
|
|
2188
|
+
metric.putMetric(`V3RouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
else if (hasV2Route) {
|
|
2192
|
+
if (routeAmounts.length > 1) {
|
|
2193
|
+
metric.putMetric(`V2SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
2194
|
+
metric.putMetric(`V2SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2195
|
+
}
|
|
2196
|
+
else {
|
|
2197
|
+
metric.putMetric(`V2Route`, 1, MetricLoggerUnit.Count);
|
|
2198
|
+
metric.putMetric(`V2RouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
calculateOptimalRatio(position, sqrtRatioX96, zeroForOne) {
|
|
2203
|
+
const upperSqrtRatioX96 = TickMath.getSqrtRatioAtTick(position.tickUpper);
|
|
2204
|
+
const lowerSqrtRatioX96 = TickMath.getSqrtRatioAtTick(position.tickLower);
|
|
2205
|
+
// returns Fraction(0, 1) for any out of range position regardless of zeroForOne. Implication: function
|
|
2206
|
+
// cannot be used to determine the trading direction of out of range positions.
|
|
2207
|
+
if (JSBI.greaterThan(sqrtRatioX96, upperSqrtRatioX96) ||
|
|
2208
|
+
JSBI.lessThan(sqrtRatioX96, lowerSqrtRatioX96)) {
|
|
2209
|
+
return new Fraction(0, 1);
|
|
2210
|
+
}
|
|
2211
|
+
const precision = JSBI.BigInt('1' + '0'.repeat(18));
|
|
2212
|
+
let optimalRatio = new Fraction(SqrtPriceMath.getAmount0Delta(sqrtRatioX96, upperSqrtRatioX96, precision, true), SqrtPriceMath.getAmount1Delta(sqrtRatioX96, lowerSqrtRatioX96, precision, true));
|
|
2213
|
+
if (!zeroForOne)
|
|
2214
|
+
optimalRatio = optimalRatio.invert();
|
|
2215
|
+
return optimalRatio;
|
|
2216
|
+
}
|
|
2217
|
+
async userHasSufficientBalance(fromAddress, tradeType, amount, quote) {
|
|
2218
|
+
try {
|
|
2219
|
+
const neededBalance = tradeType === TradeType.EXACT_INPUT ? amount : quote;
|
|
2220
|
+
let balance;
|
|
2221
|
+
if (neededBalance.currency.isNative) {
|
|
2222
|
+
balance = await this.provider.getBalance(fromAddress);
|
|
2223
|
+
}
|
|
2224
|
+
else {
|
|
2225
|
+
const tokenContract = Erc20__factory.connect(neededBalance.currency.address, this.provider);
|
|
2226
|
+
balance = await tokenContract.balanceOf(fromAddress);
|
|
2227
|
+
}
|
|
2228
|
+
return balance.gte(BigNumber.from(neededBalance.quotient.toString()));
|
|
2229
|
+
}
|
|
2230
|
+
catch (e) {
|
|
2231
|
+
log.error(e, 'Error while checking user balance');
|
|
2232
|
+
return false;
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
absoluteValue(fraction) {
|
|
2236
|
+
const numeratorAbs = JSBI.lessThan(fraction.numerator, JSBI.BigInt(0))
|
|
2237
|
+
? JSBI.unaryMinus(fraction.numerator)
|
|
2238
|
+
: fraction.numerator;
|
|
2239
|
+
const denominatorAbs = JSBI.lessThan(fraction.denominator, JSBI.BigInt(0))
|
|
2240
|
+
? JSBI.unaryMinus(fraction.denominator)
|
|
2241
|
+
: fraction.denominator;
|
|
2242
|
+
return new Fraction(numeratorAbs, denominatorAbs);
|
|
2243
|
+
}
|
|
2244
|
+
getBlockNumberPromise() {
|
|
2245
|
+
return retry(async (_b, attempt) => {
|
|
2246
|
+
if (attempt > 1) {
|
|
2247
|
+
log.info(`Get block number attempt ${attempt}`);
|
|
2248
|
+
}
|
|
2249
|
+
return this.provider.getBlockNumber();
|
|
2250
|
+
}, {
|
|
2251
|
+
retries: 2,
|
|
2252
|
+
minTimeout: 100,
|
|
2253
|
+
maxTimeout: 1000,
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
// If we are requesting URv1.2, we need to keep entering cache
|
|
2257
|
+
// We want to skip cached routes access whenever "intent === INTENT.CACHING" or "hooksOption !== HooksOption.HOOKS_INCLUSIVE"
|
|
2258
|
+
// We keep this method as we might want to add more conditions in the future.
|
|
2259
|
+
static isAllowedToEnterCachedRoutes(intent, hooksOptions, swapRouter) {
|
|
2260
|
+
// intent takes highest precedence, as we need to ensure during caching intent, we do not enter cache no matter what
|
|
2261
|
+
if (intent !== undefined && intent === INTENT.CACHING) {
|
|
2262
|
+
return false;
|
|
2263
|
+
}
|
|
2264
|
+
// in case we have URv1.2 request during QUOTE intent, we assume cached routes correctly returns mixed route w/o v4, if mixed is best
|
|
2265
|
+
// or v2/v3 is the best.
|
|
2266
|
+
// implicitly it means hooksOptions no longer matters for URv1.2
|
|
2267
|
+
// swapRouter has higher precedence than hooksOptions, because in case of URv1.2, we set hooksOptions = NO_HOOKS as default,
|
|
2268
|
+
// but swapRouter does not have any v4 pool for routing, so swapRouter should always use caching during QUOTE intent.
|
|
2269
|
+
if (swapRouter) {
|
|
2270
|
+
return true;
|
|
2271
|
+
}
|
|
2272
|
+
// in case we have URv2.0, and we are in QUOTE intent, we only want to enter cache when hooksOptions is default, HOOKS_INCLUSIVE
|
|
2273
|
+
if (hooksOptions !== undefined &&
|
|
2274
|
+
hooksOptions !== HooksOptions.HOOKS_INCLUSIVE) {
|
|
2275
|
+
return false;
|
|
2276
|
+
}
|
|
2277
|
+
return true;
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxwaGEtcm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3JvdXRlcnMvYWxwaGEtcm91dGVyL2FscGhhLXJvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckQsT0FBTyxFQUFnQixlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RSxPQUFPLGtCQUFrQixNQUFNLDZCQUE2QixDQUFDO0FBQzdELE9BQU8sRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFTLElBQUksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzlFLE9BQU8sRUFDTCxPQUFPLEVBRVAsUUFBUSxFQUNSLEtBQUssRUFDTCxTQUFTLEdBQ1YsTUFBTSx5QkFBeUIsQ0FBQztBQUVqQyxPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxhQUFhLEVBQUUsUUFBUSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDaEYsT0FBTyxLQUFLLE1BQU0sYUFBYSxDQUFDO0FBQ2hDLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUN4QixPQUFPLENBQUMsTUFBTSxRQUFRLENBQUM7QUFDdkIsT0FBTyxTQUFTLE1BQU0sWUFBWSxDQUFDO0FBRW5DLE9BQU8sRUFDTCxZQUFZLEVBQ1osU0FBUyxFQUNULHlCQUF5QixFQUN6QixnQ0FBZ0MsRUFDaEMscUJBQXFCO0FBQ3JCLDZCQUE2QjtBQUM3QixxQkFBcUI7QUFDckIsNkJBQTZCO0FBQzdCLDZCQUE2QjtBQUM3Qix1QkFBdUIsRUFDdkIseUJBQXlCLEVBV3pCLHNCQUFzQixFQUN0QixXQUFXLEVBQ1gsdUJBQXVCLEVBQ3ZCLG9CQUFvQixFQUNwQiw0QkFBNEI7QUFDNUIsb0NBQW9DO0FBQ3BDLCtCQUErQixFQUMvQixzQ0FBc0MsRUFDdEMseUJBQXlCLEVBQ3pCLGtCQUFrQixFQUNsQixtQkFBbUIsRUFDbkIsZ0JBQWdCLEVB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
|