v-swap-smart-order-router 3.10.2
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 +248 -0
- package/build/main/index.d.ts +3 -0
- package/build/main/index.js +20 -0
- package/build/main/providers/cache-node.d.ts +9 -0
- package/build/main/providers/cache-node.js +19 -0
- package/build/main/providers/cache.d.ts +13 -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 +26 -0
- package/build/main/providers/caching/route/model/cached-route.js +30 -0
- package/build/main/providers/caching/route/model/cached-routes.d.ts +63 -0
- package/build/main/providers/caching/route/model/cached-routes.js +73 -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 +91 -0
- package/build/main/providers/caching/route/route-caching-provider.js +65 -0
- package/build/main/providers/caching-gas-provider.d.ts +23 -0
- package/build/main/providers/caching-gas-provider.js +37 -0
- package/build/main/providers/caching-token-list-provider.d.ts +40 -0
- package/build/main/providers/caching-token-list-provider.js +123 -0
- package/build/main/providers/caching-token-provider.d.ts +25 -0
- package/build/main/providers/caching-token-provider.js +202 -0
- package/build/main/providers/eip-1559-gas-price-provider.d.ts +31 -0
- package/build/main/providers/eip-1559-gas-price-provider.js +66 -0
- package/build/main/providers/eth-estimate-gas-provider.d.ts +16 -0
- package/build/main/providers/eth-estimate-gas-provider.js +74 -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 +37 -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 +37 -0
- package/build/main/providers/index.js +54 -0
- package/build/main/providers/legacy-gas-price-provider.d.ts +7 -0
- package/build/main/providers/legacy-gas-price-provider.js +20 -0
- package/build/main/providers/multicall-provider.d.ts +82 -0
- package/build/main/providers/multicall-provider.js +15 -0
- package/build/main/providers/multicall-uniswap-provider.d.ts +37 -0
- package/build/main/providers/multicall-uniswap-provider.js +163 -0
- package/build/main/providers/on-chain-gas-price-provider.d.ts +19 -0
- package/build/main/providers/on-chain-gas-price-provider.js +38 -0
- package/build/main/providers/on-chain-quote-provider.d.ts +221 -0
- package/build/main/providers/on-chain-quote-provider.js +523 -0
- package/build/main/providers/provider.d.ts +10 -0
- package/build/main/providers/provider.js +3 -0
- package/build/main/providers/simulation-provider.d.ts +42 -0
- package/build/main/providers/simulation-provider.js +130 -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/swap-router-provider.d.ts +31 -0
- package/build/main/providers/swap-router-provider.js +42 -0
- package/build/main/providers/tenderly-simulation-provider.d.ts +45 -0
- package/build/main/providers/tenderly-simulation-provider.js +254 -0
- package/build/main/providers/token-provider.d.ts +114 -0
- package/build/main/providers/token-provider.js +297 -0
- package/build/main/providers/token-validator-provider.d.ts +42 -0
- package/build/main/providers/token-validator-provider.js +95 -0
- package/build/main/providers/uri-subgraph-provider.d.ts +20 -0
- package/build/main/providers/uri-subgraph-provider.js +65 -0
- package/build/main/providers/v2/caching-pool-provider.d.ts +34 -0
- package/build/main/providers/v2/caching-pool-provider.js +88 -0
- package/build/main/providers/v2/caching-subgraph-provider.d.ts +23 -0
- package/build/main/providers/v2/caching-subgraph-provider.js +34 -0
- package/build/main/providers/v2/pool-provider.d.ts +60 -0
- package/build/main/providers/v2/pool-provider.js +110 -0
- package/build/main/providers/v2/quote-provider.d.ts +33 -0
- package/build/main/providers/v2/quote-provider.js +91 -0
- package/build/main/providers/v2/static-subgraph-provider.d.ts +20 -0
- package/build/main/providers/v2/static-subgraph-provider.js +103 -0
- package/build/main/providers/v2/subgraph-provider-with-fallback.d.ts +19 -0
- package/build/main/providers/v2/subgraph-provider-with-fallback.js +35 -0
- package/build/main/providers/v2/subgraph-provider.d.ts +34 -0
- package/build/main/providers/v2/subgraph-provider.js +135 -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 +33 -0
- package/build/main/providers/v3/caching-pool-provider.js +77 -0
- package/build/main/providers/v3/caching-subgraph-provider.d.ts +23 -0
- package/build/main/providers/v3/caching-subgraph-provider.js +34 -0
- package/build/main/providers/v3/gas-data-provider.d.ts +57 -0
- package/build/main/providers/v3/gas-data-provider.js +66 -0
- package/build/main/providers/v3/pool-provider.d.ts +61 -0
- package/build/main/providers/v3/pool-provider.js +123 -0
- package/build/main/providers/v3/static-subgraph-provider.d.ts +21 -0
- package/build/main/providers/v3/static-subgraph-provider.js +203 -0
- package/build/main/providers/v3/subgraph-provider-with-fallback.d.ts +15 -0
- package/build/main/providers/v3/subgraph-provider-with-fallback.js +31 -0
- package/build/main/providers/v3/subgraph-provider.d.ts +37 -0
- package/build/main/providers/v3/subgraph-provider.js +145 -0
- package/build/main/providers/v3/uri-subgraph-provider.d.ts +4 -0
- package/build/main/providers/v3/uri-subgraph-provider.js +8 -0
- package/build/main/routers/alpha-router/alpha-router.d.ts +267 -0
- package/build/main/routers/alpha-router/alpha-router.js +825 -0
- package/build/main/routers/alpha-router/config.d.ts +4 -0
- package/build/main/routers/alpha-router/config.js +93 -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 +163 -0
- package/build/main/routers/alpha-router/entities/route-with-valid-quote.js +143 -0
- package/build/main/routers/alpha-router/functions/best-swap-route.d.ts +19 -0
- package/build/main/routers/alpha-router/functions/best-swap-route.js +364 -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 +8 -0
- package/build/main/routers/alpha-router/functions/compute-all-routes.js +72 -0
- package/build/main/routers/alpha-router/functions/get-candidate-pools.d.ts +78 -0
- package/build/main/routers/alpha-router/functions/get-candidate-pools.js +761 -0
- package/build/main/routers/alpha-router/gas-models/gas-model.d.ts +83 -0
- package/build/main/routers/alpha-router/gas-models/gas-model.js +68 -0
- package/build/main/routers/alpha-router/gas-models/index.d.ts +2 -0
- package/build/main/routers/alpha-router/gas-models/index.js +19 -0
- package/build/main/routers/alpha-router/gas-models/mixedRoute/mixed-route-heuristic-gas-model.d.ts +25 -0
- package/build/main/routers/alpha-router/gas-models/mixedRoute/mixed-route-heuristic-gas-model.js +175 -0
- package/build/main/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.d.ts +29 -0
- package/build/main/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.js +167 -0
- package/build/main/routers/alpha-router/gas-models/v3/gas-costs.d.ts +6 -0
- package/build/main/routers/alpha-router/gas-models/v3/gas-costs.js +110 -0
- package/build/main/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.d.ts +31 -0
- package/build/main/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.js +288 -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 +68 -0
- package/build/main/routers/alpha-router/quoters/base-quoter.js +61 -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 +20 -0
- package/build/main/routers/alpha-router/quoters/mixed-quoter.js +130 -0
- package/build/main/routers/alpha-router/quoters/model/index.d.ts +1 -0
- package/build/main/routers/alpha-router/quoters/model/index.js +18 -0
- package/build/main/routers/alpha-router/quoters/model/results/get-quotes-result.d.ts +6 -0
- package/build/main/routers/alpha-router/quoters/model/results/get-quotes-result.js +3 -0
- package/build/main/routers/alpha-router/quoters/model/results/get-routes-result.d.ts +6 -0
- package/build/main/routers/alpha-router/quoters/model/results/get-routes-result.js +3 -0
- package/build/main/routers/alpha-router/quoters/model/results/index.d.ts +2 -0
- package/build/main/routers/alpha-router/quoters/model/results/index.js +19 -0
- package/build/main/routers/alpha-router/quoters/v2-quoter.d.ts +21 -0
- package/build/main/routers/alpha-router/quoters/v2-quoter.js +122 -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/index.d.ts +4 -0
- package/build/main/routers/index.js +21 -0
- package/build/main/routers/legacy-router/bases.d.ts +136 -0
- package/build/main/routers/legacy-router/bases.js +87 -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 +42 -0
- package/build/main/routers/legacy-router/legacy-router.js +289 -0
- package/build/main/routers/router.d.ts +165 -0
- package/build/main/routers/router.js +52 -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/GasPriceOracle__factory.d.ts +46 -0
- package/build/main/types/other/factories/GasPriceOracle__factory.js +316 -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/Permit2__factory.d.ts +87 -0
- package/build/main/types/other/factories/Permit2__factory.js +936 -0
- package/build/main/types/other/factories/SwapRouter02__factory.d.ts +67 -0
- package/build/main/types/other/factories/SwapRouter02__factory.js +1098 -0
- package/build/main/types/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 +26 -0
- package/build/main/util/addresses.js +73 -0
- package/build/main/util/amounts.d.ts +8 -0
- package/build/main/util/amounts.js +51 -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 +77 -0
- package/build/main/util/chains.js +564 -0
- package/build/main/util/gas-factory-helpers.d.ts +24 -0
- package/build/main/util/gas-factory-helpers.js +308 -0
- package/build/main/util/index.d.ts +7 -0
- package/build/main/util/index.js +24 -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 +108 -0
- package/build/main/util/metric.d.ts +48 -0
- package/build/main/util/metric.js +59 -0
- package/build/main/util/protocols.d.ts +2 -0
- package/build/main/util/protocols.js +18 -0
- package/build/main/util/routes.d.ts +8 -0
- package/build/main/util/routes.js +60 -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 +9 -0
- package/build/module/providers/cache-node.js +15 -0
- package/build/module/providers/cache.d.ts +13 -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 +26 -0
- package/build/module/providers/caching/route/model/cached-route.js +26 -0
- package/build/module/providers/caching/route/model/cached-routes.d.ts +63 -0
- package/build/module/providers/caching/route/model/cached-routes.js +66 -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 +91 -0
- package/build/module/providers/caching/route/route-caching-provider.js +61 -0
- package/build/module/providers/caching-gas-provider.d.ts +23 -0
- package/build/module/providers/caching-gas-provider.js +33 -0
- package/build/module/providers/caching-token-list-provider.d.ts +40 -0
- package/build/module/providers/caching-token-list-provider.js +116 -0
- package/build/module/providers/caching-token-provider.d.ts +25 -0
- package/build/module/providers/caching-token-provider.js +195 -0
- package/build/module/providers/eip-1559-gas-price-provider.d.ts +31 -0
- package/build/module/providers/eip-1559-gas-price-provider.js +59 -0
- package/build/module/providers/eth-estimate-gas-provider.d.ts +16 -0
- package/build/module/providers/eth-estimate-gas-provider.js +82 -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 +30 -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 +37 -0
- package/build/module/providers/index.js +38 -0
- package/build/module/providers/legacy-gas-price-provider.d.ts +7 -0
- package/build/module/providers/legacy-gas-price-provider.js +16 -0
- package/build/module/providers/multicall-provider.d.ts +82 -0
- package/build/module/providers/multicall-provider.js +11 -0
- package/build/module/providers/multicall-uniswap-provider.d.ts +37 -0
- package/build/module/providers/multicall-uniswap-provider.js +156 -0
- package/build/module/providers/on-chain-gas-price-provider.d.ts +19 -0
- package/build/module/providers/on-chain-gas-price-provider.js +34 -0
- package/build/module/providers/on-chain-quote-provider.d.ts +221 -0
- package/build/module/providers/on-chain-quote-provider.js +517 -0
- package/build/module/providers/provider.d.ts +10 -0
- package/build/module/providers/provider.js +2 -0
- package/build/module/providers/simulation-provider.d.ts +42 -0
- package/build/module/providers/simulation-provider.js +132 -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/swap-router-provider.d.ts +31 -0
- package/build/module/providers/swap-router-provider.js +38 -0
- package/build/module/providers/tenderly-simulation-provider.d.ts +45 -0
- package/build/module/providers/tenderly-simulation-provider.js +249 -0
- package/build/module/providers/token-provider.d.ts +114 -0
- package/build/module/providers/token-provider.js +285 -0
- package/build/module/providers/token-validator-provider.d.ts +42 -0
- package/build/module/providers/token-validator-provider.js +88 -0
- package/build/module/providers/uri-subgraph-provider.d.ts +20 -0
- package/build/module/providers/uri-subgraph-provider.js +58 -0
- package/build/module/providers/v2/caching-pool-provider.d.ts +34 -0
- package/build/module/providers/v2/caching-pool-provider.js +81 -0
- package/build/module/providers/v2/caching-subgraph-provider.d.ts +23 -0
- package/build/module/providers/v2/caching-subgraph-provider.js +30 -0
- package/build/module/providers/v2/pool-provider.d.ts +60 -0
- package/build/module/providers/v2/pool-provider.js +103 -0
- package/build/module/providers/v2/quote-provider.d.ts +33 -0
- package/build/module/providers/v2/quote-provider.js +87 -0
- package/build/module/providers/v2/static-subgraph-provider.d.ts +20 -0
- package/build/module/providers/v2/static-subgraph-provider.js +96 -0
- package/build/module/providers/v2/subgraph-provider-with-fallback.d.ts +19 -0
- package/build/module/providers/v2/subgraph-provider-with-fallback.js +31 -0
- package/build/module/providers/v2/subgraph-provider.d.ts +34 -0
- package/build/module/providers/v2/subgraph-provider.js +136 -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 +33 -0
- package/build/module/providers/v3/caching-pool-provider.js +70 -0
- package/build/module/providers/v3/caching-subgraph-provider.d.ts +23 -0
- package/build/module/providers/v3/caching-subgraph-provider.js +30 -0
- package/build/module/providers/v3/gas-data-provider.d.ts +57 -0
- package/build/module/providers/v3/gas-data-provider.js +61 -0
- package/build/module/providers/v3/pool-provider.d.ts +61 -0
- package/build/module/providers/v3/pool-provider.js +116 -0
- package/build/module/providers/v3/static-subgraph-provider.d.ts +21 -0
- package/build/module/providers/v3/static-subgraph-provider.js +200 -0
- package/build/module/providers/v3/subgraph-provider-with-fallback.d.ts +15 -0
- package/build/module/providers/v3/subgraph-provider-with-fallback.js +27 -0
- package/build/module/providers/v3/subgraph-provider.d.ts +37 -0
- package/build/module/providers/v3/subgraph-provider.js +132 -0
- package/build/module/providers/v3/uri-subgraph-provider.d.ts +4 -0
- package/build/module/providers/v3/uri-subgraph-provider.js +4 -0
- package/build/module/routers/alpha-router/alpha-router.d.ts +267 -0
- package/build/module/routers/alpha-router/alpha-router.js +823 -0
- package/build/module/routers/alpha-router/config.d.ts +4 -0
- package/build/module/routers/alpha-router/config.js +89 -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 +163 -0
- package/build/module/routers/alpha-router/entities/route-with-valid-quote.js +134 -0
- package/build/module/routers/alpha-router/functions/best-swap-route.d.ts +19 -0
- package/build/module/routers/alpha-router/functions/best-swap-route.js +356 -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 +8 -0
- package/build/module/routers/alpha-router/functions/compute-all-routes.js +65 -0
- package/build/module/routers/alpha-router/functions/get-candidate-pools.d.ts +78 -0
- package/build/module/routers/alpha-router/functions/get-candidate-pools.js +776 -0
- package/build/module/routers/alpha-router/gas-models/gas-model.d.ts +83 -0
- package/build/module/routers/alpha-router/gas-models/gas-model.js +67 -0
- package/build/module/routers/alpha-router/gas-models/index.d.ts +2 -0
- package/build/module/routers/alpha-router/gas-models/index.js +3 -0
- package/build/module/routers/alpha-router/gas-models/mixedRoute/mixed-route-heuristic-gas-model.d.ts +25 -0
- package/build/module/routers/alpha-router/gas-models/mixedRoute/mixed-route-heuristic-gas-model.js +168 -0
- package/build/module/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.d.ts +29 -0
- package/build/module/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.js +160 -0
- package/build/module/routers/alpha-router/gas-models/v3/gas-costs.d.ts +6 -0
- package/build/module/routers/alpha-router/gas-models/v3/gas-costs.js +104 -0
- package/build/module/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.d.ts +31 -0
- package/build/module/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.js +281 -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 +68 -0
- package/build/module/routers/alpha-router/quoters/base-quoter.js +54 -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 +20 -0
- package/build/module/routers/alpha-router/quoters/mixed-quoter.js +123 -0
- package/build/module/routers/alpha-router/quoters/model/index.d.ts +1 -0
- package/build/module/routers/alpha-router/quoters/model/index.js +2 -0
- package/build/module/routers/alpha-router/quoters/model/results/get-quotes-result.d.ts +6 -0
- package/build/module/routers/alpha-router/quoters/model/results/get-quotes-result.js +2 -0
- package/build/module/routers/alpha-router/quoters/model/results/get-routes-result.d.ts +6 -0
- package/build/module/routers/alpha-router/quoters/model/results/get-routes-result.js +2 -0
- package/build/module/routers/alpha-router/quoters/model/results/index.d.ts +2 -0
- package/build/module/routers/alpha-router/quoters/model/results/index.js +3 -0
- package/build/module/routers/alpha-router/quoters/v2-quoter.d.ts +21 -0
- package/build/module/routers/alpha-router/quoters/v2-quoter.js +115 -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/index.d.ts +4 -0
- package/build/module/routers/index.js +5 -0
- package/build/module/routers/legacy-router/bases.d.ts +136 -0
- package/build/module/routers/legacy-router/bases.js +93 -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 +42 -0
- package/build/module/routers/legacy-router/legacy-router.js +290 -0
- package/build/module/routers/router.d.ts +165 -0
- package/build/module/routers/router.js +44 -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/GasPriceOracle__factory.d.ts +46 -0
- package/build/module/types/other/factories/GasPriceOracle__factory.js +312 -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/Permit2__factory.d.ts +87 -0
- package/build/module/types/other/factories/Permit2__factory.js +932 -0
- package/build/module/types/other/factories/SwapRouter02__factory.d.ts +67 -0
- package/build/module/types/other/factories/SwapRouter02__factory.js +1094 -0
- package/build/module/types/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 +26 -0
- package/build/module/util/addresses.js +98 -0
- package/build/module/util/amounts.d.ts +8 -0
- package/build/module/util/amounts.js +41 -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 +77 -0
- package/build/module/util/chains.js +556 -0
- package/build/module/util/gas-factory-helpers.d.ts +24 -0
- package/build/module/util/gas-factory-helpers.js +291 -0
- package/build/module/util/index.d.ts +7 -0
- package/build/module/util/index.js +8 -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 +106 -0
- package/build/module/util/metric.d.ts +48 -0
- package/build/module/util/metric.js +53 -0
- package/build/module/util/protocols.d.ts +2 -0
- package/build/module/util/protocols.js +14 -0
- package/build/module/util/routes.d.ts +8 -0
- package/build/module/util/routes.js +50 -0
- package/build/module/util/unsupported-tokens.d.ts +37 -0
- package/build/module/util/unsupported-tokens.js +1116 -0
- package/package.json +119 -0
|
@@ -0,0 +1,823 @@
|
|
|
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 } from '@uniswap/router-sdk';
|
|
5
|
+
import { Fraction, TradeType } from '@uniswap/sdk-core';
|
|
6
|
+
import { Pool, Position, SqrtPriceMath, TickMath } from '@uniswap/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, CachingV2SubgraphProvider, CachingV3PoolProvider, CachingV3SubgraphProvider, EIP1559GasPriceProvider, ETHGasStationInfoProvider, LegacyGasPriceProvider, NodeJSCache, OnChainGasPriceProvider, OnChainQuoteProvider, StaticV2SubgraphProvider, StaticV3SubgraphProvider, SwapRouterProvider, UniswapMulticallProvider, URISubgraphProvider, V2QuoteProvider, V2SubgraphProviderWithFallBacks, V3SubgraphProviderWithFallBacks, } from '../../providers';
|
|
12
|
+
import { CachingTokenListProvider } from '../../providers/caching-token-list-provider';
|
|
13
|
+
import { TokenProvider } from '../../providers/token-provider';
|
|
14
|
+
import { TokenValidatorProvider, } from '../../providers/token-validator-provider';
|
|
15
|
+
import { V2PoolProvider } from '../../providers/v2/pool-provider';
|
|
16
|
+
import { ArbitrumGasDataProvider, OptimismGasDataProvider, } from '../../providers/v3/gas-data-provider';
|
|
17
|
+
import { V3PoolProvider } from '../../providers/v3/pool-provider';
|
|
18
|
+
import { Erc20__factory } from '../../types/other/factories/Erc20__factory';
|
|
19
|
+
import { SWAP_ROUTER_02_ADDRESSES } from '../../util';
|
|
20
|
+
import { CurrencyAmount } from '../../util/amounts';
|
|
21
|
+
import { ChainId, ID_TO_CHAIN_ID, ID_TO_NETWORK_NAME, V2_SUPPORTED } from '../../util/chains';
|
|
22
|
+
import { log } from '../../util/log';
|
|
23
|
+
import { buildSwapMethodParameters, buildTrade } from '../../util/methodParameters';
|
|
24
|
+
import { metric, MetricLoggerUnit } from '../../util/metric';
|
|
25
|
+
import { UNSUPPORTED_TOKENS } from '../../util/unsupported-tokens';
|
|
26
|
+
import { SwapToRatioStatus, } from '../router';
|
|
27
|
+
import { DEFAULT_ROUTING_CONFIG_BY_CHAIN, ETH_GAS_STATION_API_URL } from './config';
|
|
28
|
+
import { getBestSwapRoute } from './functions/best-swap-route';
|
|
29
|
+
import { calculateRatioAmountIn } from './functions/calculate-ratio-amount-in';
|
|
30
|
+
import { MixedRouteHeuristicGasModelFactory } from './gas-models/mixedRoute/mixed-route-heuristic-gas-model';
|
|
31
|
+
import { V2HeuristicGasModelFactory } from './gas-models/v2/v2-heuristic-gas-model';
|
|
32
|
+
import { V3HeuristicGasModelFactory } from './gas-models/v3/v3-heuristic-gas-model';
|
|
33
|
+
import { MixedQuoter, V2Quoter, V3Quoter } from './quoters';
|
|
34
|
+
export class MapWithLowerCaseKey extends Map {
|
|
35
|
+
set(key, value) {
|
|
36
|
+
return super.set(key.toLowerCase(), value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export class AlphaRouter {
|
|
40
|
+
constructor({ chainId, provider, multicall2Provider, v3PoolProvider, onChainQuoteProvider, v2PoolProvider, v2QuoteProvider, v2SubgraphProvider, tokenProvider, blockedTokenListProvider, v3SubgraphProvider, gasPriceProvider, v3GasModelFactory, v2GasModelFactory, mixedRouteGasModelFactory, swapRouterProvider, optimismGasDataProvider, tokenValidatorProvider, arbitrumGasDataProvider, simulator, routeCachingProvider, }) {
|
|
41
|
+
this.chainId = chainId;
|
|
42
|
+
this.provider = provider;
|
|
43
|
+
this.multicall2Provider =
|
|
44
|
+
multicall2Provider !== null && multicall2Provider !== void 0 ? multicall2Provider : new UniswapMulticallProvider(chainId, provider, 375000);
|
|
45
|
+
this.v3PoolProvider =
|
|
46
|
+
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 })));
|
|
47
|
+
this.simulator = simulator;
|
|
48
|
+
this.routeCachingProvider = routeCachingProvider;
|
|
49
|
+
if (onChainQuoteProvider) {
|
|
50
|
+
this.onChainQuoteProvider = onChainQuoteProvider;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
switch (chainId) {
|
|
54
|
+
case ChainId.OPTIMISM:
|
|
55
|
+
case ChainId.OPTIMISM_GOERLI:
|
|
56
|
+
case ChainId.OPTIMISTIC_KOVAN:
|
|
57
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, {
|
|
58
|
+
retries: 2,
|
|
59
|
+
minTimeout: 100,
|
|
60
|
+
maxTimeout: 1000,
|
|
61
|
+
}, {
|
|
62
|
+
multicallChunk: 110,
|
|
63
|
+
gasLimitPerCall: 1200000,
|
|
64
|
+
quoteMinSuccessRate: 0.1,
|
|
65
|
+
}, {
|
|
66
|
+
gasLimitOverride: 3000000,
|
|
67
|
+
multicallChunk: 45,
|
|
68
|
+
}, {
|
|
69
|
+
gasLimitOverride: 3000000,
|
|
70
|
+
multicallChunk: 45,
|
|
71
|
+
}, {
|
|
72
|
+
baseBlockOffset: -10,
|
|
73
|
+
rollback: {
|
|
74
|
+
enabled: true,
|
|
75
|
+
attemptsBeforeRollback: 1,
|
|
76
|
+
rollbackBlockOffset: -10,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
break;
|
|
80
|
+
case ChainId.ARBITRUM_ONE:
|
|
81
|
+
case ChainId.ARBITRUM_RINKEBY:
|
|
82
|
+
case ChainId.ARBITRUM_GOERLI:
|
|
83
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, {
|
|
84
|
+
retries: 2,
|
|
85
|
+
minTimeout: 100,
|
|
86
|
+
maxTimeout: 1000,
|
|
87
|
+
}, {
|
|
88
|
+
multicallChunk: 10,
|
|
89
|
+
gasLimitPerCall: 12000000,
|
|
90
|
+
quoteMinSuccessRate: 0.1,
|
|
91
|
+
}, {
|
|
92
|
+
gasLimitOverride: 30000000,
|
|
93
|
+
multicallChunk: 6,
|
|
94
|
+
}, {
|
|
95
|
+
gasLimitOverride: 30000000,
|
|
96
|
+
multicallChunk: 6,
|
|
97
|
+
});
|
|
98
|
+
break;
|
|
99
|
+
case ChainId.CELO:
|
|
100
|
+
case ChainId.CELO_ALFAJORES:
|
|
101
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, {
|
|
102
|
+
retries: 2,
|
|
103
|
+
minTimeout: 100,
|
|
104
|
+
maxTimeout: 1000,
|
|
105
|
+
}, {
|
|
106
|
+
multicallChunk: 10,
|
|
107
|
+
gasLimitPerCall: 5000000,
|
|
108
|
+
quoteMinSuccessRate: 0.1,
|
|
109
|
+
}, {
|
|
110
|
+
gasLimitOverride: 5000000,
|
|
111
|
+
multicallChunk: 5,
|
|
112
|
+
}, {
|
|
113
|
+
gasLimitOverride: 6250000,
|
|
114
|
+
multicallChunk: 4,
|
|
115
|
+
});
|
|
116
|
+
break;
|
|
117
|
+
case ChainId.CFX:
|
|
118
|
+
case ChainId.CFX_TEST:
|
|
119
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, {
|
|
120
|
+
retries: 2,
|
|
121
|
+
minTimeout: 100,
|
|
122
|
+
maxTimeout: 1000,
|
|
123
|
+
}, {
|
|
124
|
+
multicallChunk: 20,
|
|
125
|
+
gasLimitPerCall: 705000,
|
|
126
|
+
quoteMinSuccessRate: 0.15,
|
|
127
|
+
}, {
|
|
128
|
+
gasLimitOverride: 2000000,
|
|
129
|
+
multicallChunk: 70,
|
|
130
|
+
});
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
this.onChainQuoteProvider = new OnChainQuoteProvider(chainId, provider, this.multicall2Provider, {
|
|
134
|
+
retries: 2,
|
|
135
|
+
minTimeout: 100,
|
|
136
|
+
maxTimeout: 1000,
|
|
137
|
+
}, {
|
|
138
|
+
multicallChunk: 210,
|
|
139
|
+
gasLimitPerCall: 705000,
|
|
140
|
+
quoteMinSuccessRate: 0.15,
|
|
141
|
+
}, {
|
|
142
|
+
gasLimitOverride: 2000000,
|
|
143
|
+
multicallChunk: 70,
|
|
144
|
+
});
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this.v2PoolProvider =
|
|
149
|
+
v2PoolProvider !== null && v2PoolProvider !== void 0 ? v2PoolProvider : new CachingV2PoolProvider(chainId, new V2PoolProvider(chainId, this.multicall2Provider), new NodeJSCache(new NodeCache({ stdTTL: 60, useClones: false })));
|
|
150
|
+
this.v2QuoteProvider = v2QuoteProvider !== null && v2QuoteProvider !== void 0 ? v2QuoteProvider : new V2QuoteProvider();
|
|
151
|
+
this.blockedTokenListProvider =
|
|
152
|
+
blockedTokenListProvider !== null && blockedTokenListProvider !== void 0 ? blockedTokenListProvider : new CachingTokenListProvider(chainId, UNSUPPORTED_TOKENS, new NodeJSCache(new NodeCache({ stdTTL: 3600, useClones: false })));
|
|
153
|
+
this.tokenProvider =
|
|
154
|
+
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));
|
|
155
|
+
const chainName = ID_TO_NETWORK_NAME(chainId);
|
|
156
|
+
// ipfs urls in the following format: `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/${protocol}/${chainName}.json`;
|
|
157
|
+
if (v2SubgraphProvider) {
|
|
158
|
+
this.v2SubgraphProvider = v2SubgraphProvider;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.v2SubgraphProvider = new V2SubgraphProviderWithFallBacks([
|
|
162
|
+
new CachingV2SubgraphProvider(chainId, new URISubgraphProvider(chainId, `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/v2/${chainName}.json`, undefined, 0), new NodeJSCache(new NodeCache({ stdTTL: 300, useClones: false }))),
|
|
163
|
+
new StaticV2SubgraphProvider(chainId),
|
|
164
|
+
]);
|
|
165
|
+
}
|
|
166
|
+
if (v3SubgraphProvider) {
|
|
167
|
+
this.v3SubgraphProvider = v3SubgraphProvider;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
this.v3SubgraphProvider = new V3SubgraphProviderWithFallBacks([
|
|
171
|
+
new CachingV3SubgraphProvider(chainId, new URISubgraphProvider(chainId, `https://cloudflare-ipfs.com/ipns/api.uniswap.org/v1/pools/v3/${chainName}.json`, undefined, 0), new NodeJSCache(new NodeCache({ stdTTL: 300, useClones: false }))),
|
|
172
|
+
new StaticV3SubgraphProvider(chainId, this.v3PoolProvider),
|
|
173
|
+
]);
|
|
174
|
+
}
|
|
175
|
+
let gasPriceProviderInstance;
|
|
176
|
+
if (JsonRpcProvider.isProvider(this.provider)) {
|
|
177
|
+
gasPriceProviderInstance = new OnChainGasPriceProvider(chainId, new EIP1559GasPriceProvider(this.provider), new LegacyGasPriceProvider(this.provider));
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
gasPriceProviderInstance = new ETHGasStationInfoProvider(ETH_GAS_STATION_API_URL);
|
|
181
|
+
}
|
|
182
|
+
this.gasPriceProvider =
|
|
183
|
+
gasPriceProvider !== null && gasPriceProvider !== void 0 ? gasPriceProvider : new CachingGasStationProvider(chainId, gasPriceProviderInstance, new NodeJSCache(new NodeCache({ stdTTL: 15, useClones: false })));
|
|
184
|
+
this.v3GasModelFactory =
|
|
185
|
+
v3GasModelFactory !== null && v3GasModelFactory !== void 0 ? v3GasModelFactory : new V3HeuristicGasModelFactory();
|
|
186
|
+
this.v2GasModelFactory =
|
|
187
|
+
v2GasModelFactory !== null && v2GasModelFactory !== void 0 ? v2GasModelFactory : new V2HeuristicGasModelFactory();
|
|
188
|
+
this.mixedRouteGasModelFactory =
|
|
189
|
+
mixedRouteGasModelFactory !== null && mixedRouteGasModelFactory !== void 0 ? mixedRouteGasModelFactory : new MixedRouteHeuristicGasModelFactory();
|
|
190
|
+
this.swapRouterProvider =
|
|
191
|
+
swapRouterProvider !== null && swapRouterProvider !== void 0 ? swapRouterProvider : new SwapRouterProvider(this.multicall2Provider, this.chainId);
|
|
192
|
+
if (chainId === ChainId.OPTIMISM || chainId === ChainId.OPTIMISTIC_KOVAN) {
|
|
193
|
+
this.l2GasDataProvider =
|
|
194
|
+
optimismGasDataProvider !== null && optimismGasDataProvider !== void 0 ? optimismGasDataProvider : new OptimismGasDataProvider(chainId, this.multicall2Provider);
|
|
195
|
+
}
|
|
196
|
+
if (chainId === ChainId.ARBITRUM_ONE ||
|
|
197
|
+
chainId === ChainId.ARBITRUM_RINKEBY ||
|
|
198
|
+
chainId === ChainId.ARBITRUM_GOERLI) {
|
|
199
|
+
this.l2GasDataProvider =
|
|
200
|
+
arbitrumGasDataProvider !== null && arbitrumGasDataProvider !== void 0 ? arbitrumGasDataProvider : new ArbitrumGasDataProvider(chainId, this.provider);
|
|
201
|
+
}
|
|
202
|
+
if (tokenValidatorProvider) {
|
|
203
|
+
this.tokenValidatorProvider = tokenValidatorProvider;
|
|
204
|
+
}
|
|
205
|
+
else if (this.chainId === ChainId.MAINNET) {
|
|
206
|
+
this.tokenValidatorProvider = new TokenValidatorProvider(this.chainId, this.multicall2Provider, new NodeJSCache(new NodeCache({ stdTTL: 30000, useClones: false })));
|
|
207
|
+
}
|
|
208
|
+
// Initialize the Quoters.
|
|
209
|
+
// Quoters are an abstraction encapsulating the business logic of fetching routes and quotes.
|
|
210
|
+
this.v2Quoter = new V2Quoter(this.v2SubgraphProvider, this.v2PoolProvider, this.v2QuoteProvider, this.v2GasModelFactory, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
211
|
+
this.v3Quoter = new V3Quoter(this.v3SubgraphProvider, this.v3PoolProvider, this.onChainQuoteProvider, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
212
|
+
this.mixedQuoter = new MixedQuoter(this.v3SubgraphProvider, this.v3PoolProvider, this.v2SubgraphProvider, this.v2PoolProvider, this.onChainQuoteProvider, this.tokenProvider, this.chainId, this.blockedTokenListProvider, this.tokenValidatorProvider);
|
|
213
|
+
}
|
|
214
|
+
async routeToRatio(token0Balance, token1Balance, position, swapAndAddConfig, swapAndAddOptions, routingConfig = DEFAULT_ROUTING_CONFIG_BY_CHAIN(this.chainId)) {
|
|
215
|
+
if (token1Balance.currency.wrapped.sortsBefore(token0Balance.currency.wrapped)) {
|
|
216
|
+
[token0Balance, token1Balance] = [token1Balance, token0Balance];
|
|
217
|
+
}
|
|
218
|
+
let preSwapOptimalRatio = this.calculateOptimalRatio(position, position.pool.sqrtRatioX96, true);
|
|
219
|
+
// set up parameters according to which token will be swapped
|
|
220
|
+
let zeroForOne;
|
|
221
|
+
if (position.pool.tickCurrent > position.tickUpper) {
|
|
222
|
+
zeroForOne = true;
|
|
223
|
+
}
|
|
224
|
+
else if (position.pool.tickCurrent < position.tickLower) {
|
|
225
|
+
zeroForOne = false;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
zeroForOne = new Fraction(token0Balance.quotient, token1Balance.quotient).greaterThan(preSwapOptimalRatio);
|
|
229
|
+
if (!zeroForOne)
|
|
230
|
+
preSwapOptimalRatio = preSwapOptimalRatio.invert();
|
|
231
|
+
}
|
|
232
|
+
const [inputBalance, outputBalance] = zeroForOne
|
|
233
|
+
? [token0Balance, token1Balance]
|
|
234
|
+
: [token1Balance, token0Balance];
|
|
235
|
+
let optimalRatio = preSwapOptimalRatio;
|
|
236
|
+
let postSwapTargetPool = position.pool;
|
|
237
|
+
let exchangeRate = zeroForOne
|
|
238
|
+
? position.pool.token0Price
|
|
239
|
+
: position.pool.token1Price;
|
|
240
|
+
let swap = null;
|
|
241
|
+
let ratioAchieved = false;
|
|
242
|
+
let n = 0;
|
|
243
|
+
// iterate until we find a swap with a sufficient ratio or return null
|
|
244
|
+
while (!ratioAchieved) {
|
|
245
|
+
n++;
|
|
246
|
+
if (n > swapAndAddConfig.maxIterations) {
|
|
247
|
+
log.info('max iterations exceeded');
|
|
248
|
+
return {
|
|
249
|
+
status: SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
250
|
+
error: 'max iterations exceeded',
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const amountToSwap = calculateRatioAmountIn(optimalRatio, exchangeRate, inputBalance, outputBalance);
|
|
254
|
+
if (amountToSwap.equalTo(0)) {
|
|
255
|
+
log.info(`no swap needed: amountToSwap = 0`);
|
|
256
|
+
return {
|
|
257
|
+
status: SwapToRatioStatus.NO_SWAP_NEEDED,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
swap = await this.route(amountToSwap, outputBalance.currency, TradeType.EXACT_INPUT, undefined, {
|
|
261
|
+
...DEFAULT_ROUTING_CONFIG_BY_CHAIN(this.chainId),
|
|
262
|
+
...routingConfig,
|
|
263
|
+
/// @dev We do not want to query for mixedRoutes for routeToRatio as they are not supported
|
|
264
|
+
/// [Protocol.V3, Protocol.V2] will make sure we only query for V3 and V2
|
|
265
|
+
protocols: [Protocol.V3, Protocol.V2],
|
|
266
|
+
});
|
|
267
|
+
if (!swap) {
|
|
268
|
+
log.info('no route found from this.route()');
|
|
269
|
+
return {
|
|
270
|
+
status: SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
271
|
+
error: 'no route found',
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const inputBalanceUpdated = inputBalance.subtract(swap.trade.inputAmount);
|
|
275
|
+
const outputBalanceUpdated = outputBalance.add(swap.trade.outputAmount);
|
|
276
|
+
const newRatio = inputBalanceUpdated.divide(outputBalanceUpdated);
|
|
277
|
+
let targetPoolPriceUpdate;
|
|
278
|
+
swap.route.forEach((route) => {
|
|
279
|
+
if (route.protocol === Protocol.V3) {
|
|
280
|
+
const v3Route = route;
|
|
281
|
+
v3Route.route.pools.forEach((pool, i) => {
|
|
282
|
+
if (pool.token0.equals(position.pool.token0) &&
|
|
283
|
+
pool.token1.equals(position.pool.token1) &&
|
|
284
|
+
pool.fee === position.pool.fee) {
|
|
285
|
+
targetPoolPriceUpdate = JSBI.BigInt(v3Route.sqrtPriceX96AfterList[i].toString());
|
|
286
|
+
optimalRatio = this.calculateOptimalRatio(position, JSBI.BigInt(targetPoolPriceUpdate.toString()), zeroForOne);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
if (!targetPoolPriceUpdate) {
|
|
292
|
+
optimalRatio = preSwapOptimalRatio;
|
|
293
|
+
}
|
|
294
|
+
ratioAchieved =
|
|
295
|
+
newRatio.equalTo(optimalRatio) ||
|
|
296
|
+
this.absoluteValue(newRatio.asFraction.divide(optimalRatio).subtract(1)).lessThan(swapAndAddConfig.ratioErrorTolerance);
|
|
297
|
+
if (ratioAchieved && targetPoolPriceUpdate) {
|
|
298
|
+
postSwapTargetPool = new Pool(position.pool.token0, position.pool.token1, position.pool.fee, targetPoolPriceUpdate, position.pool.liquidity, TickMath.getTickAtSqrtRatio(targetPoolPriceUpdate), position.pool.tickDataProvider);
|
|
299
|
+
}
|
|
300
|
+
exchangeRate = swap.trade.outputAmount.divide(swap.trade.inputAmount);
|
|
301
|
+
log.info({
|
|
302
|
+
exchangeRate: exchangeRate.asFraction.toFixed(18),
|
|
303
|
+
optimalRatio: optimalRatio.asFraction.toFixed(18),
|
|
304
|
+
newRatio: newRatio.asFraction.toFixed(18),
|
|
305
|
+
inputBalanceUpdated: inputBalanceUpdated.asFraction.toFixed(18),
|
|
306
|
+
outputBalanceUpdated: outputBalanceUpdated.asFraction.toFixed(18),
|
|
307
|
+
ratioErrorTolerance: swapAndAddConfig.ratioErrorTolerance.toFixed(18),
|
|
308
|
+
iterationN: n.toString(),
|
|
309
|
+
}, 'QuoteToRatio Iteration Parameters');
|
|
310
|
+
if (exchangeRate.equalTo(0)) {
|
|
311
|
+
log.info('exchangeRate to 0');
|
|
312
|
+
return {
|
|
313
|
+
status: SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
314
|
+
error: 'insufficient liquidity to swap to optimal ratio',
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (!swap) {
|
|
319
|
+
return {
|
|
320
|
+
status: SwapToRatioStatus.NO_ROUTE_FOUND,
|
|
321
|
+
error: 'no route found',
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
let methodParameters;
|
|
325
|
+
if (swapAndAddOptions) {
|
|
326
|
+
methodParameters = await this.buildSwapAndAddMethodParameters(swap.trade, swapAndAddOptions, {
|
|
327
|
+
initialBalanceTokenIn: inputBalance,
|
|
328
|
+
initialBalanceTokenOut: outputBalance,
|
|
329
|
+
preLiquidityPosition: position,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
status: SwapToRatioStatus.SUCCESS,
|
|
334
|
+
result: { ...swap, methodParameters, optimalRatio, postSwapTargetPool },
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* @inheritdoc IRouter
|
|
339
|
+
*/
|
|
340
|
+
async route(amount, quoteCurrency, tradeType, swapConfig, partialRoutingConfig = {}) {
|
|
341
|
+
var _a, _c, _d;
|
|
342
|
+
const { currencyIn, currencyOut } = this.determineCurrencyInOutFromTradeType(tradeType, amount, quoteCurrency);
|
|
343
|
+
const tokenIn = currencyIn.wrapped;
|
|
344
|
+
const tokenOut = currencyOut.wrapped;
|
|
345
|
+
metric.setProperty('chainId', this.chainId);
|
|
346
|
+
metric.setProperty('pair', `${tokenIn.symbol}/${tokenOut.symbol}`);
|
|
347
|
+
metric.setProperty('tokenIn', tokenIn.address);
|
|
348
|
+
metric.setProperty('tokenOut', tokenOut.address);
|
|
349
|
+
metric.setProperty('tradeType', tradeType === TradeType.EXACT_INPUT ? 'ExactIn' : 'ExactOut');
|
|
350
|
+
metric.putMetric(`QuoteRequestedForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
351
|
+
// Get a block number to specify in all our calls. Ensures data we fetch from chain is
|
|
352
|
+
// from the same block.
|
|
353
|
+
const blockNumber = (_a = partialRoutingConfig.blockNumber) !== null && _a !== void 0 ? _a : this.getBlockNumberPromise();
|
|
354
|
+
const routingConfig = _.merge({}, DEFAULT_ROUTING_CONFIG_BY_CHAIN(this.chainId), partialRoutingConfig, { blockNumber });
|
|
355
|
+
const gasPriceWei = await this.getGasPriceWei();
|
|
356
|
+
const quoteToken = quoteCurrency.wrapped;
|
|
357
|
+
const [v3GasModel, mixedRouteGasModel] = await this.getGasModels(gasPriceWei, amount.currency.wrapped, quoteToken);
|
|
358
|
+
// Create a Set to sanitize the protocols input, a Set of undefined becomes an empty set,
|
|
359
|
+
// Then create an Array from the values of that Set.
|
|
360
|
+
const protocols = Array.from(new Set(routingConfig.protocols).values());
|
|
361
|
+
const cacheMode = await ((_c = this.routeCachingProvider) === null || _c === void 0 ? void 0 : _c.getCacheMode(this.chainId, amount, quoteToken, tradeType, protocols));
|
|
362
|
+
// Fetch CachedRoutes
|
|
363
|
+
let cachedRoutes;
|
|
364
|
+
if (cacheMode !== CacheMode.Darkmode) {
|
|
365
|
+
cachedRoutes = await ((_d = this.routeCachingProvider) === null || _d === void 0 ? void 0 : _d.getCachedRoute(this.chainId, amount, quoteToken, tradeType, protocols, await blockNumber));
|
|
366
|
+
}
|
|
367
|
+
if (cacheMode && cacheMode !== CacheMode.Darkmode && !cachedRoutes) {
|
|
368
|
+
metric.putMetric(`GetCachedRoute_miss_${cacheMode}`, 1, MetricLoggerUnit.Count);
|
|
369
|
+
log.info({
|
|
370
|
+
tokenIn: tokenIn.symbol,
|
|
371
|
+
tokenInAddress: tokenIn.address,
|
|
372
|
+
tokenOut: tokenOut.symbol,
|
|
373
|
+
tokenOutAddress: tokenOut.address,
|
|
374
|
+
cacheMode,
|
|
375
|
+
amount: amount.toExact(),
|
|
376
|
+
chainId: this.chainId,
|
|
377
|
+
tradeType: this.tradeTypeStr(tradeType)
|
|
378
|
+
}, `GetCachedRoute miss ${cacheMode} for ${this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType)}`);
|
|
379
|
+
}
|
|
380
|
+
else if (cachedRoutes) {
|
|
381
|
+
metric.putMetric(`GetCachedRoute_hit_${cacheMode}`, 1, MetricLoggerUnit.Count);
|
|
382
|
+
log.info({
|
|
383
|
+
tokenIn: tokenIn.symbol,
|
|
384
|
+
tokenInAddress: tokenIn.address,
|
|
385
|
+
tokenOut: tokenOut.symbol,
|
|
386
|
+
tokenOutAddress: tokenOut.address,
|
|
387
|
+
cacheMode,
|
|
388
|
+
amount: amount.toExact(),
|
|
389
|
+
chainId: this.chainId,
|
|
390
|
+
tradeType: this.tradeTypeStr(tradeType)
|
|
391
|
+
}, `GetCachedRoute hit ${cacheMode} for ${this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType)}`);
|
|
392
|
+
}
|
|
393
|
+
let swapRouteFromCachePromise = Promise.resolve(null);
|
|
394
|
+
if (cachedRoutes) {
|
|
395
|
+
swapRouteFromCachePromise = this.getSwapRouteFromCache(cachedRoutes, await blockNumber, amount, quoteToken, tradeType, routingConfig, v3GasModel, mixedRouteGasModel, gasPriceWei);
|
|
396
|
+
}
|
|
397
|
+
let swapRouteFromChainPromise = Promise.resolve(null);
|
|
398
|
+
if (!cachedRoutes || cacheMode !== CacheMode.Livemode) {
|
|
399
|
+
swapRouteFromChainPromise = this.getSwapRouteFromChain(amount, tokenIn, tokenOut, protocols, quoteToken, tradeType, routingConfig, v3GasModel, mixedRouteGasModel, gasPriceWei);
|
|
400
|
+
}
|
|
401
|
+
const [swapRouteFromCache, swapRouteFromChain] = await Promise.all([
|
|
402
|
+
swapRouteFromCachePromise,
|
|
403
|
+
swapRouteFromChainPromise
|
|
404
|
+
]);
|
|
405
|
+
let swapRouteRaw;
|
|
406
|
+
if (cacheMode === CacheMode.Livemode && swapRouteFromCache) {
|
|
407
|
+
log.info(`CacheMode is ${cacheMode}, and we are using swapRoute from cache`);
|
|
408
|
+
swapRouteRaw = swapRouteFromCache;
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
log.info(`CacheMode is ${cacheMode}, and we are using materialized swapRoute`);
|
|
412
|
+
swapRouteRaw = swapRouteFromChain;
|
|
413
|
+
}
|
|
414
|
+
if (cacheMode === CacheMode.Tapcompare && swapRouteFromCache && swapRouteFromChain) {
|
|
415
|
+
const quoteDiff = swapRouteFromChain.quote.subtract(swapRouteFromCache.quote);
|
|
416
|
+
const quoteGasAdjustedDiff = swapRouteFromChain.quoteGasAdjusted.subtract(swapRouteFromCache.quoteGasAdjusted);
|
|
417
|
+
const gasUsedDiff = swapRouteFromChain.estimatedGasUsed.sub(swapRouteFromCache.estimatedGasUsed);
|
|
418
|
+
// Only log if diff is not equal to 0
|
|
419
|
+
if (!quoteDiff.equalTo(0)) {
|
|
420
|
+
log.warn({
|
|
421
|
+
quoteFromChain: swapRouteFromChain.quote.toExact(),
|
|
422
|
+
quoteFromCache: swapRouteFromCache.quote.toExact(),
|
|
423
|
+
quoteDiff: quoteDiff.toExact(),
|
|
424
|
+
quoteGasAdjustedFromChain: swapRouteFromChain.quoteGasAdjusted.toExact(),
|
|
425
|
+
quoteGasAdjustedFromCache: swapRouteFromCache.quoteGasAdjusted.toExact(),
|
|
426
|
+
quoteGasAdjustedDiff: quoteGasAdjustedDiff.toExact(),
|
|
427
|
+
gasUsedFromChain: swapRouteFromChain.estimatedGasUsed.toString(),
|
|
428
|
+
gasUsedFromCache: swapRouteFromCache.estimatedGasUsed.toString(),
|
|
429
|
+
gasUsedDiff: gasUsedDiff.toString(),
|
|
430
|
+
routesFromChain: swapRouteFromChain.routes.toString(),
|
|
431
|
+
routesFromCache: swapRouteFromCache.routes.toString(),
|
|
432
|
+
amount: amount.toExact(),
|
|
433
|
+
pair: this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType)
|
|
434
|
+
}, `Comparing quotes between Chain and Cache for ${this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType)}`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (!swapRouteRaw) {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
const { quote, quoteGasAdjusted, estimatedGasUsed, routes: routeAmounts, estimatedGasUsedQuoteToken, estimatedGasUsedUSD, } = swapRouteRaw;
|
|
441
|
+
if (this.routeCachingProvider && cacheMode !== CacheMode.Darkmode && swapRouteFromChain) {
|
|
442
|
+
// Generate the object to be cached
|
|
443
|
+
const routesToCache = CachedRoutes.fromRoutesWithValidQuotes(swapRouteFromChain.routes, this.chainId, tokenIn, tokenOut, protocols.sort(), // sort it for consistency in the order of the protocols.
|
|
444
|
+
await blockNumber, tradeType);
|
|
445
|
+
if (routesToCache) {
|
|
446
|
+
const tokenPairSymbolTradeTypeChainId = this.tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType);
|
|
447
|
+
// Attempt to insert the entry in cache. This is fire and forget promise.
|
|
448
|
+
// The catch method will prevent any exception from blocking the normal code execution.
|
|
449
|
+
this.routeCachingProvider.setCachedRoute(routesToCache, amount).then((success) => {
|
|
450
|
+
const status = success ? 'success' : 'rejected';
|
|
451
|
+
metric.putMetric(`SetCachedRoute_${tokenPairSymbolTradeTypeChainId}_${status}`, 1, MetricLoggerUnit.Count);
|
|
452
|
+
}).catch((reason) => {
|
|
453
|
+
log.info({
|
|
454
|
+
reason: reason,
|
|
455
|
+
tokenPair: tokenPairSymbolTradeTypeChainId
|
|
456
|
+
}, `SetCachedRoute failure`);
|
|
457
|
+
metric.putMetric(`SetCachedRoute_${tokenPairSymbolTradeTypeChainId}_failure`, 1, MetricLoggerUnit.Count);
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
metric.putMetric(`QuoteFoundForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
462
|
+
// Build Trade object that represents the optimal swap.
|
|
463
|
+
const trade = buildTrade(currencyIn, currencyOut, tradeType, routeAmounts);
|
|
464
|
+
let methodParameters;
|
|
465
|
+
// If user provided recipient, deadline etc. we also generate the calldata required to execute
|
|
466
|
+
// the swap and return it too.
|
|
467
|
+
if (swapConfig) {
|
|
468
|
+
methodParameters = buildSwapMethodParameters(trade, swapConfig, this.chainId);
|
|
469
|
+
}
|
|
470
|
+
const swapRoute = {
|
|
471
|
+
quote,
|
|
472
|
+
quoteGasAdjusted,
|
|
473
|
+
estimatedGasUsed,
|
|
474
|
+
estimatedGasUsedQuoteToken,
|
|
475
|
+
estimatedGasUsedUSD,
|
|
476
|
+
gasPriceWei,
|
|
477
|
+
route: routeAmounts,
|
|
478
|
+
trade,
|
|
479
|
+
methodParameters,
|
|
480
|
+
blockNumber: BigNumber.from(await blockNumber),
|
|
481
|
+
};
|
|
482
|
+
if (swapConfig &&
|
|
483
|
+
swapConfig.simulate &&
|
|
484
|
+
methodParameters &&
|
|
485
|
+
methodParameters.calldata) {
|
|
486
|
+
if (!this.simulator) {
|
|
487
|
+
throw new Error('Simulator not initialized!');
|
|
488
|
+
}
|
|
489
|
+
log.info({ swapConfig, methodParameters }, 'Starting simulation');
|
|
490
|
+
const fromAddress = swapConfig.simulate.fromAddress;
|
|
491
|
+
const beforeSimulate = Date.now();
|
|
492
|
+
const swapRouteWithSimulation = await this.simulator.simulate(fromAddress, swapConfig, swapRoute, amount,
|
|
493
|
+
// Quote will be in WETH even if quoteCurrency is ETH
|
|
494
|
+
// So we init a new CurrencyAmount object here
|
|
495
|
+
CurrencyAmount.fromRawAmount(quoteCurrency, quote.quotient.toString()), this.l2GasDataProvider
|
|
496
|
+
? await this.l2GasDataProvider.getGasData()
|
|
497
|
+
: undefined, { blockNumber });
|
|
498
|
+
metric.putMetric('SimulateTransaction', Date.now() - beforeSimulate, MetricLoggerUnit.Milliseconds);
|
|
499
|
+
return swapRouteWithSimulation;
|
|
500
|
+
}
|
|
501
|
+
return swapRoute;
|
|
502
|
+
}
|
|
503
|
+
async getSwapRouteFromCache(cachedRoutes, blockNumber, amount, quoteToken, tradeType, routingConfig, v3GasModel, mixedRouteGasModel, gasPriceWei) {
|
|
504
|
+
log.info({
|
|
505
|
+
protocols: cachedRoutes.protocolsCovered,
|
|
506
|
+
tradeType: cachedRoutes.tradeType,
|
|
507
|
+
cachedBlockNumber: cachedRoutes.blockNumber,
|
|
508
|
+
quoteBlockNumber: blockNumber,
|
|
509
|
+
}, 'Routing across CachedRoute');
|
|
510
|
+
const quotePromises = [];
|
|
511
|
+
const v3Routes = cachedRoutes.routes.filter((route) => route.protocol === Protocol.V3);
|
|
512
|
+
const v2Routes = cachedRoutes.routes.filter((route) => route.protocol === Protocol.V2);
|
|
513
|
+
const mixedRoutes = cachedRoutes.routes.filter((route) => route.protocol === Protocol.MIXED);
|
|
514
|
+
const percents = [];
|
|
515
|
+
if (v3Routes.length > 0) {
|
|
516
|
+
const v3RoutesFromCache = v3Routes.map((cachedRoute) => cachedRoute.route);
|
|
517
|
+
const v3PercentsFromCache = v3Routes.map((cachedRoute) => cachedRoute.percent);
|
|
518
|
+
percents.push(...v3PercentsFromCache);
|
|
519
|
+
const v3Amounts = v3PercentsFromCache.map((percent) => amount.multiply(new Fraction(percent, 100)));
|
|
520
|
+
quotePromises.push(this.v3Quoter.getQuotes(v3RoutesFromCache, v3Amounts, v3PercentsFromCache, quoteToken, tradeType, routingConfig, undefined, v3GasModel));
|
|
521
|
+
}
|
|
522
|
+
if (v2Routes.length > 0) {
|
|
523
|
+
const v2PercentsFromCache = v2Routes.map((cachedRoute) => cachedRoute.percent);
|
|
524
|
+
percents.push(...v2PercentsFromCache);
|
|
525
|
+
const v2Amounts = v2PercentsFromCache.map((percent) => amount.multiply(new Fraction(percent, 100)));
|
|
526
|
+
quotePromises.push(
|
|
527
|
+
// When we fetch the quotes in V2, we are not calling the `onChainProvider` like on v3Routes and mixedRoutes
|
|
528
|
+
// Instead we are using the reserves in the Pool object, so we need to re-load the current reserves.
|
|
529
|
+
this.v2Quoter.getRoutesThenQuotes(v2Routes[0].tokenIn, v2Routes[0].tokenOut, v2Amounts, v2PercentsFromCache, quoteToken, tradeType, routingConfig, undefined, gasPriceWei));
|
|
530
|
+
}
|
|
531
|
+
if (mixedRoutes.length > 0) {
|
|
532
|
+
const mixedRoutesFromCache = mixedRoutes.map((cachedRoute) => cachedRoute.route);
|
|
533
|
+
const mixedPercentsFromCache = mixedRoutes.map((cachedRoute) => cachedRoute.percent);
|
|
534
|
+
percents.push(...mixedPercentsFromCache);
|
|
535
|
+
const mixedAmounts = mixedPercentsFromCache.map((percent) => amount.multiply(new Fraction(percent, 100)));
|
|
536
|
+
quotePromises.push(this.mixedQuoter.getQuotes(mixedRoutesFromCache, mixedAmounts, mixedPercentsFromCache, quoteToken, tradeType, routingConfig, undefined, mixedRouteGasModel));
|
|
537
|
+
}
|
|
538
|
+
const getQuotesResults = await Promise.all(quotePromises);
|
|
539
|
+
const allRoutesWithValidQuotes = _.flatMap(getQuotesResults, (quoteResult) => quoteResult.routesWithValidQuotes);
|
|
540
|
+
return getBestSwapRoute(amount, percents, allRoutesWithValidQuotes, tradeType, this.chainId, routingConfig, v3GasModel);
|
|
541
|
+
}
|
|
542
|
+
async getSwapRouteFromChain(amount, tokenIn, tokenOut, protocols, quoteToken, tradeType, routingConfig, v3GasModel, mixedRouteGasModel, gasPriceWei) {
|
|
543
|
+
// Generate our distribution of amounts, i.e. fractions of the input amount.
|
|
544
|
+
// We will get quotes for fractions of the input amount for different routes, then
|
|
545
|
+
// combine to generate split routes.
|
|
546
|
+
const [percents, amounts] = this.getAmountDistribution(amount, routingConfig);
|
|
547
|
+
const noProtocolsSpecified = protocols.length === 0;
|
|
548
|
+
const v3ProtocolSpecified = protocols.includes(Protocol.V3);
|
|
549
|
+
const v2ProtocolSpecified = protocols.includes(Protocol.V2);
|
|
550
|
+
const v2SupportedInChain = V2_SUPPORTED.includes(this.chainId);
|
|
551
|
+
const shouldQueryMixedProtocol = protocols.includes(Protocol.MIXED) || (noProtocolsSpecified && v2SupportedInChain);
|
|
552
|
+
const mixedProtocolAllowed = [ChainId.MAINNET, ChainId.GÖRLI].includes(this.chainId) &&
|
|
553
|
+
tradeType === TradeType.EXACT_INPUT;
|
|
554
|
+
const quotePromises = [];
|
|
555
|
+
// Maybe Quote V3 - if V3 is specified, or no protocol is specified
|
|
556
|
+
if (v3ProtocolSpecified || noProtocolsSpecified) {
|
|
557
|
+
log.info({ protocols, tradeType }, 'Routing across V3');
|
|
558
|
+
quotePromises.push(this.v3Quoter.getRoutesThenQuotes(tokenIn, tokenOut, amounts, percents, quoteToken, tradeType, routingConfig, v3GasModel));
|
|
559
|
+
}
|
|
560
|
+
// Maybe Quote V2 - if V2 is specified, or no protocol is specified AND v2 is supported in this chain
|
|
561
|
+
if (v2SupportedInChain && (v2ProtocolSpecified || noProtocolsSpecified)) {
|
|
562
|
+
log.info({ protocols, tradeType }, 'Routing across V2');
|
|
563
|
+
quotePromises.push(this.v2Quoter.getRoutesThenQuotes(tokenIn, tokenOut, amounts, percents, quoteToken, tradeType, routingConfig, undefined, gasPriceWei));
|
|
564
|
+
}
|
|
565
|
+
// Maybe Quote mixed routes
|
|
566
|
+
// if MixedProtocol is specified or no protocol is specified and v2 is supported AND tradeType is ExactIn
|
|
567
|
+
// AND is Mainnet or Gorli
|
|
568
|
+
if (shouldQueryMixedProtocol && mixedProtocolAllowed) {
|
|
569
|
+
log.info({ protocols, tradeType }, 'Routing across MixedRoutes');
|
|
570
|
+
quotePromises.push(this.mixedQuoter.getRoutesThenQuotes(tokenIn, tokenOut, amounts, percents, quoteToken, tradeType, routingConfig, mixedRouteGasModel));
|
|
571
|
+
}
|
|
572
|
+
const getQuotesResults = await Promise.all(quotePromises);
|
|
573
|
+
const allRoutesWithValidQuotes = [];
|
|
574
|
+
const allCandidatePools = [];
|
|
575
|
+
getQuotesResults.forEach((getQuoteResult) => {
|
|
576
|
+
allRoutesWithValidQuotes.push(...getQuoteResult.routesWithValidQuotes);
|
|
577
|
+
if (getQuoteResult.candidatePools) {
|
|
578
|
+
allCandidatePools.push(getQuoteResult.candidatePools);
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
if (allRoutesWithValidQuotes.length === 0) {
|
|
582
|
+
log.info({ allRoutesWithValidQuotes }, 'Received no valid quotes');
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
// Given all the quotes for all the amounts for all the routes, find the best combination.
|
|
586
|
+
const bestSwapRoute = await getBestSwapRoute(amount, percents, allRoutesWithValidQuotes, tradeType, this.chainId, routingConfig, v3GasModel);
|
|
587
|
+
if (bestSwapRoute) {
|
|
588
|
+
this.emitPoolSelectionMetrics(bestSwapRoute, allCandidatePools);
|
|
589
|
+
}
|
|
590
|
+
return bestSwapRoute;
|
|
591
|
+
}
|
|
592
|
+
tradeTypeStr(tradeType) {
|
|
593
|
+
return tradeType === TradeType.EXACT_INPUT ? 'ExactIn' : 'ExactOut';
|
|
594
|
+
}
|
|
595
|
+
tokenPairSymbolTradeTypeChainId(tokenIn, tokenOut, tradeType) {
|
|
596
|
+
return `${tokenIn.symbol}/${tokenOut.symbol}/${this.tradeTypeStr(tradeType)}/${this.chainId}`;
|
|
597
|
+
}
|
|
598
|
+
determineCurrencyInOutFromTradeType(tradeType, amount, quoteCurrency) {
|
|
599
|
+
if (tradeType === TradeType.EXACT_INPUT) {
|
|
600
|
+
return {
|
|
601
|
+
currencyIn: amount.currency,
|
|
602
|
+
currencyOut: quoteCurrency
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
return {
|
|
607
|
+
currencyIn: quoteCurrency,
|
|
608
|
+
currencyOut: amount.currency
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
async getGasPriceWei() {
|
|
613
|
+
// Track how long it takes to resolve this async call.
|
|
614
|
+
const beforeGasTimestamp = Date.now();
|
|
615
|
+
// Get an estimate of the gas price to use when estimating gas cost of different routes.
|
|
616
|
+
const { gasPriceWei } = await this.gasPriceProvider.getGasPrice();
|
|
617
|
+
metric.putMetric('GasPriceLoad', Date.now() - beforeGasTimestamp, MetricLoggerUnit.Milliseconds);
|
|
618
|
+
return gasPriceWei;
|
|
619
|
+
}
|
|
620
|
+
async getGasModels(gasPriceWei, amountToken, quoteToken) {
|
|
621
|
+
const beforeGasModel = Date.now();
|
|
622
|
+
const v3GasModelPromise = this.v3GasModelFactory.buildGasModel({
|
|
623
|
+
chainId: this.chainId,
|
|
624
|
+
gasPriceWei,
|
|
625
|
+
v3poolProvider: this.v3PoolProvider,
|
|
626
|
+
amountToken,
|
|
627
|
+
quoteToken,
|
|
628
|
+
v2poolProvider: this.v2PoolProvider,
|
|
629
|
+
l2GasDataProvider: this.l2GasDataProvider,
|
|
630
|
+
});
|
|
631
|
+
const mixedRouteGasModelPromise = this.mixedRouteGasModelFactory.buildGasModel({
|
|
632
|
+
chainId: this.chainId,
|
|
633
|
+
gasPriceWei,
|
|
634
|
+
v3poolProvider: this.v3PoolProvider,
|
|
635
|
+
amountToken,
|
|
636
|
+
quoteToken,
|
|
637
|
+
v2poolProvider: this.v2PoolProvider,
|
|
638
|
+
});
|
|
639
|
+
const [v3GasModel, mixedRouteGasModel] = await Promise.all([
|
|
640
|
+
v3GasModelPromise,
|
|
641
|
+
mixedRouteGasModelPromise
|
|
642
|
+
]);
|
|
643
|
+
metric.putMetric('GasModelCreation', Date.now() - beforeGasModel, MetricLoggerUnit.Milliseconds);
|
|
644
|
+
return [v3GasModel, mixedRouteGasModel];
|
|
645
|
+
}
|
|
646
|
+
// Note multiplications here can result in a loss of precision in the amounts (e.g. taking 50% of 101)
|
|
647
|
+
// This is reconcilled at the end of the algorithm by adding any lost precision to one of
|
|
648
|
+
// the splits in the route.
|
|
649
|
+
getAmountDistribution(amount, routingConfig) {
|
|
650
|
+
const { distributionPercent } = routingConfig;
|
|
651
|
+
const percents = [];
|
|
652
|
+
const amounts = [];
|
|
653
|
+
for (let i = 1; i <= 100 / distributionPercent; i++) {
|
|
654
|
+
percents.push(i * distributionPercent);
|
|
655
|
+
amounts.push(amount.multiply(new Fraction(i * distributionPercent, 100)));
|
|
656
|
+
}
|
|
657
|
+
return [percents, amounts];
|
|
658
|
+
}
|
|
659
|
+
async buildSwapAndAddMethodParameters(trade, swapAndAddOptions, swapAndAddParameters) {
|
|
660
|
+
const { swapOptions: { recipient, slippageTolerance, deadline, inputTokenPermit }, addLiquidityOptions: addLiquidityConfig, } = swapAndAddOptions;
|
|
661
|
+
const preLiquidityPosition = swapAndAddParameters.preLiquidityPosition;
|
|
662
|
+
const finalBalanceTokenIn = swapAndAddParameters.initialBalanceTokenIn.subtract(trade.inputAmount);
|
|
663
|
+
const finalBalanceTokenOut = swapAndAddParameters.initialBalanceTokenOut.add(trade.outputAmount);
|
|
664
|
+
const approvalTypes = await this.swapRouterProvider.getApprovalType(finalBalanceTokenIn, finalBalanceTokenOut);
|
|
665
|
+
const zeroForOne = finalBalanceTokenIn.currency.wrapped.sortsBefore(finalBalanceTokenOut.currency.wrapped);
|
|
666
|
+
return {
|
|
667
|
+
...SwapRouter.swapAndAddCallParameters(trade, {
|
|
668
|
+
recipient,
|
|
669
|
+
slippageTolerance,
|
|
670
|
+
deadlineOrPreviousBlockhash: deadline,
|
|
671
|
+
inputTokenPermit,
|
|
672
|
+
}, Position.fromAmounts({
|
|
673
|
+
pool: preLiquidityPosition.pool,
|
|
674
|
+
tickLower: preLiquidityPosition.tickLower,
|
|
675
|
+
tickUpper: preLiquidityPosition.tickUpper,
|
|
676
|
+
amount0: zeroForOne
|
|
677
|
+
? finalBalanceTokenIn.quotient.toString()
|
|
678
|
+
: finalBalanceTokenOut.quotient.toString(),
|
|
679
|
+
amount1: zeroForOne
|
|
680
|
+
? finalBalanceTokenOut.quotient.toString()
|
|
681
|
+
: finalBalanceTokenIn.quotient.toString(),
|
|
682
|
+
useFullPrecision: false,
|
|
683
|
+
}), addLiquidityConfig, approvalTypes.approvalTokenIn, approvalTypes.approvalTokenOut),
|
|
684
|
+
to: SWAP_ROUTER_02_ADDRESSES(this.chainId),
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
emitPoolSelectionMetrics(swapRouteRaw, allPoolsBySelection) {
|
|
688
|
+
const poolAddressesUsed = new Set();
|
|
689
|
+
const { routes: routeAmounts } = swapRouteRaw;
|
|
690
|
+
_(routeAmounts)
|
|
691
|
+
.flatMap((routeAmount) => {
|
|
692
|
+
const { poolAddresses } = routeAmount;
|
|
693
|
+
return poolAddresses;
|
|
694
|
+
})
|
|
695
|
+
.forEach((address) => {
|
|
696
|
+
poolAddressesUsed.add(address.toLowerCase());
|
|
697
|
+
});
|
|
698
|
+
for (const poolsBySelection of allPoolsBySelection) {
|
|
699
|
+
const { protocol } = poolsBySelection;
|
|
700
|
+
_.forIn(poolsBySelection.selections, (pools, topNSelection) => {
|
|
701
|
+
const topNUsed = _.findLastIndex(pools, (pool) => poolAddressesUsed.has(pool.id.toLowerCase())) + 1;
|
|
702
|
+
metric.putMetric(_.capitalize(`${protocol}${topNSelection}`), topNUsed, MetricLoggerUnit.Count);
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
let hasV3Route = false;
|
|
706
|
+
let hasV2Route = false;
|
|
707
|
+
let hasMixedRoute = false;
|
|
708
|
+
for (const routeAmount of routeAmounts) {
|
|
709
|
+
if (routeAmount.protocol === Protocol.V3) {
|
|
710
|
+
hasV3Route = true;
|
|
711
|
+
}
|
|
712
|
+
if (routeAmount.protocol === Protocol.V2) {
|
|
713
|
+
hasV2Route = true;
|
|
714
|
+
}
|
|
715
|
+
if (routeAmount.protocol === Protocol.MIXED) {
|
|
716
|
+
hasMixedRoute = true;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
if (hasMixedRoute && (hasV3Route || hasV2Route)) {
|
|
720
|
+
if (hasV3Route && hasV2Route) {
|
|
721
|
+
metric.putMetric(`MixedAndV3AndV2SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
722
|
+
metric.putMetric(`MixedAndV3AndV2SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
723
|
+
}
|
|
724
|
+
else if (hasV3Route) {
|
|
725
|
+
metric.putMetric(`MixedAndV3SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
726
|
+
metric.putMetric(`MixedAndV3SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
727
|
+
}
|
|
728
|
+
else if (hasV2Route) {
|
|
729
|
+
metric.putMetric(`MixedAndV2SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
730
|
+
metric.putMetric(`MixedAndV2SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
else if (hasV3Route && hasV2Route) {
|
|
734
|
+
metric.putMetric(`V3AndV2SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
735
|
+
metric.putMetric(`V3AndV2SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
736
|
+
}
|
|
737
|
+
else if (hasMixedRoute) {
|
|
738
|
+
if (routeAmounts.length > 1) {
|
|
739
|
+
metric.putMetric(`MixedSplitRoute`, 1, MetricLoggerUnit.Count);
|
|
740
|
+
metric.putMetric(`MixedSplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
metric.putMetric(`MixedRoute`, 1, MetricLoggerUnit.Count);
|
|
744
|
+
metric.putMetric(`MixedRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
else if (hasV3Route) {
|
|
748
|
+
if (routeAmounts.length > 1) {
|
|
749
|
+
metric.putMetric(`V3SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
750
|
+
metric.putMetric(`V3SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
751
|
+
}
|
|
752
|
+
else {
|
|
753
|
+
metric.putMetric(`V3Route`, 1, MetricLoggerUnit.Count);
|
|
754
|
+
metric.putMetric(`V3RouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
else if (hasV2Route) {
|
|
758
|
+
if (routeAmounts.length > 1) {
|
|
759
|
+
metric.putMetric(`V2SplitRoute`, 1, MetricLoggerUnit.Count);
|
|
760
|
+
metric.putMetric(`V2SplitRouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
metric.putMetric(`V2Route`, 1, MetricLoggerUnit.Count);
|
|
764
|
+
metric.putMetric(`V2RouteForChain${this.chainId}`, 1, MetricLoggerUnit.Count);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
calculateOptimalRatio(position, sqrtRatioX96, zeroForOne) {
|
|
769
|
+
const upperSqrtRatioX96 = TickMath.getSqrtRatioAtTick(position.tickUpper);
|
|
770
|
+
const lowerSqrtRatioX96 = TickMath.getSqrtRatioAtTick(position.tickLower);
|
|
771
|
+
// returns Fraction(0, 1) for any out of range position regardless of zeroForOne. Implication: function
|
|
772
|
+
// cannot be used to determine the trading direction of out of range positions.
|
|
773
|
+
if (JSBI.greaterThan(sqrtRatioX96, upperSqrtRatioX96) ||
|
|
774
|
+
JSBI.lessThan(sqrtRatioX96, lowerSqrtRatioX96)) {
|
|
775
|
+
return new Fraction(0, 1);
|
|
776
|
+
}
|
|
777
|
+
const precision = JSBI.BigInt('1' + '0'.repeat(18));
|
|
778
|
+
let optimalRatio = new Fraction(SqrtPriceMath.getAmount0Delta(sqrtRatioX96, upperSqrtRatioX96, precision, true), SqrtPriceMath.getAmount1Delta(sqrtRatioX96, lowerSqrtRatioX96, precision, true));
|
|
779
|
+
if (!zeroForOne)
|
|
780
|
+
optimalRatio = optimalRatio.invert();
|
|
781
|
+
return optimalRatio;
|
|
782
|
+
}
|
|
783
|
+
async userHasSufficientBalance(fromAddress, tradeType, amount, quote) {
|
|
784
|
+
try {
|
|
785
|
+
const neededBalance = tradeType === TradeType.EXACT_INPUT ? amount : quote;
|
|
786
|
+
let balance;
|
|
787
|
+
if (neededBalance.currency.isNative) {
|
|
788
|
+
balance = await this.provider.getBalance(fromAddress);
|
|
789
|
+
}
|
|
790
|
+
else {
|
|
791
|
+
const tokenContract = Erc20__factory.connect(neededBalance.currency.address, this.provider);
|
|
792
|
+
balance = await tokenContract.balanceOf(fromAddress);
|
|
793
|
+
}
|
|
794
|
+
return balance.gte(BigNumber.from(neededBalance.quotient.toString()));
|
|
795
|
+
}
|
|
796
|
+
catch (e) {
|
|
797
|
+
log.error(e, 'Error while checking user balance');
|
|
798
|
+
return false;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
absoluteValue(fraction) {
|
|
802
|
+
const numeratorAbs = JSBI.lessThan(fraction.numerator, JSBI.BigInt(0))
|
|
803
|
+
? JSBI.unaryMinus(fraction.numerator)
|
|
804
|
+
: fraction.numerator;
|
|
805
|
+
const denominatorAbs = JSBI.lessThan(fraction.denominator, JSBI.BigInt(0))
|
|
806
|
+
? JSBI.unaryMinus(fraction.denominator)
|
|
807
|
+
: fraction.denominator;
|
|
808
|
+
return new Fraction(numeratorAbs, denominatorAbs);
|
|
809
|
+
}
|
|
810
|
+
getBlockNumberPromise() {
|
|
811
|
+
return retry(async (_b, attempt) => {
|
|
812
|
+
if (attempt > 1) {
|
|
813
|
+
log.info(`Get block number attempt ${attempt}`);
|
|
814
|
+
}
|
|
815
|
+
return this.provider.getBlockNumber();
|
|
816
|
+
}, {
|
|
817
|
+
retries: 2,
|
|
818
|
+
minTimeout: 100,
|
|
819
|
+
maxTimeout: 1000,
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxwaGEtcm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3JvdXRlcnMvYWxwaGEtcm91dGVyL2FscGhhLXJvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckQsT0FBTyxFQUFnQixlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RSxPQUFPLGtCQUFrQixNQUFNLDZCQUE2QixDQUFDO0FBQzdELE9BQU8sRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFTLE1BQU0scUJBQXFCLENBQUM7QUFDbEUsT0FBTyxFQUFZLFFBQVEsRUFBUyxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUV6RSxPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxhQUFhLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDMUUsT0FBTyxLQUFLLE1BQU0sYUFBYSxDQUFDO0FBQ2hDLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUN4QixPQUFPLENBQUMsTUFBTSxRQUFRLENBQUM7QUFDdkIsT0FBTyxTQUFTLE1BQU0sWUFBWSxDQUFDO0FBRW5DLE9BQU8sRUFDTCxZQUFZLEVBQ1osU0FBUyxFQUNULHlCQUF5QixFQUN6QixnQ0FBZ0MsRUFDaEMscUJBQXFCLEVBQ3JCLHlCQUF5QixFQUN6QixxQkFBcUIsRUFDckIseUJBQXlCLEVBQ3pCLHVCQUF1QixFQUN2Qix5QkFBeUIsRUFNekIsc0JBQXNCLEVBQ3RCLFdBQVcsRUFDWCx1QkFBdUIsRUFDdkIsb0JBQW9CLEVBRXBCLHdCQUF3QixFQUN4Qix3QkFBd0IsRUFDeEIsa0JBQWtCLEVBQ2xCLHdCQUF3QixFQUN4QixtQkFBbUIsRUFDbkIsZUFBZSxFQUNmLCtCQUErQixFQUMvQiwrQkFBK0IsR0FDaEMsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QixPQUFPLEVBQUUsd0JBQXdCLEVB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
|