@paraswap/dex-lib 3.4.2-balancer-v2-single-swap.0 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +377 -377
- package/build/config.js +9 -5
- package/build/config.js.map +1 -1
- package/build/dex/algebra/algebra.js +25 -25
- package/build/dex/balancer-v1/balancer-v1.js +34 -34
- package/build/dex/balancer-v2/balancer-v2.d.ts +1 -1
- package/build/dex/balancer-v2/balancer-v2.js +65 -78
- package/build/dex/balancer-v2/balancer-v2.js.map +1 -1
- package/build/dex/camelot/camelot.js +27 -27
- package/build/dex/kyberdmm/kyberdmm.js +27 -27
- package/build/dex/pancakeswap-v3/pancakeswap-v3.js +25 -25
- package/build/dex/solidly/solidly.js +27 -27
- package/build/dex/solidly-v3/solidly-v3.js +25 -25
- package/build/dex/swaap-v2/config.js +15 -0
- package/build/dex/swaap-v2/config.js.map +1 -1
- package/build/dex/uniswap-v2/uniswap-v2.js +26 -26
- package/build/dex/uniswap-v3/uniswap-v3.js +25 -25
- package/funding.json +5 -5
- package/package.json +1 -1
- package/src/config.ts +500 -496
- package/src/constants.ts +67 -67
- package/src/dex/aave-v2/aave-v2.ts +409 -409
- package/src/dex/aave-v3/aave-v3.ts +320 -320
- package/src/dex/algebra/algebra.ts +1180 -1180
- package/src/dex/angle-staked-stable/angle-staked-stable.ts +347 -347
- package/src/dex/augustus-rfq.ts +180 -180
- package/src/dex/bProtocol/bProtocol.ts +108 -108
- package/src/dex/balancer-v1/balancer-v1.ts +572 -572
- package/src/dex/balancer-v2/balancer-v2-e2e.test.ts +1699 -1699
- package/src/dex/balancer-v2/balancer-v2.ts +1669 -1701
- package/src/dex/bancor/bancor.ts +128 -128
- package/src/dex/camelot/camelot.ts +873 -873
- package/src/dex/compound/compound.ts +107 -107
- package/src/dex/curve-v1/config.ts +1179 -1179
- package/src/dex/curve-v1/curve-v1-e2e.test.ts +507 -507
- package/src/dex/curve-v1/curve-v1.ts +1315 -1315
- package/src/dex/curve-v1-factory/config.ts +1018 -1018
- package/src/dex/curve-v1-factory/curve-v1-factory.ts +1288 -1288
- package/src/dex/curve-v2/curve-v2.ts +440 -440
- package/src/dex/dexalot/dexalot.ts +1100 -1100
- package/src/dex/dodo-v1/dodo-v1.ts +132 -132
- package/src/dex/dodo-v2.ts +266 -266
- package/src/dex/etherfi.ts +239 -239
- package/src/dex/generic-rfq/generic-rfq.ts +431 -431
- package/src/dex/gmx/gmx.ts +321 -321
- package/src/dex/hashflow/hashflow.ts +1135 -1135
- package/src/dex/idex.ts +254 -254
- package/src/dex/index.ts +357 -357
- package/src/dex/jarvis-v6/jarvis-v6.ts +509 -509
- package/src/dex/jarvis.ts +262 -262
- package/src/dex/kyberdmm/kyberdmm.ts +649 -649
- package/src/dex/lido/lido.ts +110 -110
- package/src/dex/maker-psm/maker-psm.ts +592 -592
- package/src/dex/maverick-v1/maverick-v1.ts +537 -537
- package/src/dex/nerve/config.ts +635 -635
- package/src/dex/nerve/nerve-e2e.test.ts +731 -731
- package/src/dex/nerve/nerve-events.test.ts +911 -911
- package/src/dex/nerve/nerve.ts +467 -467
- package/src/dex/onebit/onebit.ts +113 -113
- package/src/dex/pancakeswap-v3/pancakeswap-v3.ts +1150 -1150
- package/src/dex/paraswap-limit-orders/config.ts +60 -60
- package/src/dex/paraswap-limit-orders/paraswap-limit-orders-e2e.test.ts +137 -137
- package/src/dex/paraswap-limit-orders/paraswap-limit-orders-integration.test.ts +328 -328
- package/src/dex/paraswap-limit-orders/paraswap-limit-orders.ts +631 -631
- package/src/dex/polygon-migrator/polygon-migrator.ts +194 -194
- package/src/dex/quick-perps/quick-perps.ts +337 -337
- package/src/dex/quickswap/config.ts +16 -16
- package/src/dex/quickswap/quickswap-e2e.test.ts +384 -384
- package/src/dex/smoothy/smoothy.ts +110 -110
- package/src/dex/solidly/config.ts +225 -225
- package/src/dex/solidly/solidly-e2e.test.ts +1421 -1421
- package/src/dex/solidly/solidly-integration.test.ts +1753 -1753
- package/src/dex/solidly/solidly.ts +687 -687
- package/src/dex/solidly-v3/solidly-v3.ts +968 -968
- package/src/dex/spark/spark.ts +284 -284
- package/src/dex/stable-pool/stable-pool.ts +129 -129
- package/src/dex/swaap-v2/config.ts +15 -0
- package/src/dex/swaap-v2/swaap-v2-e2e.test.ts +233 -17
- package/src/dex/swaap-v2/swaap-v2-integration.test.ts +1 -1
- package/src/dex/swaap-v2/swaap-v2.ts +1056 -1056
- package/src/dex/swell/swell.ts +312 -312
- package/src/dex/synthetix/synthetix.ts +420 -420
- package/src/dex/trader-joe-v2.1/trader-joe-v2.1.ts +180 -180
- package/src/dex/uniswap-v2/config.ts +637 -637
- package/src/dex/uniswap-v2/constants.ts +58 -58
- package/src/dex/uniswap-v2/uniswap-v2-e2e-avalanche.test.ts +1257 -1257
- package/src/dex/uniswap-v2/uniswap-v2-e2e-base.test.ts +42 -42
- package/src/dex/uniswap-v2/uniswap-v2-e2e-bsc.test.ts +1295 -1295
- package/src/dex/uniswap-v2/uniswap-v2-e2e-mainnet.test.ts +1834 -1834
- package/src/dex/uniswap-v2/uniswap-v2-e2e-polygon.test.ts +871 -871
- package/src/dex/uniswap-v2/uniswap-v2.ts +1117 -1117
- package/src/dex/uniswap-v3/uniswap-v3.ts +1501 -1501
- package/src/dex/uniswap-v3.ts +242 -242
- package/src/dex/weth/config.ts +73 -73
- package/src/dex/weth/weth.ts +230 -230
- package/src/dex/wombat/wombat.ts +467 -467
- package/src/dex/woo-fi-v2/woo-fi-v2.ts +529 -529
- package/src/dex/wsteth/wsteth.ts +304 -304
- package/src/dex/zerox/index.ts +328 -328
- package/src/executor/Executor01BytecodeBuilder.ts +474 -474
- package/src/executor/Executor02BytecodeBuilder.ts +1392 -1392
- package/src/executor/ExecutorBytecodeBuilder.ts +390 -390
- package/src/executor/ExecutorDetector.ts +131 -131
- package/src/executor/constants.ts +66 -66
- package/src/executor/executor01-bytecode-builder-e2e.test.ts +1478 -1478
- package/src/executor/utils.ts +62 -62
- package/src/router/simpleswap.ts +366 -366
- package/src/types.ts +342 -342
- package/tests/constants-e2e.ts +1632 -1622
- package/tests/generate-new-limit-order.ts +107 -107
package/src/dex/wsteth/wsteth.ts
CHANGED
|
@@ -1,304 +1,304 @@
|
|
|
1
|
-
import { Interface } from '@ethersproject/abi';
|
|
2
|
-
import {
|
|
3
|
-
Token,
|
|
4
|
-
Address,
|
|
5
|
-
ExchangePrices,
|
|
6
|
-
PoolPrices,
|
|
7
|
-
AdapterExchangeParam,
|
|
8
|
-
SimpleExchangeParam,
|
|
9
|
-
PoolLiquidity,
|
|
10
|
-
Logger,
|
|
11
|
-
NumberAsString,
|
|
12
|
-
DexExchangeParam,
|
|
13
|
-
} from '../../types';
|
|
14
|
-
import { SwapSide, Network } from '../../constants';
|
|
15
|
-
import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
|
|
16
|
-
import { getDexKeysWithNetwork } from '../../utils';
|
|
17
|
-
import { IDex } from '../../dex/idex';
|
|
18
|
-
import { IDexHelper } from '../../dex-helper/idex-helper';
|
|
19
|
-
import { WstETHData, PoolState, DexParams } from './types';
|
|
20
|
-
import { SimpleExchange } from '../simple-exchange';
|
|
21
|
-
import { WstETHConfig, Adapters } from './config';
|
|
22
|
-
import { uint256ToBigInt } from '../../lib/decoders';
|
|
23
|
-
import { Utils } from '../../utils';
|
|
24
|
-
import WSTETH_ABI from '../../abi/wstETH.json';
|
|
25
|
-
import STETH_ABI from '../../abi/stETH.json';
|
|
26
|
-
import { extractReturnAmountPosition } from '../../executor/utils';
|
|
27
|
-
|
|
28
|
-
export class WstETH extends SimpleExchange implements IDex<WstETHData> {
|
|
29
|
-
static readonly wstETHIface = new Interface(WSTETH_ABI);
|
|
30
|
-
static readonly stETHIface = new Interface(STETH_ABI);
|
|
31
|
-
|
|
32
|
-
protected config: DexParams;
|
|
33
|
-
|
|
34
|
-
readonly hasConstantPriceLargeAmounts = true;
|
|
35
|
-
|
|
36
|
-
readonly needWrapNative = false;
|
|
37
|
-
|
|
38
|
-
// There aren't actually fees on stETH but it is marked as such
|
|
39
|
-
readonly isFeeOnTransferSupported = true;
|
|
40
|
-
|
|
41
|
-
public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
|
|
42
|
-
getDexKeysWithNetwork(WstETHConfig);
|
|
43
|
-
|
|
44
|
-
logger: Logger;
|
|
45
|
-
|
|
46
|
-
private state: { blockNumber: number } & PoolState = {
|
|
47
|
-
blockNumber: 0,
|
|
48
|
-
totalPooledEther: 0n,
|
|
49
|
-
totalShares: 0n,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
constructor(
|
|
53
|
-
readonly network: Network,
|
|
54
|
-
readonly dexKey: string,
|
|
55
|
-
readonly dexHelper: IDexHelper,
|
|
56
|
-
protected adapters = Adapters[network] || {},
|
|
57
|
-
) {
|
|
58
|
-
super(dexHelper, dexKey);
|
|
59
|
-
const config = WstETHConfig[dexKey][network];
|
|
60
|
-
this.config = {
|
|
61
|
-
wstETHAddress: config.wstETHAddress.toLowerCase(),
|
|
62
|
-
stETHAddress: config.stETHAddress.toLowerCase(),
|
|
63
|
-
};
|
|
64
|
-
this.logger = dexHelper.getLogger(dexKey);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Returns the list of contract adapters (name and index)
|
|
68
|
-
// for a buy/sell. Return null if there are no adapters.
|
|
69
|
-
getAdapters(side: SwapSide): { name: string; index: number }[] | null {
|
|
70
|
-
return this.adapters[side] ? this.adapters[side] : null;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Not relevant for hasConstantPriceLargeAmounts exchanges
|
|
74
|
-
async getPoolIdentifiers(
|
|
75
|
-
srcToken: Token,
|
|
76
|
-
destToken: Token,
|
|
77
|
-
side: SwapSide,
|
|
78
|
-
_blockNumber: number,
|
|
79
|
-
): Promise<string[]> {
|
|
80
|
-
if (side === SwapSide.BUY) return [];
|
|
81
|
-
const srcTokenAddress = srcToken.address.toLowerCase();
|
|
82
|
-
const destTokenAddress = destToken.address.toLowerCase();
|
|
83
|
-
if (
|
|
84
|
-
!(
|
|
85
|
-
(srcTokenAddress === this.config.wstETHAddress &&
|
|
86
|
-
destTokenAddress === this.config.stETHAddress) ||
|
|
87
|
-
(srcTokenAddress === this.config.stETHAddress &&
|
|
88
|
-
destTokenAddress === this.config.wstETHAddress)
|
|
89
|
-
)
|
|
90
|
-
) {
|
|
91
|
-
return [];
|
|
92
|
-
}
|
|
93
|
-
return [this.dexKey];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
protected calcWrap = (amount: bigint): bigint =>
|
|
97
|
-
(amount * this.state.totalShares) / this.state.totalPooledEther;
|
|
98
|
-
|
|
99
|
-
protected calcUnwrap = (amount: bigint): bigint =>
|
|
100
|
-
(amount * this.state.totalPooledEther) / this.state.totalShares;
|
|
101
|
-
|
|
102
|
-
// Returns pool prices for amounts.
|
|
103
|
-
// limitPools always ignored due to hasConstantPriceLargeAmounts
|
|
104
|
-
async getPricesVolume(
|
|
105
|
-
srcToken: Token,
|
|
106
|
-
destToken: Token,
|
|
107
|
-
amounts: bigint[],
|
|
108
|
-
side: SwapSide,
|
|
109
|
-
blockNumber: number,
|
|
110
|
-
_limitPools?: string[],
|
|
111
|
-
): Promise<null | ExchangePrices<WstETHData>> {
|
|
112
|
-
if (side === SwapSide.BUY) return null;
|
|
113
|
-
const srcTokenAddress = srcToken.address.toLowerCase();
|
|
114
|
-
const destTokenAddress = destToken.address.toLowerCase();
|
|
115
|
-
if (
|
|
116
|
-
!(
|
|
117
|
-
(srcTokenAddress === this.config.wstETHAddress &&
|
|
118
|
-
destTokenAddress === this.config.stETHAddress) ||
|
|
119
|
-
(srcTokenAddress === this.config.stETHAddress &&
|
|
120
|
-
destTokenAddress === this.config.wstETHAddress)
|
|
121
|
-
)
|
|
122
|
-
) {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
const wrap = srcTokenAddress === this.config.stETHAddress;
|
|
126
|
-
|
|
127
|
-
if (blockNumber > this.state.blockNumber) {
|
|
128
|
-
const cached = await this.dexHelper.cache.get(
|
|
129
|
-
this.dexKey,
|
|
130
|
-
this.network,
|
|
131
|
-
'state',
|
|
132
|
-
);
|
|
133
|
-
if (cached) {
|
|
134
|
-
this.state = Utils.Parse(cached);
|
|
135
|
-
}
|
|
136
|
-
if (blockNumber > this.state.blockNumber) {
|
|
137
|
-
const calls = [
|
|
138
|
-
{
|
|
139
|
-
target: this.config.stETHAddress,
|
|
140
|
-
callData: WstETH.stETHIface.encodeFunctionData(
|
|
141
|
-
'getTotalPooledEther',
|
|
142
|
-
),
|
|
143
|
-
decodeFunction: uint256ToBigInt,
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
target: this.config.stETHAddress,
|
|
147
|
-
callData: WstETH.stETHIface.encodeFunctionData('getTotalShares'),
|
|
148
|
-
decodeFunction: uint256ToBigInt,
|
|
149
|
-
},
|
|
150
|
-
];
|
|
151
|
-
const results = await this.dexHelper.multiWrapper.tryAggregate<bigint>(
|
|
152
|
-
true,
|
|
153
|
-
calls,
|
|
154
|
-
blockNumber,
|
|
155
|
-
);
|
|
156
|
-
this.state = {
|
|
157
|
-
blockNumber,
|
|
158
|
-
totalPooledEther: results[0].returnData,
|
|
159
|
-
totalShares: results[1].returnData,
|
|
160
|
-
};
|
|
161
|
-
this.dexHelper.cache.setex(
|
|
162
|
-
this.dexKey,
|
|
163
|
-
this.network,
|
|
164
|
-
'state',
|
|
165
|
-
60,
|
|
166
|
-
Utils.Serialize(this.state),
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const calc = wrap ? this.calcWrap : this.calcUnwrap;
|
|
172
|
-
return [
|
|
173
|
-
{
|
|
174
|
-
unit: calc(1000000000000000000n),
|
|
175
|
-
prices: amounts.map(calc),
|
|
176
|
-
data: {},
|
|
177
|
-
poolAddresses: [this.config.wstETHAddress],
|
|
178
|
-
exchange: this.dexKey,
|
|
179
|
-
gasCost: wrap ? 60000 : 70000,
|
|
180
|
-
poolIdentifier: this.dexKey,
|
|
181
|
-
},
|
|
182
|
-
];
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Returns estimated gas cost of calldata for this DEX in multiSwap
|
|
186
|
-
getCalldataGasCost(_poolPrices: PoolPrices<WstETHData>): number | number[] {
|
|
187
|
-
return CALLDATA_GAS_COST.DEX_NO_PAYLOAD;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Encode params required by the exchange adapter
|
|
191
|
-
// Used for multiSwap, buy & megaSwap
|
|
192
|
-
// Hint: abiCoder.encodeParameter() could be useful
|
|
193
|
-
getAdapterParam(
|
|
194
|
-
_srcToken: string,
|
|
195
|
-
_destToken: string,
|
|
196
|
-
_srcAmount: string,
|
|
197
|
-
_destAmount: string,
|
|
198
|
-
_data: WstETHData,
|
|
199
|
-
_side: SwapSide,
|
|
200
|
-
): AdapterExchangeParam {
|
|
201
|
-
return {
|
|
202
|
-
targetExchange: this.config.wstETHAddress,
|
|
203
|
-
payload: '0x',
|
|
204
|
-
networkFee: '0',
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Encode call data used by simpleSwap like routers
|
|
209
|
-
// Used for simpleSwap & simpleBuy
|
|
210
|
-
// Hint: this.buildSimpleParamWithoutWETHConversion
|
|
211
|
-
// could be useful
|
|
212
|
-
async getSimpleParam(
|
|
213
|
-
srcToken: string,
|
|
214
|
-
_destToken: string,
|
|
215
|
-
srcAmount: string,
|
|
216
|
-
_destAmount: string,
|
|
217
|
-
_data: WstETHData,
|
|
218
|
-
_side: SwapSide,
|
|
219
|
-
): Promise<SimpleExchangeParam> {
|
|
220
|
-
if (srcToken.toLowerCase() === this.config.stETHAddress) {
|
|
221
|
-
const approveParam = await this.getApproveSimpleParam(
|
|
222
|
-
this.config.stETHAddress,
|
|
223
|
-
this.config.wstETHAddress,
|
|
224
|
-
srcAmount,
|
|
225
|
-
);
|
|
226
|
-
return {
|
|
227
|
-
callees: [...approveParam.callees, this.config.wstETHAddress],
|
|
228
|
-
calldata: [
|
|
229
|
-
...approveParam.calldata,
|
|
230
|
-
WstETH.wstETHIface.encodeFunctionData('wrap', [srcAmount]),
|
|
231
|
-
],
|
|
232
|
-
values: [...approveParam.values, '0'],
|
|
233
|
-
networkFee: '0',
|
|
234
|
-
};
|
|
235
|
-
} else {
|
|
236
|
-
return {
|
|
237
|
-
callees: [this.config.wstETHAddress],
|
|
238
|
-
calldata: [
|
|
239
|
-
WstETH.wstETHIface.encodeFunctionData('unwrap', [srcAmount]),
|
|
240
|
-
],
|
|
241
|
-
values: ['0'],
|
|
242
|
-
networkFee: '0',
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
async getDexParam(
|
|
248
|
-
srcToken: Address,
|
|
249
|
-
destToken: Address,
|
|
250
|
-
srcAmount: NumberAsString,
|
|
251
|
-
destAmount: NumberAsString,
|
|
252
|
-
recipient: Address,
|
|
253
|
-
data: WstETHData,
|
|
254
|
-
side: SwapSide,
|
|
255
|
-
): Promise<DexExchangeParam> {
|
|
256
|
-
const swapFunction =
|
|
257
|
-
srcToken.toLowerCase() === this.config.stETHAddress ? 'wrap' : 'unwrap';
|
|
258
|
-
const exchangeData = WstETH.wstETHIface.encodeFunctionData(swapFunction, [
|
|
259
|
-
srcAmount,
|
|
260
|
-
]);
|
|
261
|
-
|
|
262
|
-
return {
|
|
263
|
-
needWrapNative: this.needWrapNative,
|
|
264
|
-
dexFuncHasRecipient: false,
|
|
265
|
-
exchangeData,
|
|
266
|
-
targetExchange: this.config.wstETHAddress,
|
|
267
|
-
returnAmountPos:
|
|
268
|
-
side === SwapSide.SELL
|
|
269
|
-
? extractReturnAmountPosition(WstETH.wstETHIface, swapFunction)
|
|
270
|
-
: undefined,
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Returns list of top pools based on liquidity. Max
|
|
275
|
-
// limit number pools should be returned.
|
|
276
|
-
async getTopPoolsForToken(
|
|
277
|
-
tokenAddress: Address,
|
|
278
|
-
_limit: number,
|
|
279
|
-
): Promise<PoolLiquidity[]> {
|
|
280
|
-
tokenAddress = tokenAddress.toLowerCase();
|
|
281
|
-
if (
|
|
282
|
-
tokenAddress !== this.config.stETHAddress &&
|
|
283
|
-
tokenAddress !== this.config.wstETHAddress
|
|
284
|
-
) {
|
|
285
|
-
return [];
|
|
286
|
-
}
|
|
287
|
-
return [
|
|
288
|
-
{
|
|
289
|
-
exchange: this.dexKey,
|
|
290
|
-
address: this.config.wstETHAddress,
|
|
291
|
-
connectorTokens: [
|
|
292
|
-
{
|
|
293
|
-
decimals: 18,
|
|
294
|
-
address:
|
|
295
|
-
tokenAddress === this.config.stETHAddress
|
|
296
|
-
? this.config.wstETHAddress
|
|
297
|
-
: this.config.stETHAddress,
|
|
298
|
-
},
|
|
299
|
-
],
|
|
300
|
-
liquidityUSD: 1000000000, // Just returning a big number so this DEX will be preferred
|
|
301
|
-
},
|
|
302
|
-
];
|
|
303
|
-
}
|
|
304
|
-
}
|
|
1
|
+
import { Interface } from '@ethersproject/abi';
|
|
2
|
+
import {
|
|
3
|
+
Token,
|
|
4
|
+
Address,
|
|
5
|
+
ExchangePrices,
|
|
6
|
+
PoolPrices,
|
|
7
|
+
AdapterExchangeParam,
|
|
8
|
+
SimpleExchangeParam,
|
|
9
|
+
PoolLiquidity,
|
|
10
|
+
Logger,
|
|
11
|
+
NumberAsString,
|
|
12
|
+
DexExchangeParam,
|
|
13
|
+
} from '../../types';
|
|
14
|
+
import { SwapSide, Network } from '../../constants';
|
|
15
|
+
import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
|
|
16
|
+
import { getDexKeysWithNetwork } from '../../utils';
|
|
17
|
+
import { IDex } from '../../dex/idex';
|
|
18
|
+
import { IDexHelper } from '../../dex-helper/idex-helper';
|
|
19
|
+
import { WstETHData, PoolState, DexParams } from './types';
|
|
20
|
+
import { SimpleExchange } from '../simple-exchange';
|
|
21
|
+
import { WstETHConfig, Adapters } from './config';
|
|
22
|
+
import { uint256ToBigInt } from '../../lib/decoders';
|
|
23
|
+
import { Utils } from '../../utils';
|
|
24
|
+
import WSTETH_ABI from '../../abi/wstETH.json';
|
|
25
|
+
import STETH_ABI from '../../abi/stETH.json';
|
|
26
|
+
import { extractReturnAmountPosition } from '../../executor/utils';
|
|
27
|
+
|
|
28
|
+
export class WstETH extends SimpleExchange implements IDex<WstETHData> {
|
|
29
|
+
static readonly wstETHIface = new Interface(WSTETH_ABI);
|
|
30
|
+
static readonly stETHIface = new Interface(STETH_ABI);
|
|
31
|
+
|
|
32
|
+
protected config: DexParams;
|
|
33
|
+
|
|
34
|
+
readonly hasConstantPriceLargeAmounts = true;
|
|
35
|
+
|
|
36
|
+
readonly needWrapNative = false;
|
|
37
|
+
|
|
38
|
+
// There aren't actually fees on stETH but it is marked as such
|
|
39
|
+
readonly isFeeOnTransferSupported = true;
|
|
40
|
+
|
|
41
|
+
public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
|
|
42
|
+
getDexKeysWithNetwork(WstETHConfig);
|
|
43
|
+
|
|
44
|
+
logger: Logger;
|
|
45
|
+
|
|
46
|
+
private state: { blockNumber: number } & PoolState = {
|
|
47
|
+
blockNumber: 0,
|
|
48
|
+
totalPooledEther: 0n,
|
|
49
|
+
totalShares: 0n,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
readonly network: Network,
|
|
54
|
+
readonly dexKey: string,
|
|
55
|
+
readonly dexHelper: IDexHelper,
|
|
56
|
+
protected adapters = Adapters[network] || {},
|
|
57
|
+
) {
|
|
58
|
+
super(dexHelper, dexKey);
|
|
59
|
+
const config = WstETHConfig[dexKey][network];
|
|
60
|
+
this.config = {
|
|
61
|
+
wstETHAddress: config.wstETHAddress.toLowerCase(),
|
|
62
|
+
stETHAddress: config.stETHAddress.toLowerCase(),
|
|
63
|
+
};
|
|
64
|
+
this.logger = dexHelper.getLogger(dexKey);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Returns the list of contract adapters (name and index)
|
|
68
|
+
// for a buy/sell. Return null if there are no adapters.
|
|
69
|
+
getAdapters(side: SwapSide): { name: string; index: number }[] | null {
|
|
70
|
+
return this.adapters[side] ? this.adapters[side] : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Not relevant for hasConstantPriceLargeAmounts exchanges
|
|
74
|
+
async getPoolIdentifiers(
|
|
75
|
+
srcToken: Token,
|
|
76
|
+
destToken: Token,
|
|
77
|
+
side: SwapSide,
|
|
78
|
+
_blockNumber: number,
|
|
79
|
+
): Promise<string[]> {
|
|
80
|
+
if (side === SwapSide.BUY) return [];
|
|
81
|
+
const srcTokenAddress = srcToken.address.toLowerCase();
|
|
82
|
+
const destTokenAddress = destToken.address.toLowerCase();
|
|
83
|
+
if (
|
|
84
|
+
!(
|
|
85
|
+
(srcTokenAddress === this.config.wstETHAddress &&
|
|
86
|
+
destTokenAddress === this.config.stETHAddress) ||
|
|
87
|
+
(srcTokenAddress === this.config.stETHAddress &&
|
|
88
|
+
destTokenAddress === this.config.wstETHAddress)
|
|
89
|
+
)
|
|
90
|
+
) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
return [this.dexKey];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
protected calcWrap = (amount: bigint): bigint =>
|
|
97
|
+
(amount * this.state.totalShares) / this.state.totalPooledEther;
|
|
98
|
+
|
|
99
|
+
protected calcUnwrap = (amount: bigint): bigint =>
|
|
100
|
+
(amount * this.state.totalPooledEther) / this.state.totalShares;
|
|
101
|
+
|
|
102
|
+
// Returns pool prices for amounts.
|
|
103
|
+
// limitPools always ignored due to hasConstantPriceLargeAmounts
|
|
104
|
+
async getPricesVolume(
|
|
105
|
+
srcToken: Token,
|
|
106
|
+
destToken: Token,
|
|
107
|
+
amounts: bigint[],
|
|
108
|
+
side: SwapSide,
|
|
109
|
+
blockNumber: number,
|
|
110
|
+
_limitPools?: string[],
|
|
111
|
+
): Promise<null | ExchangePrices<WstETHData>> {
|
|
112
|
+
if (side === SwapSide.BUY) return null;
|
|
113
|
+
const srcTokenAddress = srcToken.address.toLowerCase();
|
|
114
|
+
const destTokenAddress = destToken.address.toLowerCase();
|
|
115
|
+
if (
|
|
116
|
+
!(
|
|
117
|
+
(srcTokenAddress === this.config.wstETHAddress &&
|
|
118
|
+
destTokenAddress === this.config.stETHAddress) ||
|
|
119
|
+
(srcTokenAddress === this.config.stETHAddress &&
|
|
120
|
+
destTokenAddress === this.config.wstETHAddress)
|
|
121
|
+
)
|
|
122
|
+
) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const wrap = srcTokenAddress === this.config.stETHAddress;
|
|
126
|
+
|
|
127
|
+
if (blockNumber > this.state.blockNumber) {
|
|
128
|
+
const cached = await this.dexHelper.cache.get(
|
|
129
|
+
this.dexKey,
|
|
130
|
+
this.network,
|
|
131
|
+
'state',
|
|
132
|
+
);
|
|
133
|
+
if (cached) {
|
|
134
|
+
this.state = Utils.Parse(cached);
|
|
135
|
+
}
|
|
136
|
+
if (blockNumber > this.state.blockNumber) {
|
|
137
|
+
const calls = [
|
|
138
|
+
{
|
|
139
|
+
target: this.config.stETHAddress,
|
|
140
|
+
callData: WstETH.stETHIface.encodeFunctionData(
|
|
141
|
+
'getTotalPooledEther',
|
|
142
|
+
),
|
|
143
|
+
decodeFunction: uint256ToBigInt,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
target: this.config.stETHAddress,
|
|
147
|
+
callData: WstETH.stETHIface.encodeFunctionData('getTotalShares'),
|
|
148
|
+
decodeFunction: uint256ToBigInt,
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
const results = await this.dexHelper.multiWrapper.tryAggregate<bigint>(
|
|
152
|
+
true,
|
|
153
|
+
calls,
|
|
154
|
+
blockNumber,
|
|
155
|
+
);
|
|
156
|
+
this.state = {
|
|
157
|
+
blockNumber,
|
|
158
|
+
totalPooledEther: results[0].returnData,
|
|
159
|
+
totalShares: results[1].returnData,
|
|
160
|
+
};
|
|
161
|
+
this.dexHelper.cache.setex(
|
|
162
|
+
this.dexKey,
|
|
163
|
+
this.network,
|
|
164
|
+
'state',
|
|
165
|
+
60,
|
|
166
|
+
Utils.Serialize(this.state),
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const calc = wrap ? this.calcWrap : this.calcUnwrap;
|
|
172
|
+
return [
|
|
173
|
+
{
|
|
174
|
+
unit: calc(1000000000000000000n),
|
|
175
|
+
prices: amounts.map(calc),
|
|
176
|
+
data: {},
|
|
177
|
+
poolAddresses: [this.config.wstETHAddress],
|
|
178
|
+
exchange: this.dexKey,
|
|
179
|
+
gasCost: wrap ? 60000 : 70000,
|
|
180
|
+
poolIdentifier: this.dexKey,
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Returns estimated gas cost of calldata for this DEX in multiSwap
|
|
186
|
+
getCalldataGasCost(_poolPrices: PoolPrices<WstETHData>): number | number[] {
|
|
187
|
+
return CALLDATA_GAS_COST.DEX_NO_PAYLOAD;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Encode params required by the exchange adapter
|
|
191
|
+
// Used for multiSwap, buy & megaSwap
|
|
192
|
+
// Hint: abiCoder.encodeParameter() could be useful
|
|
193
|
+
getAdapterParam(
|
|
194
|
+
_srcToken: string,
|
|
195
|
+
_destToken: string,
|
|
196
|
+
_srcAmount: string,
|
|
197
|
+
_destAmount: string,
|
|
198
|
+
_data: WstETHData,
|
|
199
|
+
_side: SwapSide,
|
|
200
|
+
): AdapterExchangeParam {
|
|
201
|
+
return {
|
|
202
|
+
targetExchange: this.config.wstETHAddress,
|
|
203
|
+
payload: '0x',
|
|
204
|
+
networkFee: '0',
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Encode call data used by simpleSwap like routers
|
|
209
|
+
// Used for simpleSwap & simpleBuy
|
|
210
|
+
// Hint: this.buildSimpleParamWithoutWETHConversion
|
|
211
|
+
// could be useful
|
|
212
|
+
async getSimpleParam(
|
|
213
|
+
srcToken: string,
|
|
214
|
+
_destToken: string,
|
|
215
|
+
srcAmount: string,
|
|
216
|
+
_destAmount: string,
|
|
217
|
+
_data: WstETHData,
|
|
218
|
+
_side: SwapSide,
|
|
219
|
+
): Promise<SimpleExchangeParam> {
|
|
220
|
+
if (srcToken.toLowerCase() === this.config.stETHAddress) {
|
|
221
|
+
const approveParam = await this.getApproveSimpleParam(
|
|
222
|
+
this.config.stETHAddress,
|
|
223
|
+
this.config.wstETHAddress,
|
|
224
|
+
srcAmount,
|
|
225
|
+
);
|
|
226
|
+
return {
|
|
227
|
+
callees: [...approveParam.callees, this.config.wstETHAddress],
|
|
228
|
+
calldata: [
|
|
229
|
+
...approveParam.calldata,
|
|
230
|
+
WstETH.wstETHIface.encodeFunctionData('wrap', [srcAmount]),
|
|
231
|
+
],
|
|
232
|
+
values: [...approveParam.values, '0'],
|
|
233
|
+
networkFee: '0',
|
|
234
|
+
};
|
|
235
|
+
} else {
|
|
236
|
+
return {
|
|
237
|
+
callees: [this.config.wstETHAddress],
|
|
238
|
+
calldata: [
|
|
239
|
+
WstETH.wstETHIface.encodeFunctionData('unwrap', [srcAmount]),
|
|
240
|
+
],
|
|
241
|
+
values: ['0'],
|
|
242
|
+
networkFee: '0',
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async getDexParam(
|
|
248
|
+
srcToken: Address,
|
|
249
|
+
destToken: Address,
|
|
250
|
+
srcAmount: NumberAsString,
|
|
251
|
+
destAmount: NumberAsString,
|
|
252
|
+
recipient: Address,
|
|
253
|
+
data: WstETHData,
|
|
254
|
+
side: SwapSide,
|
|
255
|
+
): Promise<DexExchangeParam> {
|
|
256
|
+
const swapFunction =
|
|
257
|
+
srcToken.toLowerCase() === this.config.stETHAddress ? 'wrap' : 'unwrap';
|
|
258
|
+
const exchangeData = WstETH.wstETHIface.encodeFunctionData(swapFunction, [
|
|
259
|
+
srcAmount,
|
|
260
|
+
]);
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
needWrapNative: this.needWrapNative,
|
|
264
|
+
dexFuncHasRecipient: false,
|
|
265
|
+
exchangeData,
|
|
266
|
+
targetExchange: this.config.wstETHAddress,
|
|
267
|
+
returnAmountPos:
|
|
268
|
+
side === SwapSide.SELL
|
|
269
|
+
? extractReturnAmountPosition(WstETH.wstETHIface, swapFunction)
|
|
270
|
+
: undefined,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Returns list of top pools based on liquidity. Max
|
|
275
|
+
// limit number pools should be returned.
|
|
276
|
+
async getTopPoolsForToken(
|
|
277
|
+
tokenAddress: Address,
|
|
278
|
+
_limit: number,
|
|
279
|
+
): Promise<PoolLiquidity[]> {
|
|
280
|
+
tokenAddress = tokenAddress.toLowerCase();
|
|
281
|
+
if (
|
|
282
|
+
tokenAddress !== this.config.stETHAddress &&
|
|
283
|
+
tokenAddress !== this.config.wstETHAddress
|
|
284
|
+
) {
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
287
|
+
return [
|
|
288
|
+
{
|
|
289
|
+
exchange: this.dexKey,
|
|
290
|
+
address: this.config.wstETHAddress,
|
|
291
|
+
connectorTokens: [
|
|
292
|
+
{
|
|
293
|
+
decimals: 18,
|
|
294
|
+
address:
|
|
295
|
+
tokenAddress === this.config.stETHAddress
|
|
296
|
+
? this.config.wstETHAddress
|
|
297
|
+
: this.config.stETHAddress,
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
liquidityUSD: 1000000000, // Just returning a big number so this DEX will be preferred
|
|
301
|
+
},
|
|
302
|
+
];
|
|
303
|
+
}
|
|
304
|
+
}
|