-
Notifications
You must be signed in to change notification settings - Fork 388
/
gas-model.ts
258 lines (245 loc) · 7.42 KB
/
gas-model.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
import { BigNumber } from '@ethersproject/bignumber';
import {
ChainId,
CurrencyAmount as CurrencyAmountRaw,
Token,
} from '@uniswap/sdk-core';
import { Pair } from '@uniswap/v2-sdk';
import { Pool } from '@uniswap/v3-sdk';
import { ProviderConfig } from '../../../providers/provider';
import {
CUSD_CELO,
CUSD_CELO_ALFAJORES,
DAI_ARBITRUM,
DAI_AVAX,
DAI_BNB,
DAI_GOERLI,
DAI_MAINNET,
DAI_OPTIMISM,
DAI_OPTIMISM_GOERLI,
DAI_OPTIMISM_SEPOLIA,
DAI_POLYGON_MUMBAI,
DAI_SEPOLIA, USDB_BLAST,
USDC_ARBITRUM,
USDC_ARBITRUM_GOERLI,
USDC_ARBITRUM_SEPOLIA,
USDC_AVAX,
USDC_BASE,
USDC_BNB,
USDC_BRIDGED_AVAX,
USDC_CELO,
USDC_ETHEREUM_GNOSIS,
USDC_GOERLI,
USDC_MAINNET,
USDC_MOONBEAM,
USDC_NATIVE_ARBITRUM,
USDC_NATIVE_AVAX,
USDC_NATIVE_BASE,
USDC_NATIVE_CELO,
USDC_NATIVE_OPTIMISM,
USDC_NATIVE_POLYGON,
USDC_OPTIMISM,
USDC_OPTIMISM_GOERLI,
USDC_OPTIMISM_SEPOLIA,
USDC_POLYGON,
USDC_SEPOLIA,
USDC_WORMHOLE_CELO, USDC_ZORA,
USDT_ARBITRUM,
USDT_BNB,
USDT_GOERLI,
USDT_MAINNET,
USDT_OPTIMISM,
USDT_OPTIMISM_GOERLI,
USDT_OPTIMISM_SEPOLIA,
WBTC_GOERLI
} from '../../../providers/token-provider';
import { IV2PoolProvider } from '../../../providers/v2/pool-provider';
import {
ArbitrumGasData,
IL2GasDataProvider,
} from '../../../providers/v3/gas-data-provider';
import { WRAPPED_NATIVE_CURRENCY } from '../../../util';
import { CurrencyAmount } from '../../../util/amounts';
import {
MixedRouteWithValidQuote,
RouteWithValidQuote,
V2RouteWithValidQuote,
V3RouteWithValidQuote,
} from '../entities/route-with-valid-quote';
// When adding new usd gas tokens, ensure the tokens are ordered
// from tokens with highest decimals to lowest decimals. For example,
// DAI_AVAX has 18 decimals and comes before USDC_AVAX which has 6 decimals.
export const usdGasTokensByChain: { [chainId in ChainId]?: Token[] } = {
[ChainId.MAINNET]: [DAI_MAINNET, USDC_MAINNET, USDT_MAINNET],
[ChainId.ARBITRUM_ONE]: [
DAI_ARBITRUM,
USDC_ARBITRUM,
USDC_NATIVE_ARBITRUM,
USDT_ARBITRUM,
],
[ChainId.OPTIMISM]: [
DAI_OPTIMISM,
USDC_OPTIMISM,
USDC_NATIVE_OPTIMISM,
USDT_OPTIMISM,
],
[ChainId.OPTIMISM_GOERLI]: [
DAI_OPTIMISM_GOERLI,
USDC_OPTIMISM_GOERLI,
USDT_OPTIMISM_GOERLI,
],
[ChainId.OPTIMISM_SEPOLIA]: [
DAI_OPTIMISM_SEPOLIA,
USDC_OPTIMISM_SEPOLIA,
USDT_OPTIMISM_SEPOLIA,
],
[ChainId.ARBITRUM_GOERLI]: [USDC_ARBITRUM_GOERLI],
[ChainId.ARBITRUM_SEPOLIA]: [USDC_ARBITRUM_SEPOLIA],
[ChainId.GOERLI]: [DAI_GOERLI, USDC_GOERLI, USDT_GOERLI, WBTC_GOERLI],
[ChainId.SEPOLIA]: [USDC_SEPOLIA, DAI_SEPOLIA],
[ChainId.POLYGON]: [USDC_POLYGON, USDC_NATIVE_POLYGON],
[ChainId.POLYGON_MUMBAI]: [DAI_POLYGON_MUMBAI],
[ChainId.CELO]: [CUSD_CELO, USDC_CELO, USDC_NATIVE_CELO, USDC_WORMHOLE_CELO],
[ChainId.CELO_ALFAJORES]: [CUSD_CELO_ALFAJORES],
[ChainId.GNOSIS]: [USDC_ETHEREUM_GNOSIS],
[ChainId.MOONBEAM]: [USDC_MOONBEAM],
[ChainId.BNB]: [USDT_BNB, USDC_BNB, DAI_BNB],
[ChainId.AVALANCHE]: [
DAI_AVAX,
USDC_AVAX,
USDC_NATIVE_AVAX,
USDC_BRIDGED_AVAX,
],
[ChainId.BASE]: [USDC_BASE, USDC_NATIVE_BASE],
[ChainId.BLAST]: [USDB_BLAST],
[ChainId.ZORA]: [USDC_ZORA],
};
export type L1ToL2GasCosts = {
gasUsedL1: BigNumber;
gasUsedL1OnL2: BigNumber;
gasCostL1USD: CurrencyAmount;
gasCostL1QuoteToken: CurrencyAmount;
};
export type GasModelProviderConfig = ProviderConfig & {
/*
* Any additional overhead to add to the gas estimate
*/
additionalGasOverhead?: BigNumber;
gasToken?: Token;
};
export type BuildOnChainGasModelFactoryType = {
chainId: ChainId;
gasPriceWei: BigNumber;
pools: LiquidityCalculationPools;
amountToken: Token;
quoteToken: Token;
v2poolProvider: IV2PoolProvider;
l2GasDataProvider?: IL2GasDataProvider<ArbitrumGasData>;
providerConfig?: GasModelProviderConfig;
};
export type BuildV2GasModelFactoryType = {
chainId: ChainId;
gasPriceWei: BigNumber;
poolProvider: IV2PoolProvider;
token: Token;
l2GasDataProvider?: IL2GasDataProvider<ArbitrumGasData>;
providerConfig?: GasModelProviderConfig;
};
export type LiquidityCalculationPools = {
usdPool: Pool;
nativeAndQuoteTokenV3Pool: Pool | null;
nativeAndAmountTokenV3Pool: Pool | null;
nativeAndSpecifiedGasTokenV3Pool: Pool | null;
};
export type GasModelType = {
v2GasModel?: IGasModel<V2RouteWithValidQuote>;
v3GasModel: IGasModel<V3RouteWithValidQuote>;
mixedRouteGasModel: IGasModel<MixedRouteWithValidQuote>;
};
/**
* Contains functions for generating gas estimates for given routes.
*
* We generally compute gas estimates off-chain because
* 1/ Calling eth_estimateGas for a swaps requires the caller to have
* the full balance token being swapped, and approvals.
* 2/ Tracking gas used using a wrapper contract is not accurate with Multicall
* due to EIP-2929
* 3/ For V2 we simulate all our swaps off-chain so have no way to track gas used.
*
* Generally these models should be optimized to return quickly by performing any
* long running operations (like fetching external data) outside of the functions defined.
* This is because the functions in the model are called once for every route and every
* amount that is considered in the algorithm so it is important to minimize the number of
* long running operations.
*/
export type IGasModel<TRouteWithValidQuote extends RouteWithValidQuote> = {
estimateGasCost(routeWithValidQuote: TRouteWithValidQuote): {
gasEstimate: BigNumber;
gasCostInToken: CurrencyAmount;
gasCostInUSD: CurrencyAmount;
gasCostInGasToken?: CurrencyAmount;
};
calculateL1GasFees?(routes: TRouteWithValidQuote[]): Promise<L1ToL2GasCosts>;
};
/**
* Factory for building gas models that can be used with any route to generate
* gas estimates.
*
* Factory model is used so that any supporting data can be fetched once and
* returned as part of the model.
*
* @export
* @abstract
* @class IV2GasModelFactory
*/
export abstract class IV2GasModelFactory {
public abstract buildGasModel({
chainId,
gasPriceWei,
poolProvider,
token,
providerConfig,
}: BuildV2GasModelFactoryType): Promise<IGasModel<V2RouteWithValidQuote>>;
}
/**
* Factory for building gas models that can be used with any route to generate
* gas estimates.
*
* Factory model is used so that any supporting data can be fetched once and
* returned as part of the model.
*
* @export
* @abstract
* @class IOnChainGasModelFactory
*/
export abstract class IOnChainGasModelFactory {
public abstract buildGasModel({
chainId,
gasPriceWei,
pools,
amountToken,
quoteToken,
v2poolProvider,
l2GasDataProvider,
providerConfig,
}: BuildOnChainGasModelFactoryType): Promise<
IGasModel<V3RouteWithValidQuote | MixedRouteWithValidQuote>
>;
}
// Determines if native currency is token0
// Gets the native price of the pool, dependent on 0 or 1
// quotes across the pool
export const getQuoteThroughNativePool = (
chainId: ChainId,
nativeTokenAmount: CurrencyAmountRaw<Token>,
nativeTokenPool: Pool | Pair
): CurrencyAmount => {
const nativeCurrency = WRAPPED_NATIVE_CURRENCY[chainId];
const isToken0 = nativeTokenPool.token0.equals(nativeCurrency);
// returns mid price in terms of the native currency (the ratio of token/nativeToken)
const nativeTokenPrice = isToken0
? nativeTokenPool.token0Price
: nativeTokenPool.token1Price;
// return gas cost in terms of the non native currency
return nativeTokenPrice.quote(nativeTokenAmount) as CurrencyAmount;
};