From d9ab147c9438a9442fe23ef191501255da764f81 Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Thu, 20 Jan 2022 20:55:20 -0500 Subject: [PATCH 01/12] adding optimism l1 security fee to gas estimates --- cli/base-command.ts | 14 +- cli/commands/quote.ts | 12 +- package.json | 2 +- src/abis/gasPriceOracle.json | 298 ++++++++++++++++++ src/providers/swap-router-provider.ts | 2 +- src/providers/v3/gas-data-provider.ts | 51 +++ src/routers/alpha-router/alpha-router.ts | 205 +++--------- src/routers/alpha-router/config.ts | 12 +- .../entities/route-with-valid-quote.ts | 25 +- .../alpha-router/functions/best-swap-route.ts | 27 ++ .../alpha-router/gas-models/gas-model.ts | 8 +- .../gas-models/v2/v2-heuristic-gas-model.ts | 3 + .../alpha-router/gas-models/v3/gas-costs.ts | 60 ++++ .../gas-models/v3/v3-heuristic-gas-model.ts | 169 ++++++++-- src/routers/router.ts | 12 +- src/util/addresses.ts | 2 + src/util/methodParameters.ts | 173 ++++++++++ 17 files changed, 856 insertions(+), 219 deletions(-) create mode 100644 src/abis/gasPriceOracle.json create mode 100644 src/providers/v3/gas-data-provider.ts create mode 100644 src/routers/alpha-router/gas-models/v3/gas-costs.ts create mode 100644 src/util/methodParameters.ts diff --git a/cli/base-command.ts b/cli/base-command.ts index 6641ff3fe..0cea10c2b 100644 --- a/cli/base-command.ts +++ b/cli/base-command.ts @@ -70,7 +70,7 @@ export abstract class BaseCommand extends Command { }), maxSwapsPerPath: flags.integer({ required: false, - default: 3, + default: 1, }), minSplits: flags.integer({ required: false, @@ -78,7 +78,7 @@ export abstract class BaseCommand extends Command { }), maxSplits: flags.integer({ required: false, - default: 3, + default: 1, }), distributionPercent: flags.integer({ required: false, @@ -297,7 +297,10 @@ export abstract class BaseCommand extends Command { methodParameters: MethodParameters | undefined, blockNumber: BigNumber, estimatedGasUsed: BigNumber, - gasPriceWei: BigNumber + gasPriceWei: BigNumber, + initTicksCrossed?: BigNumber, + l1GasUse?: BigNumber, + l1GasCost?: BigNumber ) { this.logger.info(`Best Route:`); this.logger.info(`${routeAmountsToString(routeAmounts)}`); @@ -318,5 +321,10 @@ export abstract class BaseCommand extends Command { estimatedGasUsed: estimatedGasUsed.toString(), gasPriceWei: gasPriceWei.toString(), }); + const hops = routeAmounts[0]?.poolAddresses.length; + this.logger.info(`Total hops ${hops}`); + this.logger.info(`Total initialized ticks crossed ${initTicksCrossed}`); + this.logger.info(`Optimism l1 gas cost: ${l1GasCost}`); + this.logger.info(`Optimism l1 gas use: ${l1GasUse}`); } } diff --git a/cli/commands/quote.ts b/cli/commands/quote.ts index ba92aa15d..6f7548536 100644 --- a/cli/commands/quote.ts +++ b/cli/commands/quote.ts @@ -109,9 +109,9 @@ export class Quote extends BaseCommand { TradeType.EXACT_INPUT, recipient ? { - deadline: 100, + deadline: 10000000000, recipient, - slippageTolerance: new Percent(5, 10_000), + slippageTolerance: new Percent(200000, 10_000), } : undefined, { @@ -186,6 +186,9 @@ export class Quote extends BaseCommand { quote, quoteGasAdjusted, route: routeAmounts, + initTicksCrossed, + l1GasUse, + l1GasCost, } = swapRoutes; this.logSwapResults( @@ -197,7 +200,10 @@ export class Quote extends BaseCommand { methodParameters, blockNumber, estimatedGasUsed, - gasPriceWei + gasPriceWei, + initTicksCrossed!, + l1GasUse!, + l1GasCost! ); } } diff --git a/package.json b/package.json index 02f5229b6..7de4cc20a 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "scripts": { "compile-v3-types": "npx typechain --target ethers-v5 --out-dir src/types/v3 './node_modules/@uniswap/?(v3-core|v3-periphery)/artifacts/contracts/**/*.json'", "compile-v2-types": "npx typechain --target ethers-v5 --out-dir src/types/v2 './node_modules/@uniswap/?(v2-core|v2-periphery)/build/*UniswapV2*.json'", - "compile-router": "npx typechain --target ethers-v5 --out-dir src/types/other './node_modules/@uniswap/swap-router-contracts/artifacts/contracts/SwapRouter02.sol/SwapRouter02.json'", + "compile-router": "npx typechain --target ethers-v5 --out-dir src/types/router02 './node_modules/@uniswap/swap-router-contracts/artifacts/contracts/SwapRouter02.sol/SwapRouter02.json'", "compile-external-types": "npx typechain --target ethers-v5 --out-dir src/types/other 'src/abis/**/*.json'", "build": "run-p compile-v3-types compile-v2-types compile-router compile-external-types && run-p build:*", "build:main": "tsc -p tsconfig.json", diff --git a/src/abis/gasPriceOracle.json b/src/abis/gasPriceOracle.json new file mode 100644 index 000000000..1a81647c4 --- /dev/null +++ b/src/abis/gasPriceOracle.json @@ -0,0 +1,298 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "DecimalsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "GasPriceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "L1BaseFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "OverheadUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "ScalarUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "getL1Fee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "getL1GasUsed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1BaseFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "overhead", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "scalar", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_decimals", + "type": "uint256" + } + ], + "name": "setDecimals", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasPrice", + "type": "uint256" + } + ], + "name": "setGasPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_baseFee", + "type": "uint256" + } + ], + "name": "setL1BaseFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_overhead", + "type": "uint256" + } + ], + "name": "setOverhead", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_scalar", + "type": "uint256" + } + ], + "name": "setScalar", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] \ No newline at end of file diff --git a/src/providers/swap-router-provider.ts b/src/providers/swap-router-provider.ts index 16831add2..a73a7110d 100644 --- a/src/providers/swap-router-provider.ts +++ b/src/providers/swap-router-provider.ts @@ -1,6 +1,6 @@ import { ApprovalTypes } from '@uniswap/router-sdk'; import { Currency, CurrencyAmount } from '@uniswap/sdk-core'; -import { SwapRouter02__factory } from '../types/other'; +import { SwapRouter02__factory } from '../types/router02'; import { log } from '../util'; import { IMulticallProvider } from './multicall-provider'; diff --git a/src/providers/v3/gas-data-provider.ts b/src/providers/v3/gas-data-provider.ts new file mode 100644 index 000000000..69630a4d6 --- /dev/null +++ b/src/providers/v3/gas-data-provider.ts @@ -0,0 +1,51 @@ +import { BigNumber, providers } from 'ethers'; +import { OptimismGasData } from '../../routers'; +import { GasPriceOracle, GasPriceOracle__factory } from '../../types/other'; +import { ChainId, log, OVM_GASPRICE_ADDRESS } from '../../util'; + +export interface IGasDataProvider { + getGasData(): Promise; +} + +export class GasDataProvider implements IGasDataProvider { + protected gasOracleAddress: string; + private gasOracleContract: GasPriceOracle; + + constructor( + protected chainId: ChainId, + protected provider: providers.BaseProvider, + gasPriceAddress?: string + ) { + this.gasOracleAddress = gasPriceAddress ?? OVM_GASPRICE_ADDRESS; + + this.gasOracleContract = GasPriceOracle__factory.connect( + this.gasOracleAddress, + provider + ); + } + + public async getGasData(): Promise { + const [l1BaseFee, scalar, decimals, overhead]: BigNumber[] = + await Promise.all([ + this.gasOracleContract.l1BaseFee(), + this.gasOracleContract.scalar(), + this.gasOracleContract.decimals(), + this.gasOracleContract.overhead(), + ]); + + const data: OptimismGasData = { + l1BaseFee, + scalar, + decimals, + overhead, + }; + + log.debug('DATA FIELD'); + log.debug(data.decimals); + log.debug(data.l1BaseFee); + log.debug(data.overhead); + log.debug(data.scalar); + + return data; + } +} diff --git a/src/routers/alpha-router/alpha-router.ts b/src/routers/alpha-router/alpha-router.ts index 25b6ac740..c80f6af1c 100644 --- a/src/routers/alpha-router/alpha-router.ts +++ b/src/routers/alpha-router/alpha-router.ts @@ -2,12 +2,10 @@ import DEFAULT_TOKEN_LIST from '@uniswap/default-token-list'; import { Protocol, SwapRouter, Trade } from '@uniswap/router-sdk'; import { Currency, Fraction, Token, TradeType } from '@uniswap/sdk-core'; import { TokenList } from '@uniswap/token-lists'; -import { Route as V2RouteRaw } from '@uniswap/v2-sdk'; import { MethodParameters, Pool, Position, - Route as V3RouteRaw, SqrtPriceMath, TickMath, } from '@uniswap/v3-sdk'; @@ -52,6 +50,10 @@ import { IV2PoolProvider, V2PoolProvider, } from '../../providers/v2/pool-provider'; +import { + GasDataProvider, + IGasDataProvider, +} from '../../providers/v3/gas-data-provider'; import { IV3PoolProvider, V3PoolProvider, @@ -64,6 +66,10 @@ import { IV3SubgraphProvider } from '../../providers/v3/subgraph-provider'; import { CurrencyAmount } from '../../util/amounts'; import { ChainId, ID_TO_CHAIN_ID, ID_TO_NETWORK_NAME } from '../../util/chains'; import { log } from '../../util/log'; +import { + buildSwapMethodParameters, + buildTrade, +} from '../../util/methodParameters'; import { metric, MetricLoggerUnit } from '../../util/metric'; import { routeToString } from '../../util/routes'; import { UNSUPPORTED_TOKENS } from '../../util/unsupported-tokens'; @@ -288,6 +294,7 @@ export class AlphaRouter protected v3GasModelFactory: IV3GasModelFactory; protected v2GasModelFactory: IV2GasModelFactory; protected blockedTokenListProvider?: ITokenListProvider; + protected optimismGasDataProvider?: IGasDataProvider; constructor({ chainId, @@ -492,6 +499,13 @@ export class AlphaRouter this.swapRouterProvider = swapRouterProvider ?? new SwapRouterProvider(this.multicall2Provider); + + if (chainId == ChainId.OPTIMISM || ChainId.OPTIMISTIC_KOVAN) { + this.optimismGasDataProvider = new GasDataProvider( + chainId, + this.provider + ); + } } public async routeToRatio( @@ -768,7 +782,8 @@ export class AlphaRouter quoteToken, gasPriceWei, tradeType, - routingConfig + routingConfig, + swapConfig ?? undefined ) ); } @@ -831,10 +846,13 @@ export class AlphaRouter routes: routeAmounts, estimatedGasUsedQuoteToken, estimatedGasUsedUSD, + initTicksCrossed, + l1GasCost, + l1GasUse, } = swapRouteRaw; // Build Trade object that represents the optimal swap. - const trade = this.buildTrade( + const trade = buildTrade( currencyIn, currencyOut, tradeType, @@ -846,7 +864,7 @@ export class AlphaRouter // If user provided recipient, deadline etc. we also generate the calldata required to execute // the swap and return it too. if (swapConfig) { - methodParameters = this.buildSwapMethodParameters(trade, swapConfig); + methodParameters = buildSwapMethodParameters(trade, swapConfig); } metric.putMetric( @@ -874,6 +892,9 @@ export class AlphaRouter trade, methodParameters, blockNumber: BigNumber.from(await blockNumber), + initTicksCrossed, + l1GasCost, + l1GasUse, }; } @@ -885,7 +906,8 @@ export class AlphaRouter quoteToken: Token, gasPriceWei: BigNumber, swapType: TradeType, - routingConfig: AlphaRouterConfig + routingConfig: AlphaRouterConfig, + swapConfig?: SwapOptions ): Promise<{ routesWithValidQuotes: V3RouteWithValidQuote[]; candidatePools: CandidatePoolsBySelectionCriteria; @@ -934,11 +956,18 @@ export class AlphaRouter blockNumber: routingConfig.blockNumber, }); + // only make contract calls once + const gasData = this.optimismGasDataProvider + ? await this.optimismGasDataProvider.getGasData() + : undefined; + const gasModel = await this.v3GasModelFactory.buildGasModel( this.chainId, gasPriceWei, this.v3PoolProvider, - quoteToken + quoteToken, + swapConfig, + gasData ); metric.putMetric( @@ -1143,168 +1172,6 @@ export class AlphaRouter return [percents, amounts]; } - private buildTrade( - tokenInCurrency: Currency, - tokenOutCurrency: Currency, - tradeType: TTradeType, - routeAmounts: RouteWithValidQuote[] - ): Trade { - const [v3RouteAmounts, v2RouteAmounts] = _.partition( - routeAmounts, - (routeAmount) => routeAmount.protocol == Protocol.V3 - ); - - const v3Routes = _.map< - V3RouteWithValidQuote, - { - routev3: V3RouteRaw; - inputAmount: CurrencyAmount; - outputAmount: CurrencyAmount; - } - >( - v3RouteAmounts as V3RouteWithValidQuote[], - (routeAmount: V3RouteWithValidQuote) => { - const { route, amount, quote } = routeAmount; - - // The route, amount and quote are all in terms of wrapped tokens. - // When constructing the Trade object the inputAmount/outputAmount must - // use native currencies if specified by the user. This is so that the Trade knows to wrap/unwrap. - if (tradeType == TradeType.EXACT_INPUT) { - const amountCurrency = CurrencyAmount.fromFractionalAmount( - tokenInCurrency, - amount.numerator, - amount.denominator - ); - const quoteCurrency = CurrencyAmount.fromFractionalAmount( - tokenOutCurrency, - quote.numerator, - quote.denominator - ); - - const routeRaw = new V3RouteRaw( - route.pools, - amountCurrency.currency, - quoteCurrency.currency - ); - - return { - routev3: routeRaw, - inputAmount: amountCurrency, - outputAmount: quoteCurrency, - }; - } else { - const quoteCurrency = CurrencyAmount.fromFractionalAmount( - tokenInCurrency, - quote.numerator, - quote.denominator - ); - - const amountCurrency = CurrencyAmount.fromFractionalAmount( - tokenOutCurrency, - amount.numerator, - amount.denominator - ); - - const routeCurrency = new V3RouteRaw( - route.pools, - quoteCurrency.currency, - amountCurrency.currency - ); - - return { - routev3: routeCurrency, - inputAmount: quoteCurrency, - outputAmount: amountCurrency, - }; - } - } - ); - - const v2Routes = _.map< - V2RouteWithValidQuote, - { - routev2: V2RouteRaw; - inputAmount: CurrencyAmount; - outputAmount: CurrencyAmount; - } - >( - v2RouteAmounts as V2RouteWithValidQuote[], - (routeAmount: V2RouteWithValidQuote) => { - const { route, amount, quote } = routeAmount; - - // The route, amount and quote are all in terms of wrapped tokens. - // When constructing the Trade object the inputAmount/outputAmount must - // use native currencies if specified by the user. This is so that the Trade knows to wrap/unwrap. - if (tradeType == TradeType.EXACT_INPUT) { - const amountCurrency = CurrencyAmount.fromFractionalAmount( - tokenInCurrency, - amount.numerator, - amount.denominator - ); - const quoteCurrency = CurrencyAmount.fromFractionalAmount( - tokenOutCurrency, - quote.numerator, - quote.denominator - ); - - const routeV2SDK = new V2RouteRaw( - route.pairs, - amountCurrency.currency, - quoteCurrency.currency - ); - - return { - routev2: routeV2SDK, - inputAmount: amountCurrency, - outputAmount: quoteCurrency, - }; - } else { - const quoteCurrency = CurrencyAmount.fromFractionalAmount( - tokenInCurrency, - quote.numerator, - quote.denominator - ); - - const amountCurrency = CurrencyAmount.fromFractionalAmount( - tokenOutCurrency, - amount.numerator, - amount.denominator - ); - - const routeV2SDK = new V2RouteRaw( - route.pairs, - quoteCurrency.currency, - amountCurrency.currency - ); - - return { - routev2: routeV2SDK, - inputAmount: quoteCurrency, - outputAmount: amountCurrency, - }; - } - } - ); - - const trade = new Trade({ v2Routes, v3Routes, tradeType }); - - return trade; - } - - private buildSwapMethodParameters( - trade: Trade, - swapConfig: SwapOptions - ): MethodParameters { - const { recipient, slippageTolerance, deadline, inputTokenPermit } = - swapConfig; - return SwapRouter.swapCallParameters(trade, { - recipient, - slippageTolerance, - deadlineOrPreviousBlockhash: deadline, - inputTokenPermit, - }); - } - private async buildSwapAndAddMethodParameters( trade: Trade, swapAndAddOptions: SwapAndAddOptions, diff --git a/src/routers/alpha-router/config.ts b/src/routers/alpha-router/config.ts index d01d3c6ee..d18ce5b06 100644 --- a/src/routers/alpha-router/config.ts +++ b/src/routers/alpha-router/config.ts @@ -25,9 +25,9 @@ export const DEFAULT_ROUTING_CONFIG_BY_CHAIN = ( topNWithEachBaseToken: 3, topNWithBaseToken: 3, }, - maxSwapsPerPath: 3, + maxSwapsPerPath: 1, minSplits: 1, - maxSplits: 7, + maxSplits: 1, distributionPercent: 10, forceCrossProtocol: false, }; @@ -53,9 +53,9 @@ export const DEFAULT_ROUTING_CONFIG_BY_CHAIN = ( topNWithEachBaseToken: 3, topNWithBaseToken: 2, }, - maxSwapsPerPath: 2, + maxSwapsPerPath: 1, minSplits: 1, - maxSplits: 7, + maxSplits: 1, distributionPercent: 25, forceCrossProtocol: false, }; @@ -77,9 +77,9 @@ export const DEFAULT_ROUTING_CONFIG_BY_CHAIN = ( topNWithEachBaseToken: 3, topNWithBaseToken: 5, }, - maxSwapsPerPath: 3, + maxSwapsPerPath: 1, minSplits: 1, - maxSplits: 7, + maxSplits: 1, distributionPercent: 5, forceCrossProtocol: false, }; diff --git a/src/routers/alpha-router/entities/route-with-valid-quote.ts b/src/routers/alpha-router/entities/route-with-valid-quote.ts index a132393e2..2a82203d0 100644 --- a/src/routers/alpha-router/entities/route-with-valid-quote.ts +++ b/src/routers/alpha-router/entities/route-with-valid-quote.ts @@ -79,6 +79,9 @@ export class V2RouteWithValidQuote implements IV2RouteWithValidQuote { public tradeType: TradeType; public poolAddresses: string[]; public tokenPath: Token[]; + public initTicksCrossed: number; + public gasUseL1: BigNumber; + public gasCostL1: BigNumber; public toString(): string { return `${this.percent.toFixed( @@ -107,12 +110,16 @@ export class V2RouteWithValidQuote implements IV2RouteWithValidQuote { this.quoteToken = quoteToken; this.tradeType = tradeType; - const { gasEstimate, gasCostInToken, gasCostInUSD } = + const { gasEstimate, gasCostInToken, gasCostInUSD, initTicksCrossed } = this.gasModel.estimateGasCost(this); this.gasCostInToken = gasCostInToken; this.gasCostInUSD = gasCostInUSD; this.gasEstimate = gasEstimate; + this.initTicksCrossed = initTicksCrossed!; + // these costs are from optimism which is not deployed on v2 so we ignore + this.gasUseL1 = BigNumber.from(0); + this.gasCostL1 = BigNumber.from(0); // If its exact out, we need to request *more* of the input token to account for the gas. if (this.tradeType == TradeType.EXACT_INPUT) { @@ -173,6 +180,9 @@ export class V3RouteWithValidQuote implements IV3RouteWithValidQuote { public tradeType: TradeType; public poolAddresses: string[]; public tokenPath: Token[]; + public initTicksCrossed: number; + public gasUseL1: BigNumber; + public gasCostL1: BigNumber; public toString(): string { return `${this.percent.toFixed( @@ -207,12 +217,21 @@ export class V3RouteWithValidQuote implements IV3RouteWithValidQuote { this.quoteToken = quoteToken; this.tradeType = tradeType; - const { gasEstimate, gasCostInToken, gasCostInUSD } = - this.gasModel.estimateGasCost(this); + const { + gasEstimate, + gasCostInToken, + gasCostInUSD, + initTicksCrossed, + gasUseL1, + gasCostL1, + } = this.gasModel.estimateGasCost(this); this.gasCostInToken = gasCostInToken; this.gasCostInUSD = gasCostInUSD; this.gasEstimate = gasEstimate; + this.initTicksCrossed = initTicksCrossed!; + this.gasUseL1 = gasUseL1!; + this.gasCostL1 = gasCostL1!; // If its exact out, we need to request *more* of the input token to account for the gas. if (this.tradeType == TradeType.EXACT_INPUT) { diff --git a/src/routers/alpha-router/functions/best-swap-route.ts b/src/routers/alpha-router/functions/best-swap-route.ts index dd981e6ff..05e581d5c 100644 --- a/src/routers/alpha-router/functions/best-swap-route.ts +++ b/src/routers/alpha-router/functions/best-swap-route.ts @@ -26,6 +26,9 @@ export function getBestSwapRoute( estimatedGasUsedUSD: CurrencyAmount; estimatedGasUsedQuoteToken: CurrencyAmount; routes: RouteWithValidQuote[]; + initTicksCrossed: BigNumber; + l1GasCost: BigNumber; + l1GasUse: BigNumber; } | null { const now = Date.now(); @@ -116,6 +119,9 @@ export function getBestSwapRouteBy( estimatedGasUsedUSD: CurrencyAmount; estimatedGasUsedQuoteToken: CurrencyAmount; routes: RouteWithValidQuote[]; + initTicksCrossed: BigNumber; + l1GasUse: BigNumber; + l1GasCost: BigNumber; } | undefined { // Build a map of percentage to sorted list of quotes, with the biggest quote being first in the list. @@ -433,6 +439,24 @@ export function getBestSwapRouteBy( _.map(bestSwap, (routeWithValidQuote) => routeWithValidQuote.quote) ); + const totalInitTicksCrossed = _.map( + bestSwap, + (routeWithValidQuote) => routeWithValidQuote.initTicksCrossed + ).reduce( + (sum, routeWithValidQuote) => sum.add(routeWithValidQuote), + BigNumber.from(0) + ); + + const totalL1GasUsed = _.map(bestSwap, (route) => route.gasUseL1).reduce( + (sum, route) => sum.add(route), + BigNumber.from(0) + ); + + const totalL1GasCost = _.map(bestSwap, (route) => route.gasCostL1).reduce( + (sum, route) => sum.add(route), + BigNumber.from(0) + ); + const routeWithQuotes = bestSwap.sort((routeAmountA, routeAmountB) => routeAmountB.amount.greaterThan(routeAmountA.amount) ? 1 : -1 ); @@ -450,6 +474,9 @@ export function getBestSwapRouteBy( estimatedGasUsedUSD, estimatedGasUsedQuoteToken, routes: routeWithQuotes, + initTicksCrossed: totalInitTicksCrossed, + l1GasCost: totalL1GasCost, + l1GasUse: totalL1GasUsed, }; } diff --git a/src/routers/alpha-router/gas-models/gas-model.ts b/src/routers/alpha-router/gas-models/gas-model.ts index 93a4e8839..ad726c4da 100644 --- a/src/routers/alpha-router/gas-models/gas-model.ts +++ b/src/routers/alpha-router/gas-models/gas-model.ts @@ -34,6 +34,7 @@ import { IV2PoolProvider } from '../../../providers/v2/pool-provider'; import { IV3PoolProvider } from '../../../providers/v3/pool-provider'; import { CurrencyAmount } from '../../../util/amounts'; import { ChainId } from '../../../util/chains'; +import { OptimismGasData, SwapOptions } from '../../router'; import { RouteWithValidQuote, V2RouteWithValidQuote, @@ -79,6 +80,9 @@ export type IGasModel = { gasEstimate: BigNumber; gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; + initTicksCrossed?: number; + gasUseL1?: BigNumber; + gasCostL1?: BigNumber; }; }; @@ -98,7 +102,9 @@ export abstract class IV3GasModelFactory { chainId: number, gasPriceWei: BigNumber, poolProvider: IV3PoolProvider, - inTermsOfToken: Token + inTermsOfToken: Token, + swapConfig?: SwapOptions, + gasData?: OptimismGasData ): Promise>; } diff --git a/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts b/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts index 8aabe0575..3d6837908 100644 --- a/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts +++ b/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts @@ -75,6 +75,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { gasEstimate: gasUse, gasCostInToken: gasCostInEth, gasCostInUSD: gasCostInTermsOfUSD, + initTicksCrossed: 0, }; }, }; @@ -114,6 +115,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { gasEstimate: gasUse, gasCostInToken: CurrencyAmount.fromRawAmount(token, 0), gasCostInUSD: CurrencyAmount.fromRawAmount(usdToken, 0), + initTicksCrossed: 0, }; } @@ -169,6 +171,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { gasEstimate: gasUse, gasCostInToken: gasCostInTermsOfQuoteToken, gasCostInUSD: gasCostInTermsOfUSD!, + initTicksCrossed: 0, }; }, }; diff --git a/src/routers/alpha-router/gas-models/v3/gas-costs.ts b/src/routers/alpha-router/gas-models/v3/gas-costs.ts new file mode 100644 index 000000000..20b35454b --- /dev/null +++ b/src/routers/alpha-router/gas-models/v3/gas-costs.ts @@ -0,0 +1,60 @@ +import { BigNumber } from 'ethers'; +import { ChainId } from '../../../..'; + +//l2 execution fee on optimism is roughly the same as mainnet +export const BASE_SWAP_COST = (id: ChainId): BigNumber => { + switch (id) { + case ChainId.MAINNET: + case ChainId.ROPSTEN: + case ChainId.RINKEBY: + case ChainId.GÖRLI: + case ChainId.OPTIMISM: + case ChainId.OPTIMISTIC_KOVAN: + case ChainId.KOVAN: + return BigNumber.from(2000); + case ChainId.ARBITRUM_ONE: + case ChainId.ARBITRUM_RINKEBY: + return BigNumber.from(2000); + case ChainId.POLYGON: + case ChainId.POLYGON_MUMBAI: + return BigNumber.from(2000); + } +}; +export const COST_PER_INIT_TICK = (id: ChainId): BigNumber => { + switch (id) { + case ChainId.MAINNET: + case ChainId.ROPSTEN: + case ChainId.RINKEBY: + case ChainId.GÖRLI: + case ChainId.KOVAN: + return BigNumber.from(31000); + case ChainId.OPTIMISM: + case ChainId.OPTIMISTIC_KOVAN: + return BigNumber.from(31000); + case ChainId.ARBITRUM_ONE: + case ChainId.ARBITRUM_RINKEBY: + return BigNumber.from(31000); + case ChainId.POLYGON: + case ChainId.POLYGON_MUMBAI: + return BigNumber.from(31000); + } +}; + +export const COST_PER_HOP = (id: ChainId): BigNumber => { + switch (id) { + case ChainId.MAINNET: + case ChainId.ROPSTEN: + case ChainId.RINKEBY: + case ChainId.GÖRLI: + case ChainId.KOVAN: + case ChainId.OPTIMISM: + case ChainId.OPTIMISTIC_KOVAN: + return BigNumber.from(80000); + case ChainId.ARBITRUM_ONE: + case ChainId.ARBITRUM_RINKEBY: + return BigNumber.from(80000); + case ChainId.POLYGON: + case ChainId.POLYGON_MUMBAI: + return BigNumber.from(80000); + } +}; diff --git a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts index ffedbb99e..7a1a997dc 100644 --- a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts +++ b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts @@ -2,30 +2,30 @@ import { BigNumber } from '@ethersproject/bignumber'; import { Token } from '@uniswap/sdk-core'; import { FeeAmount, Pool } from '@uniswap/v3-sdk'; import _ from 'lodash'; -import { WRAPPED_NATIVE_CURRENCY } from '../../../..'; +import { + OptimismGasData, + SwapOptions, + WRAPPED_NATIVE_CURRENCY, +} from '../../../..'; import { IV3PoolProvider } from '../../../../providers/v3/pool-provider'; import { ChainId } from '../../../../util'; import { CurrencyAmount } from '../../../../util/amounts'; import { log } from '../../../../util/log'; +import { + buildSwapMethodParameters, + buildTrade, +} from '../../../../util/methodParameters'; import { V3RouteWithValidQuote } from '../../entities/route-with-valid-quote'; import { IGasModel, IV3GasModelFactory, usdGasTokensByChain, } from '../gas-model'; - -// Constant cost for doing any swap regardless of pools. -const BASE_SWAP_COST = BigNumber.from(2000); - -// Cost for crossing an initialized tick. -const COST_PER_INIT_TICK = BigNumber.from(31000); +import { BASE_SWAP_COST, COST_PER_HOP, COST_PER_INIT_TICK } from './gas-costs'; // Cost for crossing an uninitialized tick. const COST_PER_UNINIT_TICK = BigNumber.from(0); -// Constant per pool swap in the route. -const COST_PER_HOP = BigNumber.from(80000); - /** * Computes a gas estimate for a V3 swap using heuristics. * Considers number of hops in the route, number of ticks crossed @@ -53,7 +53,9 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { chainId: ChainId, gasPriceWei: BigNumber, poolProvider: IV3PoolProvider, - token: Token + token: Token, + swapConfig?: SwapOptions, + gasData?: OptimismGasData // this is the quoteToken ): Promise> { // If our quote token is WETH, we don't need to convert our gas use to be in terms @@ -73,11 +75,22 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasEstimate: BigNumber; gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; + initTicksCrossed: number; + gasUseL1: BigNumber; + gasCostL1: BigNumber; } => { - const { gasCostNativeCurrency, gasUse } = this.estimateGas( + const { + totalGasCostNativeCurrency, + totalInitializedTicksCrossed, + l1GasUsed, + totalGasUse, + l1Fee, + } = this.estimateGas( routeWithValidQuote, gasPriceWei, - chainId + chainId, + swapConfig, + gasData ); const token0 = usdPool.token0.address == nativeCurrency.address; @@ -87,13 +100,16 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { : usdPool.token1Price; const gasCostInTermsOfUSD: CurrencyAmount = nativeTokenPrice.quote( - gasCostNativeCurrency + totalGasCostNativeCurrency ) as CurrencyAmount; return { - gasEstimate: gasUse, - gasCostInToken: gasCostNativeCurrency, + gasEstimate: totalGasUse, + gasCostInToken: totalGasCostNativeCurrency, gasCostInUSD: gasCostInTermsOfUSD, + initTicksCrossed: totalInitializedTicksCrossed, + gasUseL1: l1GasUsed, + gasCostL1: l1Fee, }; }; @@ -126,11 +142,22 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasEstimate: BigNumber; gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; + initTicksCrossed: number; + gasUseL1: BigNumber; + gasCostL1: BigNumber; } => { - const { gasCostNativeCurrency, gasUse } = this.estimateGas( + const { + totalGasCostNativeCurrency, + totalInitializedTicksCrossed, + l1GasUsed, + totalGasUse, + l1Fee, + } = this.estimateGas( routeWithValidQuote, gasPriceWei, - chainId + chainId, + swapConfig, + gasData ); if (!nativePool) { @@ -138,9 +165,12 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { `Unable to find ${nativeCurrency.symbol} pool with the quote token, ${token.symbol} to produce gas adjusted costs. Route will not account for gas.` ); return { - gasEstimate: gasUse, + gasEstimate: totalGasUse, gasCostInToken: CurrencyAmount.fromRawAmount(token, 0), gasCostInUSD: CurrencyAmount.fromRawAmount(usdToken, 0), + initTicksCrossed: totalInitializedTicksCrossed, + gasUseL1: l1GasUsed, + gasCostL1: l1Fee, }; } @@ -155,14 +185,14 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { try { // native token is base currency gasCostInTermsOfQuoteToken = nativeTokenPrice.quote( - gasCostNativeCurrency + totalGasCostNativeCurrency ) as CurrencyAmount; } catch (err) { log.info( { nativeTokenPriceBase: nativeTokenPrice.baseCurrency, nativeTokenPriceQuote: nativeTokenPrice.quoteCurrency, - gasCostInEth: gasCostNativeCurrency.currency, + gasCostInEth: totalGasCostNativeCurrency.currency, }, 'Debug eth price token issue' ); @@ -180,14 +210,14 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { let gasCostInTermsOfUSD: CurrencyAmount; try { gasCostInTermsOfUSD = nativeTokenPriceUSDPool.quote( - gasCostNativeCurrency + totalGasCostNativeCurrency ) as CurrencyAmount; } catch (err) { log.info( { usdT1: usdPool.token0.symbol, usdT2: usdPool.token1.symbol, - gasCostInNativeToken: gasCostNativeCurrency.currency.symbol, + gasCostInNativeToken: totalGasCostNativeCurrency.currency.symbol, }, 'Failed to compute USD gas price' ); @@ -195,9 +225,12 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { } return { - gasEstimate: gasUse, + gasEstimate: totalGasUse, gasCostInToken: gasCostInTermsOfQuoteToken, gasCostInUSD: gasCostInTermsOfUSD!, + initTicksCrossed: totalInitializedTicksCrossed, + gasUseL1: l1GasUsed, + gasCostL1: l1Fee, }; }; @@ -206,10 +239,14 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { }; } + // NOTE end of buildGasModel() + private estimateGas( routeWithValidQuote: V3RouteWithValidQuote, gasPriceWei: BigNumber, - chainId: ChainId + chainId: ChainId, + swapConfig?: SwapOptions, + gasData?: OptimismGasData ) { const totalInitializedTicksCrossed = Math.max( 1, @@ -217,24 +254,52 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { ); const totalHops = BigNumber.from(routeWithValidQuote.route.pools.length); - const hopsGasUse = COST_PER_HOP.mul(totalHops); - const tickGasUse = COST_PER_INIT_TICK.mul(totalInitializedTicksCrossed); + const hopsGasUse = COST_PER_HOP(chainId).mul(totalHops); + const tickGasUse = COST_PER_INIT_TICK(chainId).mul( + totalInitializedTicksCrossed + ); const uninitializedTickGasUse = COST_PER_UNINIT_TICK.mul(0); - const gasUse = BASE_SWAP_COST.add(hopsGasUse) + let l1GasUsed = BigNumber.from(0); + let l1Fee = BigNumber.from(0); + if (chainId == ChainId.OPTIMISM || chainId == ChainId.OPTIMISTIC_KOVAN) { + // account for the L1 security fee + if (!swapConfig) { + log.info('Skipping l1 security fee calculation'); + } else { + [l1GasUsed, l1Fee] = this.calculateL1SecurityFee( + routeWithValidQuote, + swapConfig, + gasData! + ); + } + } + const baseGasUse = BASE_SWAP_COST(chainId) + .add(hopsGasUse) .add(tickGasUse) .add(uninitializedTickGasUse); - const totalGasCostWei = gasPriceWei.mul(gasUse); + const baseGasCostWei = gasPriceWei.mul(baseGasUse); + + const totalGasUse = l1GasUsed.add(baseGasUse); + + // total gas cost including l1 security fee if on optimism + const totalGasCostWei = l1Fee.add(baseGasCostWei); const wrappedCurrency = WRAPPED_NATIVE_CURRENCY[chainId]!; - const gasCostNativeCurrency = CurrencyAmount.fromRawAmount( + const totalGasCostNativeCurrency = CurrencyAmount.fromRawAmount( wrappedCurrency, totalGasCostWei.toString() ); - return { gasCostNativeCurrency, gasUse }; + return { + totalGasCostNativeCurrency, + totalInitializedTicksCrossed, + l1GasUsed, + l1Fee, + totalGasUse, + }; } private async getHighestLiquidityNativePool( @@ -341,4 +406,46 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { return maxPool; } + + private calculateL1SecurityFee( + route: V3RouteWithValidQuote, + swapConfig: SwapOptions, + gasData: OptimismGasData + ): [BigNumber, BigNumber] { + const { l1BaseFee, scalar, decimals, overhead } = gasData; + + // build trade for swap calldata + const trade = buildTrade( + route.amount.currency, + route.quote.currency, + route.tradeType, + [route] + ); + const data = buildSwapMethodParameters(trade, swapConfig).calldata; + const l1GasUsed = this.getL1GasUsed(data, overhead); + const l1Fee = l1GasUsed.mul(l1BaseFee); + const unscaled = l1Fee.mul(scalar); + // scaled = unscaled / (10 ** decimals) + const scaledConversion = BigNumber.from(10).pow(decimals); + const scaled = unscaled.div(scaledConversion); + return [l1GasUsed, scaled]; + } + + private getL1GasUsed(data: string, overhead: BigNumber): BigNumber { + // data is hex encoded + const dataArr: string[] = data.slice(2).match(/.{1,2}/g)!; + const numBytes = dataArr.length; + let count = 0; + for (let i = 0; i < numBytes; i += 1) { + const byte = parseInt(dataArr[i]!, 16); + if (byte == 0) { + count += 4; + } else { + count += 16; + } + } + const unsigned = overhead.add(count); + const signedConversion = 68 * 16; + return unsigned.add(signedConversion); + } } diff --git a/src/routers/router.ts b/src/routers/router.ts index c39b0f64f..8b1337e63 100644 --- a/src/routers/router.ts +++ b/src/routers/router.ts @@ -16,7 +16,6 @@ import { import { BigNumber } from 'ethers'; import { CurrencyAmount } from '../util/amounts'; import { RouteWithValidQuote } from './alpha-router'; - export class V3Route extends V3RouteRaw {} export class V2Route extends V2RouteRaw {} @@ -66,6 +65,9 @@ export type SwapRoute = { * The calldata to execute the swap. Only returned if swapConfig was provided when calling the router. */ methodParameters?: MethodParameters; + initTicksCrossed?: BigNumber; + l1GasCost?: BigNumber; + l1GasUse?: BigNumber; }; export type SwapToRatioRoute = SwapRoute & { @@ -118,6 +120,14 @@ export type SwapOptions = { ); }; +export type OptimismGasData = { + // l1GasPriceWei: BigNumber; + l1BaseFee: BigNumber; + scalar: BigNumber; + decimals: BigNumber; + overhead: BigNumber; +}; + // Config passed in to determine configurations on acceptable liquidity // to add to a position and max iterations on the route-finding algorithm export type SwapAndAddConfig = { diff --git a/src/util/addresses.ts b/src/util/addresses.ts index 9b05ff37a..543366199 100644 --- a/src/util/addresses.ts +++ b/src/util/addresses.ts @@ -4,6 +4,8 @@ import { ChainId } from './chains'; export const V3_CORE_FACTORY_ADDRESS = FACTORY_ADDRESS; export const QUOTER_V2_ADDRESS = '0x61fFE014bA17989E743c5F6cB21bF9697530B21e'; +export const OVM_GASPRICE_ADDRESS = + '0x420000000000000000000000000000000000000F'; export const TICK_LENS_ADDRESS = '0xbfd8137f7d1516D3ea5cA83523914859ec47F573'; export const NONFUNGIBLE_POSITION_MANAGER_ADDRESS = '0xC36442b4a4522E871399CD717aBDD847Ab11FE88'; diff --git a/src/util/methodParameters.ts b/src/util/methodParameters.ts new file mode 100644 index 000000000..75dcc89eb --- /dev/null +++ b/src/util/methodParameters.ts @@ -0,0 +1,173 @@ +import { Protocol, SwapRouter, Trade } from '@uniswap/router-sdk'; +import { Currency, TradeType } from '@uniswap/sdk-core'; +import { Route as V2RouteRaw } from '@uniswap/v2-sdk'; +import { MethodParameters, Route as V3RouteRaw } from '@uniswap/v3-sdk'; +import _ from 'lodash'; +import { + CurrencyAmount, + RouteWithValidQuote, + SwapOptions, + V2RouteWithValidQuote, + V3RouteWithValidQuote, +} from '..'; +export function buildTrade( + tokenInCurrency: Currency, + tokenOutCurrency: Currency, + tradeType: TTradeType, + routeAmounts: RouteWithValidQuote[] +): Trade { + const [v3RouteAmounts, v2RouteAmounts] = _.partition( + routeAmounts, + (routeAmount) => routeAmount.protocol == Protocol.V3 + ); + + const v3Routes = _.map< + V3RouteWithValidQuote, + { + routev3: V3RouteRaw; + inputAmount: CurrencyAmount; + outputAmount: CurrencyAmount; + } + >( + v3RouteAmounts as V3RouteWithValidQuote[], + (routeAmount: V3RouteWithValidQuote) => { + const { route, amount, quote } = routeAmount; + + // The route, amount and quote are all in terms of wrapped tokens. + // When constructing the Trade object the inputAmount/outputAmount must + // use native currencies if specified by the user. This is so that the Trade knows to wrap/unwrap. + if (tradeType == TradeType.EXACT_INPUT) { + const amountCurrency = CurrencyAmount.fromFractionalAmount( + tokenInCurrency, + amount.numerator, + amount.denominator + ); + const quoteCurrency = CurrencyAmount.fromFractionalAmount( + tokenOutCurrency, + quote.numerator, + quote.denominator + ); + + const routeRaw = new V3RouteRaw( + route.pools, + amountCurrency.currency, + quoteCurrency.currency + ); + + return { + routev3: routeRaw, + inputAmount: amountCurrency, + outputAmount: quoteCurrency, + }; + } else { + const quoteCurrency = CurrencyAmount.fromFractionalAmount( + tokenInCurrency, + quote.numerator, + quote.denominator + ); + + const amountCurrency = CurrencyAmount.fromFractionalAmount( + tokenOutCurrency, + amount.numerator, + amount.denominator + ); + + const routeCurrency = new V3RouteRaw( + route.pools, + quoteCurrency.currency, + amountCurrency.currency + ); + + return { + routev3: routeCurrency, + inputAmount: quoteCurrency, + outputAmount: amountCurrency, + }; + } + } + ); + + const v2Routes = _.map< + V2RouteWithValidQuote, + { + routev2: V2RouteRaw; + inputAmount: CurrencyAmount; + outputAmount: CurrencyAmount; + } + >( + v2RouteAmounts as V2RouteWithValidQuote[], + (routeAmount: V2RouteWithValidQuote) => { + const { route, amount, quote } = routeAmount; + + // The route, amount and quote are all in terms of wrapped tokens. + // When constructing the Trade object the inputAmount/outputAmount must + // use native currencies if specified by the user. This is so that the Trade knows to wrap/unwrap. + if (tradeType == TradeType.EXACT_INPUT) { + const amountCurrency = CurrencyAmount.fromFractionalAmount( + tokenInCurrency, + amount.numerator, + amount.denominator + ); + const quoteCurrency = CurrencyAmount.fromFractionalAmount( + tokenOutCurrency, + quote.numerator, + quote.denominator + ); + + const routeV2SDK = new V2RouteRaw( + route.pairs, + amountCurrency.currency, + quoteCurrency.currency + ); + + return { + routev2: routeV2SDK, + inputAmount: amountCurrency, + outputAmount: quoteCurrency, + }; + } else { + const quoteCurrency = CurrencyAmount.fromFractionalAmount( + tokenInCurrency, + quote.numerator, + quote.denominator + ); + + const amountCurrency = CurrencyAmount.fromFractionalAmount( + tokenOutCurrency, + amount.numerator, + amount.denominator + ); + + const routeV2SDK = new V2RouteRaw( + route.pairs, + quoteCurrency.currency, + amountCurrency.currency + ); + + return { + routev2: routeV2SDK, + inputAmount: quoteCurrency, + outputAmount: amountCurrency, + }; + } + } + ); + + const trade = new Trade({ v2Routes, v3Routes, tradeType }); + + return trade; +} + +export function buildSwapMethodParameters( + trade: Trade, + swapConfig: SwapOptions +): MethodParameters { + const { recipient, slippageTolerance, deadline, inputTokenPermit } = + swapConfig; + return SwapRouter.swapCallParameters(trade, { + recipient, + slippageTolerance, + deadlineOrPreviousBlockhash: deadline, + inputTokenPermit, + }); +} From 3ae60e358ca3f2c9e7041e270ae0b4c4476e5082 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Fri, 21 Jan 2022 02:01:14 +0000 Subject: [PATCH 02/12] Fix code style issues with Prettier --- src/abis/gasPriceOracle.json | 594 +++++++++++++++++------------------ 1 file changed, 297 insertions(+), 297 deletions(-) diff --git a/src/abis/gasPriceOracle.json b/src/abis/gasPriceOracle.json index 1a81647c4..735c1b695 100644 --- a/src/abis/gasPriceOracle.json +++ b/src/abis/gasPriceOracle.json @@ -1,298 +1,298 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "_owner", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "DecimalsUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "GasPriceUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "L1BaseFeeUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "OverheadUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "ScalarUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "gasPrice", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "getL1Fee", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "getL1GasUsed", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1BaseFee", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "overhead", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "scalar", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_decimals", - "type": "uint256" - } - ], - "name": "setDecimals", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_gasPrice", - "type": "uint256" - } - ], - "name": "setGasPrice", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_baseFee", - "type": "uint256" - } - ], - "name": "setL1BaseFee", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_overhead", - "type": "uint256" - } - ], - "name": "setOverhead", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_scalar", - "type": "uint256" - } - ], - "name": "setScalar", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ] \ No newline at end of file + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "DecimalsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "GasPriceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "L1BaseFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "OverheadUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "ScalarUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "getL1Fee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "getL1GasUsed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1BaseFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "overhead", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "scalar", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_decimals", + "type": "uint256" + } + ], + "name": "setDecimals", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasPrice", + "type": "uint256" + } + ], + "name": "setGasPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_baseFee", + "type": "uint256" + } + ], + "name": "setL1BaseFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_overhead", + "type": "uint256" + } + ], + "name": "setOverhead", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_scalar", + "type": "uint256" + } + ], + "name": "setScalar", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] From cc3a85f5378993302157e51230b9a54f20471233 Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Tue, 25 Jan 2022 17:00:18 -0500 Subject: [PATCH 03/12] fix: ensure compatibility with v2 --- src/providers/v3/gas-data-provider.ts | 8 +-- src/routers/alpha-router/alpha-router.ts | 26 +++++++--- .../entities/route-with-valid-quote.ts | 14 ++---- .../alpha-router/functions/best-swap-route.ts | 50 ++++++++++--------- .../alpha-router/gas-models/gas-model.ts | 2 +- .../gas-models/v2/v2-heuristic-gas-model.ts | 3 -- .../gas-models/v3/v3-heuristic-gas-model.ts | 9 ++-- src/routers/legacy-router/legacy-router.ts | 2 + .../routers/alpha-router/alpha-router.test.ts | 1 + .../functions/best-swap-route.test.ts | 3 ++ 10 files changed, 62 insertions(+), 56 deletions(-) diff --git a/src/providers/v3/gas-data-provider.ts b/src/providers/v3/gas-data-provider.ts index 69630a4d6..387d6e414 100644 --- a/src/providers/v3/gas-data-provider.ts +++ b/src/providers/v3/gas-data-provider.ts @@ -1,7 +1,7 @@ import { BigNumber, providers } from 'ethers'; import { OptimismGasData } from '../../routers'; import { GasPriceOracle, GasPriceOracle__factory } from '../../types/other'; -import { ChainId, log, OVM_GASPRICE_ADDRESS } from '../../util'; +import { ChainId, OVM_GASPRICE_ADDRESS } from '../../util'; export interface IGasDataProvider { getGasData(): Promise; @@ -40,12 +40,6 @@ export class GasDataProvider implements IGasDataProvider { overhead, }; - log.debug('DATA FIELD'); - log.debug(data.decimals); - log.debug(data.l1BaseFee); - log.debug(data.overhead); - log.debug(data.scalar); - return data; } } diff --git a/src/routers/alpha-router/alpha-router.ts b/src/routers/alpha-router/alpha-router.ts index c80f6af1c..79e9ef850 100644 --- a/src/routers/alpha-router/alpha-router.ts +++ b/src/routers/alpha-router/alpha-router.ts @@ -178,6 +178,11 @@ export type AlphaRouterParams = { * LP position tokens. */ swapRouterProvider?: ISwapRouterProvider; + + /** + * Calls the optimism gas oracle contract to fetch constants for calculating the l1 security fee. + */ + optimismGasDataProvider?: IGasDataProvider; }; /** @@ -312,6 +317,7 @@ export class AlphaRouter v3GasModelFactory, v2GasModelFactory, swapRouterProvider, + optimismGasDataProvider, }: AlphaRouterParams) { this.chainId = chainId; this.provider = provider; @@ -500,11 +506,9 @@ export class AlphaRouter this.swapRouterProvider = swapRouterProvider ?? new SwapRouterProvider(this.multicall2Provider); - if (chainId == ChainId.OPTIMISM || ChainId.OPTIMISTIC_KOVAN) { - this.optimismGasDataProvider = new GasDataProvider( - chainId, - this.provider - ); + if (chainId == ChainId.OPTIMISM || chainId == ChainId.OPTIMISTIC_KOVAN) { + this.optimismGasDataProvider = + optimismGasDataProvider ?? new GasDataProvider(chainId, this.provider); } } @@ -957,9 +961,15 @@ export class AlphaRouter }); // only make contract calls once - const gasData = this.optimismGasDataProvider - ? await this.optimismGasDataProvider.getGasData() - : undefined; + let gasData; + if ( + this.chainId == ChainId.OPTIMISM || + this.chainId == ChainId.OPTIMISTIC_KOVAN + ) { + gasData = this.optimismGasDataProvider + ? await this.optimismGasDataProvider.getGasData() + : undefined; + } const gasModel = await this.v3GasModelFactory.buildGasModel( this.chainId, diff --git a/src/routers/alpha-router/entities/route-with-valid-quote.ts b/src/routers/alpha-router/entities/route-with-valid-quote.ts index 2a82203d0..0c20e084e 100644 --- a/src/routers/alpha-router/entities/route-with-valid-quote.ts +++ b/src/routers/alpha-router/entities/route-with-valid-quote.ts @@ -79,9 +79,9 @@ export class V2RouteWithValidQuote implements IV2RouteWithValidQuote { public tradeType: TradeType; public poolAddresses: string[]; public tokenPath: Token[]; - public initTicksCrossed: number; - public gasUseL1: BigNumber; - public gasCostL1: BigNumber; + public initTicksCrossed?: BigNumber; + public gasUseL1?: BigNumber; + public gasCostL1?: BigNumber; public toString(): string { return `${this.percent.toFixed( @@ -110,16 +110,12 @@ export class V2RouteWithValidQuote implements IV2RouteWithValidQuote { this.quoteToken = quoteToken; this.tradeType = tradeType; - const { gasEstimate, gasCostInToken, gasCostInUSD, initTicksCrossed } = + const { gasEstimate, gasCostInToken, gasCostInUSD } = this.gasModel.estimateGasCost(this); this.gasCostInToken = gasCostInToken; this.gasCostInUSD = gasCostInUSD; this.gasEstimate = gasEstimate; - this.initTicksCrossed = initTicksCrossed!; - // these costs are from optimism which is not deployed on v2 so we ignore - this.gasUseL1 = BigNumber.from(0); - this.gasCostL1 = BigNumber.from(0); // If its exact out, we need to request *more* of the input token to account for the gas. if (this.tradeType == TradeType.EXACT_INPUT) { @@ -180,7 +176,7 @@ export class V3RouteWithValidQuote implements IV3RouteWithValidQuote { public tradeType: TradeType; public poolAddresses: string[]; public tokenPath: Token[]; - public initTicksCrossed: number; + public initTicksCrossed: BigNumber; public gasUseL1: BigNumber; public gasCostL1: BigNumber; diff --git a/src/routers/alpha-router/functions/best-swap-route.ts b/src/routers/alpha-router/functions/best-swap-route.ts index 05e581d5c..09626e0fc 100644 --- a/src/routers/alpha-router/functions/best-swap-route.ts +++ b/src/routers/alpha-router/functions/best-swap-route.ts @@ -26,9 +26,9 @@ export function getBestSwapRoute( estimatedGasUsedUSD: CurrencyAmount; estimatedGasUsedQuoteToken: CurrencyAmount; routes: RouteWithValidQuote[]; - initTicksCrossed: BigNumber; - l1GasCost: BigNumber; - l1GasUse: BigNumber; + initTicksCrossed?: BigNumber; + l1GasCost?: BigNumber; + l1GasUse?: BigNumber; } | null { const now = Date.now(); @@ -119,9 +119,9 @@ export function getBestSwapRouteBy( estimatedGasUsedUSD: CurrencyAmount; estimatedGasUsedQuoteToken: CurrencyAmount; routes: RouteWithValidQuote[]; - initTicksCrossed: BigNumber; - l1GasUse: BigNumber; - l1GasCost: BigNumber; + initTicksCrossed?: BigNumber; + l1GasUse?: BigNumber; + l1GasCost?: BigNumber; } | undefined { // Build a map of percentage to sorted list of quotes, with the biggest quote being first in the list. @@ -439,23 +439,28 @@ export function getBestSwapRouteBy( _.map(bestSwap, (routeWithValidQuote) => routeWithValidQuote.quote) ); - const totalInitTicksCrossed = _.map( - bestSwap, - (routeWithValidQuote) => routeWithValidQuote.initTicksCrossed - ).reduce( - (sum, routeWithValidQuote) => sum.add(routeWithValidQuote), - BigNumber.from(0) - ); - - const totalL1GasUsed = _.map(bestSwap, (route) => route.gasUseL1).reduce( - (sum, route) => sum.add(route), - BigNumber.from(0) - ); + let totalL1GasUsed = BigNumber.from(0); + let totalL1GasCost = BigNumber.from(0); + let totalInitTicksCrossed = BigNumber.from(0); + if (chainId == ChainId.OPTIMISM || chainId == ChainId.OPTIMISTIC_KOVAN) { + // only need these values for optimism security fee l1 + log.info('Calculating total tick and gas costs'); + totalL1GasUsed = _.map(bestSwap, (route) => route.gasUseL1!).reduce( + (sum, route) => sum.add(route), + BigNumber.from(0) + ); + log.debug(totalL1GasUsed); + totalL1GasCost = _.map(bestSwap, (route) => route.gasCostL1!).reduce( + (sum, route) => sum.add(route), + BigNumber.from(0) + ); + log.debug(totalL1GasCost); - const totalL1GasCost = _.map(bestSwap, (route) => route.gasCostL1).reduce( - (sum, route) => sum.add(route), - BigNumber.from(0) - ); + totalInitTicksCrossed = _.map( + bestSwap, + (routeWithValidQuote) => routeWithValidQuote.initTicksCrossed! + ).reduce((sum, ticksCrossed) => sum.add(ticksCrossed), BigNumber.from(0)); + } const routeWithQuotes = bestSwap.sort((routeAmountA, routeAmountB) => routeAmountB.amount.greaterThan(routeAmountA.amount) ? 1 : -1 @@ -466,7 +471,6 @@ export function getBestSwapRouteBy( Date.now() - postSplitNow, MetricLoggerUnit.Milliseconds ); - return { quote, quoteGasAdjusted, diff --git a/src/routers/alpha-router/gas-models/gas-model.ts b/src/routers/alpha-router/gas-models/gas-model.ts index ad726c4da..b4dce8091 100644 --- a/src/routers/alpha-router/gas-models/gas-model.ts +++ b/src/routers/alpha-router/gas-models/gas-model.ts @@ -80,7 +80,7 @@ export type IGasModel = { gasEstimate: BigNumber; gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; - initTicksCrossed?: number; + initTicksCrossed?: BigNumber; gasUseL1?: BigNumber; gasCostL1?: BigNumber; }; diff --git a/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts b/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts index 3d6837908..8aabe0575 100644 --- a/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts +++ b/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts @@ -75,7 +75,6 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { gasEstimate: gasUse, gasCostInToken: gasCostInEth, gasCostInUSD: gasCostInTermsOfUSD, - initTicksCrossed: 0, }; }, }; @@ -115,7 +114,6 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { gasEstimate: gasUse, gasCostInToken: CurrencyAmount.fromRawAmount(token, 0), gasCostInUSD: CurrencyAmount.fromRawAmount(usdToken, 0), - initTicksCrossed: 0, }; } @@ -171,7 +169,6 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { gasEstimate: gasUse, gasCostInToken: gasCostInTermsOfQuoteToken, gasCostInUSD: gasCostInTermsOfUSD!, - initTicksCrossed: 0, }; }, }; diff --git a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts index 7a1a997dc..bb1155dc1 100644 --- a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts +++ b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts @@ -75,7 +75,7 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasEstimate: BigNumber; gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; - initTicksCrossed: number; + initTicksCrossed: BigNumber; gasUseL1: BigNumber; gasCostL1: BigNumber; } => { @@ -142,7 +142,7 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasEstimate: BigNumber; gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; - initTicksCrossed: number; + initTicksCrossed: BigNumber; gasUseL1: BigNumber; gasCostL1: BigNumber; } => { @@ -248,9 +248,8 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { swapConfig?: SwapOptions, gasData?: OptimismGasData ) { - const totalInitializedTicksCrossed = Math.max( - 1, - _.sum(routeWithValidQuote.initializedTicksCrossedList) + const totalInitializedTicksCrossed = BigNumber.from( + Math.max(1, _.sum(routeWithValidQuote.initializedTicksCrossedList)) ); const totalHops = BigNumber.from(routeWithValidQuote.route.pools.length); diff --git a/src/routers/legacy-router/legacy-router.ts b/src/routers/legacy-router/legacy-router.ts index 3e6bb10d5..f3796dfcd 100644 --- a/src/routers/legacy-router/legacy-router.ts +++ b/src/routers/legacy-router/legacy-router.ts @@ -141,6 +141,7 @@ export class LegacyRouter implements IRouter { ? this.buildMethodParameters(trade, swapConfig) : undefined, blockNumber: BigNumber.from(0), + initTicksCrossed: BigNumber.from(0), }; } @@ -193,6 +194,7 @@ export class LegacyRouter implements IRouter { ? this.buildMethodParameters(trade, swapConfig) : undefined, blockNumber: BigNumber.from(0), + initTicksCrossed: BigNumber.from(0), }; } diff --git a/test/unit/routers/alpha-router/alpha-router.test.ts b/test/unit/routers/alpha-router/alpha-router.test.ts index b980ac89c..f3f4da848 100644 --- a/test/unit/routers/alpha-router/alpha-router.test.ts +++ b/test/unit/routers/alpha-router/alpha-router.test.ts @@ -42,6 +42,7 @@ import { } from '../../../../src'; import { ProviderConfig } from '../../../../src/providers/provider'; import { V2PoolProvider } from '../../../../src/providers/v2/pool-provider'; +// import { GasDataProvider } from '../../../../src/providers/v3/gas-data-provider'; import { V2HeuristicGasModelFactory } from '../../../../src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model'; import { buildMockTokenAccessor, diff --git a/test/unit/routers/alpha-router/functions/best-swap-route.test.ts b/test/unit/routers/alpha-router/functions/best-swap-route.test.ts index 7286669ae..e3260c637 100644 --- a/test/unit/routers/alpha-router/functions/best-swap-route.test.ts +++ b/test/unit/routers/alpha-router/functions/best-swap-route.test.ts @@ -110,6 +110,7 @@ describe('get best swap route', () => { gasEstimate: BigNumber.from(10000), gasCostInToken: CurrencyAmount.fromRawAmount(r.quoteToken, 0), gasCostInUSD: CurrencyAmount.fromRawAmount(USDC, 0), + initTicksCrossed: BigNumber.from(1), }; }); @@ -686,6 +687,7 @@ describe('get best swap route', () => { USDC, JSBI.multiply(JSBI.BigInt(10), JSBI.BigInt(hops)) ), + initTicksCrossed: BigNumber.from(1), }; }); @@ -755,6 +757,7 @@ describe('get best swap route', () => { DAI_MAINNET, JSBI.multiply(JSBI.BigInt(10), JSBI.BigInt(hops)) ), + initTicksCrossed: BigNumber.from(1), }; }); From b820e78f23782983d336056dfeeac5352cedfee9 Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Tue, 25 Jan 2022 17:42:10 -0500 Subject: [PATCH 04/12] fix: default to v3 when no protocol specified --- src/routers/alpha-router/alpha-router.ts | 17 +++++++++++++---- src/util/chains.ts | 8 ++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/routers/alpha-router/alpha-router.ts b/src/routers/alpha-router/alpha-router.ts index 79e9ef850..2355051fe 100644 --- a/src/routers/alpha-router/alpha-router.ts +++ b/src/routers/alpha-router/alpha-router.ts @@ -64,7 +64,12 @@ import { } from '../../providers/v3/quote-provider'; import { IV3SubgraphProvider } from '../../providers/v3/subgraph-provider'; import { CurrencyAmount } from '../../util/amounts'; -import { ChainId, ID_TO_CHAIN_ID, ID_TO_NETWORK_NAME } from '../../util/chains'; +import { + ChainId, + ID_TO_CHAIN_ID, + ID_TO_NETWORK_NAME, + V2_SUPPORTED, +} from '../../util/chains'; import { log } from '../../util/log'; import { buildSwapMethodParameters, @@ -746,8 +751,9 @@ export class AlphaRouter const protocolsSet = new Set(protocols ?? []); if ( - protocolsSet.size == 0 || - (protocolsSet.has(Protocol.V2) && protocolsSet.has(Protocol.V3)) + (protocolsSet.size == 0 || + (protocolsSet.has(Protocol.V2) && protocolsSet.has(Protocol.V3))) && + V2_SUPPORTED.includes(this.chainId) ) { log.info({ protocols, tradeType }, 'Routing across all protocols'); quotePromises.push( @@ -775,7 +781,10 @@ export class AlphaRouter ) ); } else { - if (protocolsSet.has(Protocol.V3)) { + if ( + protocolsSet.has(Protocol.V3) || + (protocolsSet.size == 0 && !V2_SUPPORTED.includes(this.chainId)) + ) { log.info({ protocols, swapType: tradeType }, 'Routing across V3'); quotePromises.push( this.getV3Quotes( diff --git a/src/util/chains.ts b/src/util/chains.ts index c5c28a5b8..030556d22 100644 --- a/src/util/chains.ts +++ b/src/util/chains.ts @@ -13,6 +13,14 @@ export enum ChainId { POLYGON_MUMBAI = 80001, } +export const V2_SUPPORTED = [ + ChainId.MAINNET, + ChainId.KOVAN, + ChainId.GÖRLI, + ChainId.RINKEBY, + ChainId.ROPSTEN, +]; + export const ID_TO_CHAIN_ID = (id: number): ChainId => { switch (id) { case 1: From 99babc8d29d206d449bb54376f5db0cf7c35985a Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Wed, 26 Jan 2022 12:22:46 -0500 Subject: [PATCH 05/12] update arbgas numbers and remove config changes --- cli/base-command.ts | 4 ++-- src/routers/alpha-router/config.ts | 12 ++++++------ .../alpha-router/functions/best-swap-route.ts | 11 +++++++---- src/routers/alpha-router/gas-models/v3/gas-costs.ts | 4 ++-- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/cli/base-command.ts b/cli/base-command.ts index 0cea10c2b..17e17d40d 100644 --- a/cli/base-command.ts +++ b/cli/base-command.ts @@ -70,7 +70,7 @@ export abstract class BaseCommand extends Command { }), maxSwapsPerPath: flags.integer({ required: false, - default: 1, + default: 3, }), minSplits: flags.integer({ required: false, @@ -78,7 +78,7 @@ export abstract class BaseCommand extends Command { }), maxSplits: flags.integer({ required: false, - default: 1, + default: 3, }), distributionPercent: flags.integer({ required: false, diff --git a/src/routers/alpha-router/config.ts b/src/routers/alpha-router/config.ts index d18ce5b06..d01d3c6ee 100644 --- a/src/routers/alpha-router/config.ts +++ b/src/routers/alpha-router/config.ts @@ -25,9 +25,9 @@ export const DEFAULT_ROUTING_CONFIG_BY_CHAIN = ( topNWithEachBaseToken: 3, topNWithBaseToken: 3, }, - maxSwapsPerPath: 1, + maxSwapsPerPath: 3, minSplits: 1, - maxSplits: 1, + maxSplits: 7, distributionPercent: 10, forceCrossProtocol: false, }; @@ -53,9 +53,9 @@ export const DEFAULT_ROUTING_CONFIG_BY_CHAIN = ( topNWithEachBaseToken: 3, topNWithBaseToken: 2, }, - maxSwapsPerPath: 1, + maxSwapsPerPath: 2, minSplits: 1, - maxSplits: 1, + maxSplits: 7, distributionPercent: 25, forceCrossProtocol: false, }; @@ -77,9 +77,9 @@ export const DEFAULT_ROUTING_CONFIG_BY_CHAIN = ( topNWithEachBaseToken: 3, topNWithBaseToken: 5, }, - maxSwapsPerPath: 1, + maxSwapsPerPath: 3, minSplits: 1, - maxSplits: 1, + maxSplits: 7, distributionPercent: 5, forceCrossProtocol: false, }; diff --git a/src/routers/alpha-router/functions/best-swap-route.ts b/src/routers/alpha-router/functions/best-swap-route.ts index 09626e0fc..1b24eb274 100644 --- a/src/routers/alpha-router/functions/best-swap-route.ts +++ b/src/routers/alpha-router/functions/best-swap-route.ts @@ -449,18 +449,21 @@ export function getBestSwapRouteBy( (sum, route) => sum.add(route), BigNumber.from(0) ); - log.debug(totalL1GasUsed); totalL1GasCost = _.map(bestSwap, (route) => route.gasCostL1!).reduce( (sum, route) => sum.add(route), BigNumber.from(0) ); - log.debug(totalL1GasCost); - + } + // only need tick data for estimating gas on these chains + if ( + chainId == ChainId.OPTIMISM || chainId == ChainId.OPTIMISTIC_KOVAN || + chainId == ChainId.ARBITRUM_ONE || + chainId == ChainId.ARBITRUM_RINKEBY + ) { totalInitTicksCrossed = _.map( bestSwap, (routeWithValidQuote) => routeWithValidQuote.initTicksCrossed! ).reduce((sum, ticksCrossed) => sum.add(ticksCrossed), BigNumber.from(0)); - } const routeWithQuotes = bestSwap.sort((routeAmountA, routeAmountB) => routeAmountB.amount.greaterThan(routeAmountA.amount) ? 1 : -1 diff --git a/src/routers/alpha-router/gas-models/v3/gas-costs.ts b/src/routers/alpha-router/gas-models/v3/gas-costs.ts index 20b35454b..d112199e2 100644 --- a/src/routers/alpha-router/gas-models/v3/gas-costs.ts +++ b/src/routers/alpha-router/gas-models/v3/gas-costs.ts @@ -14,7 +14,7 @@ export const BASE_SWAP_COST = (id: ChainId): BigNumber => { return BigNumber.from(2000); case ChainId.ARBITRUM_ONE: case ChainId.ARBITRUM_RINKEBY: - return BigNumber.from(2000); + return BigNumber.from(700000); case ChainId.POLYGON: case ChainId.POLYGON_MUMBAI: return BigNumber.from(2000); @@ -33,7 +33,7 @@ export const COST_PER_INIT_TICK = (id: ChainId): BigNumber => { return BigNumber.from(31000); case ChainId.ARBITRUM_ONE: case ChainId.ARBITRUM_RINKEBY: - return BigNumber.from(31000); + return BigNumber.from(54000); case ChainId.POLYGON: case ChainId.POLYGON_MUMBAI: return BigNumber.from(31000); From 1e0fd615764d92342c716a7094f8293fd96a4a60 Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Wed, 26 Jan 2022 12:43:28 -0500 Subject: [PATCH 06/12] test cleanup and fix comile issue --- src/routers/alpha-router/functions/best-swap-route.ts | 4 +++- .../routers/alpha-router/functions/best-swap-route.test.ts | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/routers/alpha-router/functions/best-swap-route.ts b/src/routers/alpha-router/functions/best-swap-route.ts index 1b24eb274..2fea783d5 100644 --- a/src/routers/alpha-router/functions/best-swap-route.ts +++ b/src/routers/alpha-router/functions/best-swap-route.ts @@ -456,7 +456,8 @@ export function getBestSwapRouteBy( } // only need tick data for estimating gas on these chains if ( - chainId == ChainId.OPTIMISM || chainId == ChainId.OPTIMISTIC_KOVAN || + chainId == ChainId.OPTIMISM || + chainId == ChainId.OPTIMISTIC_KOVAN || chainId == ChainId.ARBITRUM_ONE || chainId == ChainId.ARBITRUM_RINKEBY ) { @@ -464,6 +465,7 @@ export function getBestSwapRouteBy( bestSwap, (routeWithValidQuote) => routeWithValidQuote.initTicksCrossed! ).reduce((sum, ticksCrossed) => sum.add(ticksCrossed), BigNumber.from(0)); + } const routeWithQuotes = bestSwap.sort((routeAmountA, routeAmountB) => routeAmountB.amount.greaterThan(routeAmountA.amount) ? 1 : -1 diff --git a/test/unit/routers/alpha-router/functions/best-swap-route.test.ts b/test/unit/routers/alpha-router/functions/best-swap-route.test.ts index e3260c637..7286669ae 100644 --- a/test/unit/routers/alpha-router/functions/best-swap-route.test.ts +++ b/test/unit/routers/alpha-router/functions/best-swap-route.test.ts @@ -110,7 +110,6 @@ describe('get best swap route', () => { gasEstimate: BigNumber.from(10000), gasCostInToken: CurrencyAmount.fromRawAmount(r.quoteToken, 0), gasCostInUSD: CurrencyAmount.fromRawAmount(USDC, 0), - initTicksCrossed: BigNumber.from(1), }; }); @@ -687,7 +686,6 @@ describe('get best swap route', () => { USDC, JSBI.multiply(JSBI.BigInt(10), JSBI.BigInt(hops)) ), - initTicksCrossed: BigNumber.from(1), }; }); @@ -757,7 +755,6 @@ describe('get best swap route', () => { DAI_MAINNET, JSBI.multiply(JSBI.BigInt(10), JSBI.BigInt(hops)) ), - initTicksCrossed: BigNumber.from(1), }; }); From 2b671b0257bbe2d9cac01cd8033df5223f708233 Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Wed, 26 Jan 2022 13:37:50 -0500 Subject: [PATCH 07/12] cleanup and comments --- cli/commands/quote.ts | 4 ++-- src/providers/v3/gas-data-provider.ts | 11 +++++++++++ src/routers/legacy-router/legacy-router.ts | 2 -- src/routers/router.ts | 1 - test/unit/routers/alpha-router/alpha-router.test.ts | 1 - 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cli/commands/quote.ts b/cli/commands/quote.ts index 6f7548536..e168b4040 100644 --- a/cli/commands/quote.ts +++ b/cli/commands/quote.ts @@ -109,9 +109,9 @@ export class Quote extends BaseCommand { TradeType.EXACT_INPUT, recipient ? { - deadline: 10000000000, + deadline: 100, recipient, - slippageTolerance: new Percent(200000, 10_000), + slippageTolerance: new Percent(5, 10_000), } : undefined, { diff --git a/src/providers/v3/gas-data-provider.ts b/src/providers/v3/gas-data-provider.ts index 387d6e414..16805c577 100644 --- a/src/providers/v3/gas-data-provider.ts +++ b/src/providers/v3/gas-data-provider.ts @@ -3,7 +3,18 @@ import { OptimismGasData } from '../../routers'; import { GasPriceOracle, GasPriceOracle__factory } from '../../types/other'; import { ChainId, OVM_GASPRICE_ADDRESS } from '../../util'; +/** + * Provider or getting Optimism gas constants. + * + * @export + * @interface IGasDataProvider + */ export interface IGasDataProvider { + /** + * Gets the data constants needed to calculate the l1 security fee on Optimism. + * @returns An OptimismGasData object that includes the l1BaseFee, + * scalar, decimals, and overhead values. + */ getGasData(): Promise; } diff --git a/src/routers/legacy-router/legacy-router.ts b/src/routers/legacy-router/legacy-router.ts index f3796dfcd..3e6bb10d5 100644 --- a/src/routers/legacy-router/legacy-router.ts +++ b/src/routers/legacy-router/legacy-router.ts @@ -141,7 +141,6 @@ export class LegacyRouter implements IRouter { ? this.buildMethodParameters(trade, swapConfig) : undefined, blockNumber: BigNumber.from(0), - initTicksCrossed: BigNumber.from(0), }; } @@ -194,7 +193,6 @@ export class LegacyRouter implements IRouter { ? this.buildMethodParameters(trade, swapConfig) : undefined, blockNumber: BigNumber.from(0), - initTicksCrossed: BigNumber.from(0), }; } diff --git a/src/routers/router.ts b/src/routers/router.ts index 8b1337e63..0b289f8cf 100644 --- a/src/routers/router.ts +++ b/src/routers/router.ts @@ -121,7 +121,6 @@ export type SwapOptions = { }; export type OptimismGasData = { - // l1GasPriceWei: BigNumber; l1BaseFee: BigNumber; scalar: BigNumber; decimals: BigNumber; diff --git a/test/unit/routers/alpha-router/alpha-router.test.ts b/test/unit/routers/alpha-router/alpha-router.test.ts index f3f4da848..b980ac89c 100644 --- a/test/unit/routers/alpha-router/alpha-router.test.ts +++ b/test/unit/routers/alpha-router/alpha-router.test.ts @@ -42,7 +42,6 @@ import { } from '../../../../src'; import { ProviderConfig } from '../../../../src/providers/provider'; import { V2PoolProvider } from '../../../../src/providers/v2/pool-provider'; -// import { GasDataProvider } from '../../../../src/providers/v3/gas-data-provider'; import { V2HeuristicGasModelFactory } from '../../../../src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model'; import { buildMockTokenAccessor, From 2f6af8b369c50bd0164830211a525fac0a316f7d Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Wed, 26 Jan 2022 13:48:04 -0500 Subject: [PATCH 08/12] remove comments --- cli/commands/quote.ts | 8 ++++---- src/providers/v3/gas-data-provider.ts | 2 +- .../alpha-router/gas-models/v3/v3-heuristic-gas-model.ts | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/cli/commands/quote.ts b/cli/commands/quote.ts index e168b4040..58cd1e9e1 100644 --- a/cli/commands/quote.ts +++ b/cli/commands/quote.ts @@ -2,7 +2,7 @@ import { flags } from '@oclif/command'; import { Protocol } from '@uniswap/router-sdk'; import { Currency, Percent, TradeType } from '@uniswap/sdk-core'; import dotenv from 'dotenv'; -import { ethers } from 'ethers'; +import { BigNumber, ethers } from 'ethers'; import _ from 'lodash'; import { ID_TO_CHAIN_ID, @@ -201,9 +201,9 @@ export class Quote extends BaseCommand { blockNumber, estimatedGasUsed, gasPriceWei, - initTicksCrossed!, - l1GasUse!, - l1GasCost! + initTicksCrossed ?? BigNumber.from(0), + l1GasUse ?? BigNumber.from(0), + l1GasCost ?? BigNumber.from(0)! ); } } diff --git a/src/providers/v3/gas-data-provider.ts b/src/providers/v3/gas-data-provider.ts index 16805c577..f5ae0580d 100644 --- a/src/providers/v3/gas-data-provider.ts +++ b/src/providers/v3/gas-data-provider.ts @@ -4,7 +4,7 @@ import { GasPriceOracle, GasPriceOracle__factory } from '../../types/other'; import { ChainId, OVM_GASPRICE_ADDRESS } from '../../util'; /** - * Provider or getting Optimism gas constants. + * Provider for getting Optimism gas constants. * * @export * @interface IGasDataProvider diff --git a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts index bb1155dc1..fc68bb655 100644 --- a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts +++ b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts @@ -239,8 +239,6 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { }; } - // NOTE end of buildGasModel() - private estimateGas( routeWithValidQuote: V3RouteWithValidQuote, gasPriceWei: BigNumber, From b7b9fbbb39b1dd918d639a2666fcc60733122cc9 Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Mon, 31 Jan 2022 14:58:54 -0500 Subject: [PATCH 09/12] add multicall function and change provider name --- src/providers/multicall-provider.ts | 25 ++++++ src/providers/multicall-uniswap-provider.ts | 98 +++++++++++++++++++++ src/providers/v3/gas-data-provider.ts | 73 +++++++++------ src/routers/alpha-router/alpha-router.ts | 11 +-- 4 files changed, 175 insertions(+), 32 deletions(-) diff --git a/src/providers/multicall-provider.ts b/src/providers/multicall-provider.ts index 654276a4a..4d782e980 100644 --- a/src/providers/multicall-provider.ts +++ b/src/providers/multicall-provider.ts @@ -26,6 +26,18 @@ export type CallSameFunctionOnContractWithMultipleParams< additionalConfig?: TAdditionalConfig; }; +export type CallMultipleFunctionsOnSameContractParams< + TFunctionParams, + TAdditionalConfig = any +> = { + address: string; + contractInterface: Interface; + functionNames: string[]; + functionParams?: TFunctionParams[]; + providerConfig?: ProviderConfig; + additionalConfig?: TAdditionalConfig; +}; + export type SuccessResult = { success: true; result: TReturn; @@ -96,4 +108,17 @@ export abstract class IMulticallProvider { blockNumber: BigNumber; results: Result[]; }>; + + public abstract callMultipleFunctionsOnSameContract< + TFunctionParams extends any[] | undefined, + TReturn = any + >( + params: CallMultipleFunctionsOnSameContractParams< + TFunctionParams, + TMulticallConfig + > + ): Promise<{ + blockNumber: BigNumber; + results: Result[]; + }>; } diff --git a/src/providers/multicall-uniswap-provider.ts b/src/providers/multicall-uniswap-provider.ts index 9d02d0cbc..8d75bdaeb 100644 --- a/src/providers/multicall-uniswap-provider.ts +++ b/src/providers/multicall-uniswap-provider.ts @@ -7,6 +7,7 @@ import { ChainId } from '../util'; import { UNISWAP_MULTICALL_ADDRESS } from '../util/addresses'; import { log } from '../util/log'; import { + CallMultipleFunctionsOnSameContractParams, CallSameFunctionOnContractWithMultipleParams, CallSameFunctionOnMultipleContractsParams, IMulticallProvider, @@ -228,4 +229,101 @@ export class UniswapMulticallProvider extends IMulticallProvider( + params: CallMultipleFunctionsOnSameContractParams< + TFunctionParams, + UniswapMulticallConfig + > + ): Promise<{ + blockNumber: BigNumber; + results: Result[]; + approxGasUsedPerSuccessCall: number; + }> { + const { + address, + contractInterface, + functionNames, + functionParams, + additionalConfig, + providerConfig, + } = params; + + const gasLimitPerCall = + additionalConfig?.gasLimitPerCallOverride ?? this.gasLimitPerCall; + const blockNumberOverride = providerConfig?.blockNumber ?? undefined; + + const calls = _.map(functionNames, (functionName, i) => { + const fragment = contractInterface.getFunction(functionName); + let callData; + const param = functionParams ? functionParams[i] : []; + callData = contractInterface.encodeFunctionData(fragment, param); + log.debug(`fragment ${fragment}`); + return { + target: address, + callData, + gasLimit: gasLimitPerCall, + }; + }); + + log.debug( + { calls }, + `About to multicall for ${functionNames.length} functions at address ${address} with ${functionParams?.length} different sets of params` + ); + + const { blockNumber, returnData: aggregateResults } = + await this.multicallContract.callStatic.multicall(calls, { + blockTag: blockNumberOverride, + }); + + const results: Result[] = []; + + const gasUsedForSuccess: number[] = []; + for (let i = 0; i < aggregateResults.length; i++) { + const fragment = contractInterface.getFunction(functionNames[i]!); + const { success, returnData, gasUsed } = aggregateResults[i]!; + + // Return data "0x" is sometimes returned for invalid pools. + if (!success || returnData.length <= 2) { + log.debug( + { result: aggregateResults[i] }, + `Invalid result calling ${functionNames[i]} with ${ + functionParams ? functionParams[i] : '0' + } params` + ); + results.push({ + success: false, + returnData, + }); + continue; + } + + gasUsedForSuccess.push(gasUsed.toNumber()); + + results.push({ + success: true, + result: contractInterface.decodeFunctionResult( + fragment, + returnData + ) as unknown as TReturn, + }); + } + + log.debug( + { results, functionNames, address }, + `Results for multicall for ${ + functionNames.length + } functions at address ${address} with ${ + functionParams ? functionParams.length : ' 0' + } different sets of params. Results as of block ${blockNumber}` + ); + return { + blockNumber, + results, + approxGasUsedPerSuccessCall: stats.percentile(gasUsedForSuccess, 99), + }; + } } diff --git a/src/providers/v3/gas-data-provider.ts b/src/providers/v3/gas-data-provider.ts index f5ae0580d..9dec8f38a 100644 --- a/src/providers/v3/gas-data-provider.ts +++ b/src/providers/v3/gas-data-provider.ts @@ -1,15 +1,16 @@ -import { BigNumber, providers } from 'ethers'; +import { BigNumber } from 'ethers'; import { OptimismGasData } from '../../routers'; -import { GasPriceOracle, GasPriceOracle__factory } from '../../types/other'; -import { ChainId, OVM_GASPRICE_ADDRESS } from '../../util'; +import { GasPriceOracle__factory } from '../../types/other'; +import { ChainId, log, OVM_GASPRICE_ADDRESS } from '../../util'; +import { IMulticallProvider } from '../multicall-provider'; /** * Provider for getting Optimism gas constants. * * @export - * @interface IGasDataProvider + * @interface IOptimismGasDataProvider */ -export interface IGasDataProvider { +export interface IOptimismGasDataProvider { /** * Gets the data constants needed to calculate the l1 security fee on Optimism. * @returns An OptimismGasData object that includes the l1BaseFee, @@ -18,39 +19,57 @@ export interface IGasDataProvider { getGasData(): Promise; } -export class GasDataProvider implements IGasDataProvider { +export class OptimismGasDataProvider implements IOptimismGasDataProvider { protected gasOracleAddress: string; - private gasOracleContract: GasPriceOracle; constructor( protected chainId: ChainId, - protected provider: providers.BaseProvider, + protected multicall2Provider: IMulticallProvider, gasPriceAddress?: string ) { + if (chainId != ChainId.OPTIMISM && chainId != ChainId.OPTIMISTIC_KOVAN) { + throw new Error('This data provider is used only on optimism networks.'); + } this.gasOracleAddress = gasPriceAddress ?? OVM_GASPRICE_ADDRESS; - - this.gasOracleContract = GasPriceOracle__factory.connect( - this.gasOracleAddress, - provider - ); } public async getGasData(): Promise { - const [l1BaseFee, scalar, decimals, overhead]: BigNumber[] = - await Promise.all([ - this.gasOracleContract.l1BaseFee(), - this.gasOracleContract.scalar(), - this.gasOracleContract.decimals(), - this.gasOracleContract.overhead(), - ]); + const funcNames = ['l1BaseFee', 'scalar', 'decimals', 'overhead']; + const tx = + await this.multicall2Provider.callMultipleFunctionsOnSameContract< + undefined, + [BigNumber] + >({ + address: this.gasOracleAddress, + contractInterface: GasPriceOracle__factory.createInterface(), + functionNames: funcNames, + }); - const data: OptimismGasData = { - l1BaseFee, - scalar, - decimals, - overhead, - }; + if ( + !tx.results[0]?.success || + !tx.results[1]?.success || + !tx.results[2]?.success || + !tx.results[3]?.success + ) { + log.info( + { results: tx.results }, + 'Failed to get gas constants data from the optimism gas oracle' + ); + throw new Error( + 'Failed to get gas constants data from the optimism gas oracle' + ); + } - return data; + const { result: l1BaseFee } = tx.results![0]; + const { result: scalar } = tx.results![1]; + const { result: decimals } = tx.results![2]; + const { result: overhead } = tx.results![3]; + + return { + l1BaseFee: l1BaseFee[0], + scalar: scalar[0], + decimals: decimals[0], + overhead: overhead[0], + }; } } diff --git a/src/routers/alpha-router/alpha-router.ts b/src/routers/alpha-router/alpha-router.ts index 2355051fe..894285d85 100644 --- a/src/routers/alpha-router/alpha-router.ts +++ b/src/routers/alpha-router/alpha-router.ts @@ -51,8 +51,8 @@ import { V2PoolProvider, } from '../../providers/v2/pool-provider'; import { - GasDataProvider, - IGasDataProvider, + IOptimismGasDataProvider, + OptimismGasDataProvider, } from '../../providers/v3/gas-data-provider'; import { IV3PoolProvider, @@ -187,7 +187,7 @@ export type AlphaRouterParams = { /** * Calls the optimism gas oracle contract to fetch constants for calculating the l1 security fee. */ - optimismGasDataProvider?: IGasDataProvider; + optimismGasDataProvider?: IOptimismGasDataProvider; }; /** @@ -304,7 +304,7 @@ export class AlphaRouter protected v3GasModelFactory: IV3GasModelFactory; protected v2GasModelFactory: IV2GasModelFactory; protected blockedTokenListProvider?: ITokenListProvider; - protected optimismGasDataProvider?: IGasDataProvider; + protected optimismGasDataProvider?: IOptimismGasDataProvider; constructor({ chainId, @@ -513,7 +513,8 @@ export class AlphaRouter if (chainId == ChainId.OPTIMISM || chainId == ChainId.OPTIMISTIC_KOVAN) { this.optimismGasDataProvider = - optimismGasDataProvider ?? new GasDataProvider(chainId, this.provider); + optimismGasDataProvider ?? + new OptimismGasDataProvider(chainId, this.multicall2Provider); } } From 679d9b020215d219cbe34e81b300664da569805c Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Mon, 31 Jan 2022 16:39:21 -0500 Subject: [PATCH 10/12] remove and rename variables, add dummy swap config --- cli/base-command.ts | 17 ++-- cli/commands/quote.ts | 10 +-- src/providers/v3/gas-data-provider.ts | 8 +- src/routers/alpha-router/alpha-router.ts | 26 +----- .../entities/route-with-valid-quote.ts | 19 +--- .../alpha-router/functions/best-swap-route.ts | 37 -------- .../alpha-router/gas-models/gas-model.ts | 8 +- .../gas-models/v3/v3-heuristic-gas-model.ts | 88 +++++++------------ src/routers/router.ts | 10 --- 9 files changed, 58 insertions(+), 165 deletions(-) diff --git a/cli/base-command.ts b/cli/base-command.ts index 17e17d40d..56505ae9e 100644 --- a/cli/base-command.ts +++ b/cli/base-command.ts @@ -2,6 +2,7 @@ import { Command, flags } from '@oclif/command'; import { ParserOutput } from '@oclif/parser/lib/parse'; import DEFAULT_TOKEN_LIST from '@uniswap/default-token-list'; +import { Protocol } from '@uniswap/router-sdk'; import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'; import { MethodParameters } from '@uniswap/v3-sdk'; import { default as bunyan, default as Logger } from 'bunyan'; @@ -34,6 +35,7 @@ import { UniswapMulticallProvider, V3PoolProvider, V3QuoteProvider, + V3RouteWithValidQuote, } from '../src'; import { LegacyGasPriceProvider } from '../src/providers/legacy-gas-price-provider'; import { OnChainGasPriceProvider } from '../src/providers/on-chain-gas-price-provider'; @@ -297,10 +299,7 @@ export abstract class BaseCommand extends Command { methodParameters: MethodParameters | undefined, blockNumber: BigNumber, estimatedGasUsed: BigNumber, - gasPriceWei: BigNumber, - initTicksCrossed?: BigNumber, - l1GasUse?: BigNumber, - l1GasCost?: BigNumber + gasPriceWei: BigNumber ) { this.logger.info(`Best Route:`); this.logger.info(`${routeAmountsToString(routeAmounts)}`); @@ -323,8 +322,12 @@ export abstract class BaseCommand extends Command { }); const hops = routeAmounts[0]?.poolAddresses.length; this.logger.info(`Total hops ${hops}`); - this.logger.info(`Total initialized ticks crossed ${initTicksCrossed}`); - this.logger.info(`Optimism l1 gas cost: ${l1GasCost}`); - this.logger.info(`Optimism l1 gas use: ${l1GasUse}`); + + if (routeAmounts[0]?.protocol == Protocol.V3) { + const v3Route = routeAmounts[0] as V3RouteWithValidQuote; + this.logger.info( + `Total initialized ticks crossed ${v3Route.initializedTicksCrossedList.length}` + ); + } } } diff --git a/cli/commands/quote.ts b/cli/commands/quote.ts index 58cd1e9e1..ba92aa15d 100644 --- a/cli/commands/quote.ts +++ b/cli/commands/quote.ts @@ -2,7 +2,7 @@ import { flags } from '@oclif/command'; import { Protocol } from '@uniswap/router-sdk'; import { Currency, Percent, TradeType } from '@uniswap/sdk-core'; import dotenv from 'dotenv'; -import { BigNumber, ethers } from 'ethers'; +import { ethers } from 'ethers'; import _ from 'lodash'; import { ID_TO_CHAIN_ID, @@ -186,9 +186,6 @@ export class Quote extends BaseCommand { quote, quoteGasAdjusted, route: routeAmounts, - initTicksCrossed, - l1GasUse, - l1GasCost, } = swapRoutes; this.logSwapResults( @@ -200,10 +197,7 @@ export class Quote extends BaseCommand { methodParameters, blockNumber, estimatedGasUsed, - gasPriceWei, - initTicksCrossed ?? BigNumber.from(0), - l1GasUse ?? BigNumber.from(0), - l1GasCost ?? BigNumber.from(0)! + gasPriceWei ); } } diff --git a/src/providers/v3/gas-data-provider.ts b/src/providers/v3/gas-data-provider.ts index 9dec8f38a..eb5c41aff 100644 --- a/src/providers/v3/gas-data-provider.ts +++ b/src/providers/v3/gas-data-provider.ts @@ -1,9 +1,15 @@ import { BigNumber } from 'ethers'; -import { OptimismGasData } from '../../routers'; import { GasPriceOracle__factory } from '../../types/other'; import { ChainId, log, OVM_GASPRICE_ADDRESS } from '../../util'; import { IMulticallProvider } from '../multicall-provider'; +export type OptimismGasData = { + l1BaseFee: BigNumber; + scalar: BigNumber; + decimals: BigNumber; + overhead: BigNumber; +}; + /** * Provider for getting Optimism gas constants. * diff --git a/src/routers/alpha-router/alpha-router.ts b/src/routers/alpha-router/alpha-router.ts index 894285d85..48c00f69c 100644 --- a/src/routers/alpha-router/alpha-router.ts +++ b/src/routers/alpha-router/alpha-router.ts @@ -796,8 +796,7 @@ export class AlphaRouter quoteToken, gasPriceWei, tradeType, - routingConfig, - swapConfig ?? undefined + routingConfig ) ); } @@ -860,9 +859,6 @@ export class AlphaRouter routes: routeAmounts, estimatedGasUsedQuoteToken, estimatedGasUsedUSD, - initTicksCrossed, - l1GasCost, - l1GasUse, } = swapRouteRaw; // Build Trade object that represents the optimal swap. @@ -906,9 +902,6 @@ export class AlphaRouter trade, methodParameters, blockNumber: BigNumber.from(await blockNumber), - initTicksCrossed, - l1GasCost, - l1GasUse, }; } @@ -920,8 +913,7 @@ export class AlphaRouter quoteToken: Token, gasPriceWei: BigNumber, swapType: TradeType, - routingConfig: AlphaRouterConfig, - swapConfig?: SwapOptions + routingConfig: AlphaRouterConfig ): Promise<{ routesWithValidQuotes: V3RouteWithValidQuote[]; candidatePools: CandidatePoolsBySelectionCriteria; @@ -970,24 +962,12 @@ export class AlphaRouter blockNumber: routingConfig.blockNumber, }); - // only make contract calls once - let gasData; - if ( - this.chainId == ChainId.OPTIMISM || - this.chainId == ChainId.OPTIMISTIC_KOVAN - ) { - gasData = this.optimismGasDataProvider - ? await this.optimismGasDataProvider.getGasData() - : undefined; - } - const gasModel = await this.v3GasModelFactory.buildGasModel( this.chainId, gasPriceWei, this.v3PoolProvider, quoteToken, - swapConfig, - gasData + this.optimismGasDataProvider ); metric.putMetric( diff --git a/src/routers/alpha-router/entities/route-with-valid-quote.ts b/src/routers/alpha-router/entities/route-with-valid-quote.ts index 0c20e084e..a132393e2 100644 --- a/src/routers/alpha-router/entities/route-with-valid-quote.ts +++ b/src/routers/alpha-router/entities/route-with-valid-quote.ts @@ -79,9 +79,6 @@ export class V2RouteWithValidQuote implements IV2RouteWithValidQuote { public tradeType: TradeType; public poolAddresses: string[]; public tokenPath: Token[]; - public initTicksCrossed?: BigNumber; - public gasUseL1?: BigNumber; - public gasCostL1?: BigNumber; public toString(): string { return `${this.percent.toFixed( @@ -176,9 +173,6 @@ export class V3RouteWithValidQuote implements IV3RouteWithValidQuote { public tradeType: TradeType; public poolAddresses: string[]; public tokenPath: Token[]; - public initTicksCrossed: BigNumber; - public gasUseL1: BigNumber; - public gasCostL1: BigNumber; public toString(): string { return `${this.percent.toFixed( @@ -213,21 +207,12 @@ export class V3RouteWithValidQuote implements IV3RouteWithValidQuote { this.quoteToken = quoteToken; this.tradeType = tradeType; - const { - gasEstimate, - gasCostInToken, - gasCostInUSD, - initTicksCrossed, - gasUseL1, - gasCostL1, - } = this.gasModel.estimateGasCost(this); + const { gasEstimate, gasCostInToken, gasCostInUSD } = + this.gasModel.estimateGasCost(this); this.gasCostInToken = gasCostInToken; this.gasCostInUSD = gasCostInUSD; this.gasEstimate = gasEstimate; - this.initTicksCrossed = initTicksCrossed!; - this.gasUseL1 = gasUseL1!; - this.gasCostL1 = gasCostL1!; // If its exact out, we need to request *more* of the input token to account for the gas. if (this.tradeType == TradeType.EXACT_INPUT) { diff --git a/src/routers/alpha-router/functions/best-swap-route.ts b/src/routers/alpha-router/functions/best-swap-route.ts index 2fea783d5..c3dc77cc8 100644 --- a/src/routers/alpha-router/functions/best-swap-route.ts +++ b/src/routers/alpha-router/functions/best-swap-route.ts @@ -26,9 +26,6 @@ export function getBestSwapRoute( estimatedGasUsedUSD: CurrencyAmount; estimatedGasUsedQuoteToken: CurrencyAmount; routes: RouteWithValidQuote[]; - initTicksCrossed?: BigNumber; - l1GasCost?: BigNumber; - l1GasUse?: BigNumber; } | null { const now = Date.now(); @@ -119,9 +116,6 @@ export function getBestSwapRouteBy( estimatedGasUsedUSD: CurrencyAmount; estimatedGasUsedQuoteToken: CurrencyAmount; routes: RouteWithValidQuote[]; - initTicksCrossed?: BigNumber; - l1GasUse?: BigNumber; - l1GasCost?: BigNumber; } | undefined { // Build a map of percentage to sorted list of quotes, with the biggest quote being first in the list. @@ -439,34 +433,6 @@ export function getBestSwapRouteBy( _.map(bestSwap, (routeWithValidQuote) => routeWithValidQuote.quote) ); - let totalL1GasUsed = BigNumber.from(0); - let totalL1GasCost = BigNumber.from(0); - let totalInitTicksCrossed = BigNumber.from(0); - if (chainId == ChainId.OPTIMISM || chainId == ChainId.OPTIMISTIC_KOVAN) { - // only need these values for optimism security fee l1 - log.info('Calculating total tick and gas costs'); - totalL1GasUsed = _.map(bestSwap, (route) => route.gasUseL1!).reduce( - (sum, route) => sum.add(route), - BigNumber.from(0) - ); - totalL1GasCost = _.map(bestSwap, (route) => route.gasCostL1!).reduce( - (sum, route) => sum.add(route), - BigNumber.from(0) - ); - } - // only need tick data for estimating gas on these chains - if ( - chainId == ChainId.OPTIMISM || - chainId == ChainId.OPTIMISTIC_KOVAN || - chainId == ChainId.ARBITRUM_ONE || - chainId == ChainId.ARBITRUM_RINKEBY - ) { - totalInitTicksCrossed = _.map( - bestSwap, - (routeWithValidQuote) => routeWithValidQuote.initTicksCrossed! - ).reduce((sum, ticksCrossed) => sum.add(ticksCrossed), BigNumber.from(0)); - } - const routeWithQuotes = bestSwap.sort((routeAmountA, routeAmountB) => routeAmountB.amount.greaterThan(routeAmountA.amount) ? 1 : -1 ); @@ -483,9 +449,6 @@ export function getBestSwapRouteBy( estimatedGasUsedUSD, estimatedGasUsedQuoteToken, routes: routeWithQuotes, - initTicksCrossed: totalInitTicksCrossed, - l1GasCost: totalL1GasCost, - l1GasUse: totalL1GasUsed, }; } diff --git a/src/routers/alpha-router/gas-models/gas-model.ts b/src/routers/alpha-router/gas-models/gas-model.ts index b4dce8091..013cc9394 100644 --- a/src/routers/alpha-router/gas-models/gas-model.ts +++ b/src/routers/alpha-router/gas-models/gas-model.ts @@ -31,10 +31,10 @@ import { WBTC_GÖRLI, } from '../../../providers/token-provider'; import { IV2PoolProvider } from '../../../providers/v2/pool-provider'; +import { IOptimismGasDataProvider } from '../../../providers/v3/gas-data-provider'; import { IV3PoolProvider } from '../../../providers/v3/pool-provider'; import { CurrencyAmount } from '../../../util/amounts'; import { ChainId } from '../../../util/chains'; -import { OptimismGasData, SwapOptions } from '../../router'; import { RouteWithValidQuote, V2RouteWithValidQuote, @@ -80,9 +80,6 @@ export type IGasModel = { gasEstimate: BigNumber; gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; - initTicksCrossed?: BigNumber; - gasUseL1?: BigNumber; - gasCostL1?: BigNumber; }; }; @@ -103,8 +100,7 @@ export abstract class IV3GasModelFactory { gasPriceWei: BigNumber, poolProvider: IV3PoolProvider, inTermsOfToken: Token, - swapConfig?: SwapOptions, - gasData?: OptimismGasData + optimismGasDataProvider?: IOptimismGasDataProvider ): Promise>; } diff --git a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts index fc68bb655..433564ac9 100644 --- a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts +++ b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts @@ -1,12 +1,12 @@ import { BigNumber } from '@ethersproject/bignumber'; -import { Token } from '@uniswap/sdk-core'; +import { Percent, Token } from '@uniswap/sdk-core'; import { FeeAmount, Pool } from '@uniswap/v3-sdk'; import _ from 'lodash'; +import { SwapOptions, WRAPPED_NATIVE_CURRENCY } from '../../../..'; import { + IOptimismGasDataProvider, OptimismGasData, - SwapOptions, - WRAPPED_NATIVE_CURRENCY, -} from '../../../..'; +} from '../../../../providers/v3/gas-data-provider'; import { IV3PoolProvider } from '../../../../providers/v3/pool-provider'; import { ChainId } from '../../../../util'; import { CurrencyAmount } from '../../../../util/amounts'; @@ -54,10 +54,13 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasPriceWei: BigNumber, poolProvider: IV3PoolProvider, token: Token, - swapConfig?: SwapOptions, - gasData?: OptimismGasData + optimismGasDataProvider?: IOptimismGasDataProvider // this is the quoteToken ): Promise> { + const optimismGasData = optimismGasDataProvider + ? await optimismGasDataProvider.getGasData() + : undefined; + // If our quote token is WETH, we don't need to convert our gas use to be in terms // of the quote token in order to produce a gas adjusted amount. // We do return a gas use in USD however, so we still convert to usd. @@ -75,22 +78,12 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasEstimate: BigNumber; gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; - initTicksCrossed: BigNumber; - gasUseL1: BigNumber; - gasCostL1: BigNumber; } => { - const { - totalGasCostNativeCurrency, - totalInitializedTicksCrossed, - l1GasUsed, - totalGasUse, - l1Fee, - } = this.estimateGas( + const { totalGasCostNativeCurrency, totalGasUse } = this.estimateGas( routeWithValidQuote, gasPriceWei, chainId, - swapConfig, - gasData + optimismGasData ); const token0 = usdPool.token0.address == nativeCurrency.address; @@ -107,9 +100,6 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasEstimate: totalGasUse, gasCostInToken: totalGasCostNativeCurrency, gasCostInUSD: gasCostInTermsOfUSD, - initTicksCrossed: totalInitializedTicksCrossed, - gasUseL1: l1GasUsed, - gasCostL1: l1Fee, }; }; @@ -142,22 +132,12 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasEstimate: BigNumber; gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; - initTicksCrossed: BigNumber; - gasUseL1: BigNumber; - gasCostL1: BigNumber; } => { - const { - totalGasCostNativeCurrency, - totalInitializedTicksCrossed, - l1GasUsed, - totalGasUse, - l1Fee, - } = this.estimateGas( + const { totalGasCostNativeCurrency, totalGasUse } = this.estimateGas( routeWithValidQuote, gasPriceWei, chainId, - swapConfig, - gasData + optimismGasData ); if (!nativePool) { @@ -168,9 +148,6 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasEstimate: totalGasUse, gasCostInToken: CurrencyAmount.fromRawAmount(token, 0), gasCostInUSD: CurrencyAmount.fromRawAmount(usdToken, 0), - initTicksCrossed: totalInitializedTicksCrossed, - gasUseL1: l1GasUsed, - gasCostL1: l1Fee, }; } @@ -228,9 +205,6 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasEstimate: totalGasUse, gasCostInToken: gasCostInTermsOfQuoteToken, gasCostInUSD: gasCostInTermsOfUSD!, - initTicksCrossed: totalInitializedTicksCrossed, - gasUseL1: l1GasUsed, - gasCostL1: l1Fee, }; }; @@ -243,7 +217,6 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { routeWithValidQuote: V3RouteWithValidQuote, gasPriceWei: BigNumber, chainId: ChainId, - swapConfig?: SwapOptions, gasData?: OptimismGasData ) { const totalInitializedTicksCrossed = BigNumber.from( @@ -261,15 +234,17 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { let l1Fee = BigNumber.from(0); if (chainId == ChainId.OPTIMISM || chainId == ChainId.OPTIMISTIC_KOVAN) { // account for the L1 security fee - if (!swapConfig) { - log.info('Skipping l1 security fee calculation'); - } else { - [l1GasUsed, l1Fee] = this.calculateL1SecurityFee( - routeWithValidQuote, - swapConfig, - gasData! - ); - } + // create dummy swapConfig to get calldata bytes + const swapConfig: SwapOptions = { + recipient: '0x0000000000000000000000000000000000000001', + deadline: 100, + slippageTolerance: new Percent(5, 10_000), + }; + [l1GasUsed, l1Fee] = this.calculateOptimismToL1SecurityFee( + routeWithValidQuote, + swapConfig, + gasData! + ); } const baseGasUse = BASE_SWAP_COST(chainId) .add(hopsGasUse) @@ -278,9 +253,8 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { const baseGasCostWei = gasPriceWei.mul(baseGasUse); - const totalGasUse = l1GasUsed.add(baseGasUse); - // total gas cost including l1 security fee if on optimism + const totalGasUse = l1GasUsed.add(baseGasUse); const totalGasCostWei = l1Fee.add(baseGasCostWei); const wrappedCurrency = WRAPPED_NATIVE_CURRENCY[chainId]!; @@ -293,8 +267,6 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { return { totalGasCostNativeCurrency, totalInitializedTicksCrossed, - l1GasUsed, - l1Fee, totalGasUse, }; } @@ -404,7 +376,11 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { return maxPool; } - private calculateL1SecurityFee( + /** + * To avoid having a call to optimism's L1 security fee contract for every route and amount combination, + * we replicate the gas cost accounting here. + */ + private calculateOptimismToL1SecurityFee( route: V3RouteWithValidQuote, swapConfig: SwapOptions, gasData: OptimismGasData @@ -419,7 +395,7 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { [route] ); const data = buildSwapMethodParameters(trade, swapConfig).calldata; - const l1GasUsed = this.getL1GasUsed(data, overhead); + const l1GasUsed = this.getOptimismToL1GasUsed(data, overhead); const l1Fee = l1GasUsed.mul(l1BaseFee); const unscaled = l1Fee.mul(scalar); // scaled = unscaled / (10 ** decimals) @@ -428,7 +404,7 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { return [l1GasUsed, scaled]; } - private getL1GasUsed(data: string, overhead: BigNumber): BigNumber { + private getOptimismToL1GasUsed(data: string, overhead: BigNumber): BigNumber { // data is hex encoded const dataArr: string[] = data.slice(2).match(/.{1,2}/g)!; const numBytes = dataArr.length; diff --git a/src/routers/router.ts b/src/routers/router.ts index 0b289f8cf..9339f44d5 100644 --- a/src/routers/router.ts +++ b/src/routers/router.ts @@ -65,9 +65,6 @@ export type SwapRoute = { * The calldata to execute the swap. Only returned if swapConfig was provided when calling the router. */ methodParameters?: MethodParameters; - initTicksCrossed?: BigNumber; - l1GasCost?: BigNumber; - l1GasUse?: BigNumber; }; export type SwapToRatioRoute = SwapRoute & { @@ -120,13 +117,6 @@ export type SwapOptions = { ); }; -export type OptimismGasData = { - l1BaseFee: BigNumber; - scalar: BigNumber; - decimals: BigNumber; - overhead: BigNumber; -}; - // Config passed in to determine configurations on acceptable liquidity // to add to a position and max iterations on the route-finding algorithm export type SwapAndAddConfig = { From 00d574e8791e93489f978d71195e634a237dd6ba Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Tue, 1 Feb 2022 11:45:06 -0500 Subject: [PATCH 11/12] remove logs --- cli/base-command.ts | 11 ----------- src/providers/multicall-uniswap-provider.ts | 4 +--- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/cli/base-command.ts b/cli/base-command.ts index 56505ae9e..6641ff3fe 100644 --- a/cli/base-command.ts +++ b/cli/base-command.ts @@ -2,7 +2,6 @@ import { Command, flags } from '@oclif/command'; import { ParserOutput } from '@oclif/parser/lib/parse'; import DEFAULT_TOKEN_LIST from '@uniswap/default-token-list'; -import { Protocol } from '@uniswap/router-sdk'; import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'; import { MethodParameters } from '@uniswap/v3-sdk'; import { default as bunyan, default as Logger } from 'bunyan'; @@ -35,7 +34,6 @@ import { UniswapMulticallProvider, V3PoolProvider, V3QuoteProvider, - V3RouteWithValidQuote, } from '../src'; import { LegacyGasPriceProvider } from '../src/providers/legacy-gas-price-provider'; import { OnChainGasPriceProvider } from '../src/providers/on-chain-gas-price-provider'; @@ -320,14 +318,5 @@ export abstract class BaseCommand extends Command { estimatedGasUsed: estimatedGasUsed.toString(), gasPriceWei: gasPriceWei.toString(), }); - const hops = routeAmounts[0]?.poolAddresses.length; - this.logger.info(`Total hops ${hops}`); - - if (routeAmounts[0]?.protocol == Protocol.V3) { - const v3Route = routeAmounts[0] as V3RouteWithValidQuote; - this.logger.info( - `Total initialized ticks crossed ${v3Route.initializedTicksCrossedList.length}` - ); - } } } diff --git a/src/providers/multicall-uniswap-provider.ts b/src/providers/multicall-uniswap-provider.ts index 8d75bdaeb..6a59f199f 100644 --- a/src/providers/multicall-uniswap-provider.ts +++ b/src/providers/multicall-uniswap-provider.ts @@ -258,10 +258,8 @@ export class UniswapMulticallProvider extends IMulticallProvider { const fragment = contractInterface.getFunction(functionName); - let callData; const param = functionParams ? functionParams[i] : []; - callData = contractInterface.encodeFunctionData(fragment, param); - log.debug(`fragment ${fragment}`); + const callData = contractInterface.encodeFunctionData(fragment, param); return { target: address, callData, From 3de4a88042709d24fb1573cbfa8e816eec8b4265 Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Tue, 1 Feb 2022 12:13:42 -0500 Subject: [PATCH 12/12] rremove 02 typeing --- src/providers/swap-router-provider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/providers/swap-router-provider.ts b/src/providers/swap-router-provider.ts index 3c82af236..16831add2 100644 --- a/src/providers/swap-router-provider.ts +++ b/src/providers/swap-router-provider.ts @@ -1,6 +1,6 @@ import { ApprovalTypes } from '@uniswap/router-sdk'; import { Currency, CurrencyAmount } from '@uniswap/sdk-core'; -import { SwapRouter02__factory } from '../types/router02'; +import { SwapRouter02__factory } from '../types/other'; import { log } from '../util'; import { IMulticallProvider } from './multicall-provider'; @@ -9,7 +9,7 @@ type TokenApprovalTypes = { approvalTokenOut: ApprovalTypes; }; -const SWAP_ROUTER_ADDRESS = '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45'; +const SWAP_ROUTER_ADDRESS = '0x075B36dE1Bd11cb361c5B3B1E80A9ab0e7aa8a60'; /** * Provider for accessing the SwapRouter02 Contract .