@paraswap/dex-lib 4.7.14-multi-route.1 → 4.7.14-multi-route.3
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/build/dex/simple-exchange.js +7 -1
- package/build/dex/simple-exchange.js.map +1 -1
- package/build/executor/Executor01BytecodeBuilder.d.ts +6 -6
- package/build/executor/Executor01BytecodeBuilder.js +6 -3
- package/build/executor/Executor01BytecodeBuilder.js.map +1 -1
- package/build/executor/Executor02BytecodeBuilder.d.ts +5 -5
- package/build/executor/Executor02BytecodeBuilder.js +6 -3
- package/build/executor/Executor02BytecodeBuilder.js.map +1 -1
- package/build/executor/Executor02BytecodeBuilderMultiRoute.d.ts +91 -0
- package/build/executor/Executor02BytecodeBuilderMultiRoute.js +744 -0
- package/build/executor/Executor02BytecodeBuilderMultiRoute.js.map +1 -0
- package/build/executor/Executor03BytecodeBuilder.d.ts +6 -6
- package/build/executor/Executor03BytecodeBuilder.js +5 -3
- package/build/executor/Executor03BytecodeBuilder.js.map +1 -1
- package/build/executor/ExecutorBytecodeBuilder.d.ts +19 -7
- package/build/executor/ExecutorBytecodeBuilder.js +18 -5
- package/build/executor/ExecutorBytecodeBuilder.js.map +1 -1
- package/build/executor/ExecutorDetector.d.ts +2 -1
- package/build/executor/ExecutorDetector.js +10 -4
- package/build/executor/ExecutorDetector.js.map +1 -1
- package/build/executor/types.d.ts +13 -6
- package/build/executor/types.js +1 -0
- package/build/executor/types.js.map +1 -1
- package/build/generic-swap-transaction-builder.d.ts +2 -2
- package/build/generic-swap-transaction-builder.js +20 -10
- package/build/generic-swap-transaction-builder.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Executor02BytecodeBuilderMultiRoute = void 0;
|
|
4
|
+
const ethers_1 = require("ethers");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
const ExecutorBytecodeBuilder_1 = require("./ExecutorBytecodeBuilder");
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
const { utils: { hexlify, hexDataLength, hexConcat, hexZeroPad, solidityPack }, } = ethers_1.ethers;
|
|
10
|
+
/**
|
|
11
|
+
* Class to build bytecode for Executor02 - simpleSwap with N DEXs (VERTICAL_BRANCH), multiSwaps (VERTICAL_BRANCH_HORIZONTAL_SEQUENCE) and megaswaps (NESTED_VERTICAL_BRANCH_HORIZONTAL_SEQUENCE)
|
|
12
|
+
*/
|
|
13
|
+
class Executor02BytecodeBuilderMultiRoute extends ExecutorBytecodeBuilder_1.ExecutorBytecodeBuilder {
|
|
14
|
+
type = types_1.Executors.TWO;
|
|
15
|
+
/**
|
|
16
|
+
* Executor02 Flags:
|
|
17
|
+
* switch (flag % 4):
|
|
18
|
+
* case 0: don't instert fromAmount
|
|
19
|
+
* case 1: sendEth equal to fromAmount
|
|
20
|
+
* case 2: sendEth equal to fromAmount + insert fromAmount
|
|
21
|
+
* case 3: insert fromAmount
|
|
22
|
+
|
|
23
|
+
* switch (flag % 3):
|
|
24
|
+
* case 0: don't check balance after swap
|
|
25
|
+
* case 1: check eth balance after swap
|
|
26
|
+
* case 2: check destToken balance after swap
|
|
27
|
+
*/
|
|
28
|
+
buildSimpleSwapFlags(params) {
|
|
29
|
+
const { maybeWethCallData, swapExchange, swap } = params;
|
|
30
|
+
const { srcToken, destToken } = swap;
|
|
31
|
+
const isEthSrc = (0, utils_1.isETHAddress)(srcToken);
|
|
32
|
+
const isEthDest = (0, utils_1.isETHAddress)(destToken);
|
|
33
|
+
const exchangeParam = swapExchange.build.dexParams;
|
|
34
|
+
const { dexFuncHasRecipient, needWrapNative, specialDexFlag, specialDexSupportsInsertFromAmount, swappedAmountNotPresentInExchangeData, preSwapUnwrapCalldata, sendEthButSupportsInsertFromAmount, } = exchangeParam;
|
|
35
|
+
const needWrap = needWrapNative && isEthSrc && maybeWethCallData?.deposit;
|
|
36
|
+
const needUnwrap = needWrapNative && isEthDest && maybeWethCallData?.withdraw;
|
|
37
|
+
const isSpecialDex = specialDexFlag !== undefined && specialDexFlag !== types_1.SpecialDex.DEFAULT;
|
|
38
|
+
const forcePreventInsertFromAmount = swappedAmountNotPresentInExchangeData ||
|
|
39
|
+
(isSpecialDex && !specialDexSupportsInsertFromAmount);
|
|
40
|
+
let dexFlag = forcePreventInsertFromAmount
|
|
41
|
+
? types_1.Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP
|
|
42
|
+
: types_1.Flag.INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP; // 0 or 3
|
|
43
|
+
let approveFlag = types_1.Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP; // 0
|
|
44
|
+
if (isEthSrc && !needWrap) {
|
|
45
|
+
dexFlag = dexFuncHasRecipient
|
|
46
|
+
? !sendEthButSupportsInsertFromAmount
|
|
47
|
+
? types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP // 9
|
|
48
|
+
: types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_PLUS_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP // 18
|
|
49
|
+
: !sendEthButSupportsInsertFromAmount
|
|
50
|
+
? types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP // 5
|
|
51
|
+
: types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_PLUS_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP; // 18
|
|
52
|
+
}
|
|
53
|
+
else if (isEthDest && !needUnwrap) {
|
|
54
|
+
dexFlag = forcePreventInsertFromAmount
|
|
55
|
+
? types_1.Flag.DONT_INSERT_FROM_AMOUNT_CHECK_ETH_BALANCE_AFTER_SWAP
|
|
56
|
+
: types_1.Flag.INSERT_FROM_AMOUNT_CHECK_ETH_BALANCE_AFTER_SWAP; // 4 or 7
|
|
57
|
+
}
|
|
58
|
+
else if (!dexFuncHasRecipient || (isEthDest && needUnwrap)) {
|
|
59
|
+
dexFlag = forcePreventInsertFromAmount
|
|
60
|
+
? types_1.Flag.DONT_INSERT_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP
|
|
61
|
+
: types_1.Flag.INSERT_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP; // 8 or 11
|
|
62
|
+
}
|
|
63
|
+
// Actual srcToken is eth, because we'll unwrap weth before swap.
|
|
64
|
+
// Need to check balance, some dexes don't have 1:1 ETH -> custom_ETH rate
|
|
65
|
+
if (preSwapUnwrapCalldata) {
|
|
66
|
+
dexFlag =
|
|
67
|
+
types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
dexFlag,
|
|
71
|
+
approveFlag,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Executor02 Flags:
|
|
76
|
+
* switch (flag % 4):
|
|
77
|
+
* case 0: don't instert fromAmount
|
|
78
|
+
* case 1: sendEth equal to fromAmount
|
|
79
|
+
* case 2: sendEth equal to fromAmount + insert fromAmount
|
|
80
|
+
* case 3: insert fromAmount
|
|
81
|
+
|
|
82
|
+
* switch (flag % 3):
|
|
83
|
+
* case 0: don't check balance after swap
|
|
84
|
+
* case 1: check eth balance after swap
|
|
85
|
+
* case 2: check destToken balance after swap
|
|
86
|
+
*/
|
|
87
|
+
buildMultiMegaSwapFlags(params) {
|
|
88
|
+
const { singleRoutes, swap, swapExchange, maybeWethCallData, routeIndex, swapIndex, swapExchangeIndex, } = params;
|
|
89
|
+
const route = singleRoutes[routeIndex];
|
|
90
|
+
const exchangeParam = swapExchange.build.dexParams;
|
|
91
|
+
const { srcToken, destToken } = swap;
|
|
92
|
+
const applyVerticalBranching = this.doesSwapNeedToBeAsVerticalBranch(singleRoutes, routeIndex, swap);
|
|
93
|
+
const isHorizontalSequence = route.swaps.length > 1; // check if route is a multi-swap (horizontal sequence)
|
|
94
|
+
const isFirstSwap = swapIndex === 0;
|
|
95
|
+
const isLastSwap = !isFirstSwap && swapIndex === route.swaps.length - 1;
|
|
96
|
+
const { dexFuncHasRecipient, needWrapNative, specialDexFlag, specialDexSupportsInsertFromAmount, swappedAmountNotPresentInExchangeData, wethAddress, sendEthButSupportsInsertFromAmount, preSwapUnwrapCalldata, } = exchangeParam;
|
|
97
|
+
const isEthSrc = (0, utils_1.isETHAddress)(srcToken);
|
|
98
|
+
const isEthDest = (0, utils_1.isETHAddress)(destToken);
|
|
99
|
+
const isWethDest = (wethAddress && destToken.toLowerCase() === wethAddress.toLowerCase()) ||
|
|
100
|
+
this.dexHelper.config.isWETH(destToken);
|
|
101
|
+
const isSpecialDex = specialDexFlag !== undefined && specialDexFlag !== types_1.SpecialDex.DEFAULT;
|
|
102
|
+
const forcePreventInsertFromAmount = swappedAmountNotPresentInExchangeData ||
|
|
103
|
+
(isSpecialDex && !specialDexSupportsInsertFromAmount);
|
|
104
|
+
const forceBalanceOfCheck = (isSpecialDex &&
|
|
105
|
+
isHorizontalSequence &&
|
|
106
|
+
!applyVerticalBranching &&
|
|
107
|
+
!isLastSwap) ||
|
|
108
|
+
!dexFuncHasRecipient;
|
|
109
|
+
const needUnwrap = needWrapNative && isEthDest && maybeWethCallData?.withdraw;
|
|
110
|
+
const needSendEth = isEthSrc && !needWrapNative;
|
|
111
|
+
const needCheckEthBalance = isEthDest && !needWrapNative;
|
|
112
|
+
const anyDexOnSwapDoesntNeedWrapNative = this.anyDexOnSwapDoesntNeedWrapNative(swap);
|
|
113
|
+
// check if current exchange is the last with needWrapNative
|
|
114
|
+
const isLastExchangeWithNeedWrapNative = this.isLastExchangeWithNeedWrapNative(swap, swapExchangeIndex);
|
|
115
|
+
// for the first part, basically replicates the logic from `unwrap after last swap` in buildSingleSwapExchangeCallData
|
|
116
|
+
const needCheckSrcTokenBalanceOf = (needUnwrap &&
|
|
117
|
+
(!applyVerticalBranching ||
|
|
118
|
+
(applyVerticalBranching && anyDexOnSwapDoesntNeedWrapNative)) &&
|
|
119
|
+
(isLastExchangeWithNeedWrapNative || exchangeParam.wethAddress)) ||
|
|
120
|
+
(isHorizontalSequence && !applyVerticalBranching && !isLastSwap);
|
|
121
|
+
let dexFlag;
|
|
122
|
+
let approveFlag = types_1.Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP; // 0
|
|
123
|
+
if (needSendEth) {
|
|
124
|
+
const preventInsertForSendEth = forcePreventInsertFromAmount || !sendEthButSupportsInsertFromAmount;
|
|
125
|
+
dexFlag =
|
|
126
|
+
needCheckSrcTokenBalanceOf || forceBalanceOfCheck
|
|
127
|
+
? preventInsertForSendEth
|
|
128
|
+
? types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP // 5
|
|
129
|
+
: types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_PLUS_INSERT_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP // 14
|
|
130
|
+
: dexFuncHasRecipient
|
|
131
|
+
? preventInsertForSendEth
|
|
132
|
+
? types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP // 9
|
|
133
|
+
: types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_PLUS_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP // 18
|
|
134
|
+
: preventInsertForSendEth
|
|
135
|
+
? types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP // 5
|
|
136
|
+
: types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_PLUS_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP; // 18
|
|
137
|
+
}
|
|
138
|
+
else if (needCheckEthBalance) {
|
|
139
|
+
dexFlag =
|
|
140
|
+
needCheckSrcTokenBalanceOf || forceBalanceOfCheck
|
|
141
|
+
? forcePreventInsertFromAmount && dexFuncHasRecipient
|
|
142
|
+
? types_1.Flag.DONT_INSERT_FROM_AMOUNT_CHECK_ETH_BALANCE_AFTER_SWAP // 4
|
|
143
|
+
: types_1.Flag.INSERT_FROM_AMOUNT_CHECK_ETH_BALANCE_AFTER_SWAP // 7
|
|
144
|
+
: forcePreventInsertFromAmount && dexFuncHasRecipient
|
|
145
|
+
? types_1.Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP // 0
|
|
146
|
+
: types_1.Flag.INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP; // 3
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
dexFlag =
|
|
150
|
+
needCheckSrcTokenBalanceOf || forceBalanceOfCheck
|
|
151
|
+
? forcePreventInsertFromAmount
|
|
152
|
+
? types_1.Flag.DONT_INSERT_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP // 8
|
|
153
|
+
: types_1.Flag.INSERT_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP // 11
|
|
154
|
+
: forcePreventInsertFromAmount
|
|
155
|
+
? types_1.Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP // 0
|
|
156
|
+
: types_1.Flag.INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP; // 3
|
|
157
|
+
}
|
|
158
|
+
// Actual srcToken is eth, because we'll unwrap weth before swap.
|
|
159
|
+
// Need to check balance, some dexes don't have 1:1 ETH -> custom_ETH rate
|
|
160
|
+
if (preSwapUnwrapCalldata) {
|
|
161
|
+
dexFlag =
|
|
162
|
+
types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP;
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
dexFlag,
|
|
166
|
+
approveFlag,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
buildDexCallData(params) {
|
|
170
|
+
const { singleRoutes, swapExchangeIndex, routeIndex, swapIndex, destToken, } = params;
|
|
171
|
+
const swap = singleRoutes[routeIndex].swaps[swapIndex];
|
|
172
|
+
const swapExchange = swap.swapExchanges[swapExchangeIndex];
|
|
173
|
+
const flag = swapExchange.build.dexFlag;
|
|
174
|
+
const exchangeParam = swap.swapExchanges[swapExchangeIndex].build.dexParams;
|
|
175
|
+
let { exchangeData, specialDexFlag, targetExchange, needWrapNative } = exchangeParam;
|
|
176
|
+
const routeNeedsRootUnwrapEth = this.doesRouteNeedsRootUnwrapEth(singleRoutes, destToken);
|
|
177
|
+
const needUnwrap =
|
|
178
|
+
// check if current exchange is the last with needWrapNative
|
|
179
|
+
this.isLastExchangeWithNeedWrapNative(swap, swapExchangeIndex) ||
|
|
180
|
+
exchangeParam.wethAddress;
|
|
181
|
+
const needUnwrapAfterLastSwapInRoute = needUnwrap &&
|
|
182
|
+
(0, utils_1.isETHAddress)(swap.destToken) &&
|
|
183
|
+
this.anyDexOnSwapDoesntNeedWrapNative(swap);
|
|
184
|
+
const returnAmountPos = exchangeParam.returnAmountPos !== undefined &&
|
|
185
|
+
!routeNeedsRootUnwrapEth &&
|
|
186
|
+
!needUnwrapAfterLastSwapInRoute // prevent returnAmoutPos optimisation if route needs root unwrap eth
|
|
187
|
+
? exchangeParam.returnAmountPos
|
|
188
|
+
: constants_1.DEFAULT_RETURN_AMOUNT_POS;
|
|
189
|
+
const applyVerticalBranching = this.doesSwapNeedToBeAsVerticalBranch(singleRoutes, routeIndex, swap);
|
|
190
|
+
const dontCheckBalanceAfterSwap = flag % 3 === 0;
|
|
191
|
+
const checkDestTokenBalanceAfterSwap = flag % 3 === 2;
|
|
192
|
+
const insertFromAmount = flag % 4 === 3 || flag % 4 === 2;
|
|
193
|
+
const srcTokenAddress = (0, utils_1.isETHAddress)(swap.srcToken) && needWrapNative
|
|
194
|
+
? this.getWETHAddress(exchangeParam)
|
|
195
|
+
: swap.srcToken.toLowerCase();
|
|
196
|
+
const destTokenAddress = (0, utils_1.isETHAddress)(swap.destToken) && needWrapNative
|
|
197
|
+
? this.getWETHAddress(exchangeParam)
|
|
198
|
+
: swap.destToken.toLowerCase();
|
|
199
|
+
exchangeData = this.addTokenAddressToCallData(exchangeData, srcTokenAddress);
|
|
200
|
+
if (applyVerticalBranching ||
|
|
201
|
+
(checkDestTokenBalanceAfterSwap && !dontCheckBalanceAfterSwap)) {
|
|
202
|
+
exchangeData = this.addTokenAddressToCallData(exchangeData, destTokenAddress);
|
|
203
|
+
}
|
|
204
|
+
let destTokenPos = 0;
|
|
205
|
+
if (checkDestTokenBalanceAfterSwap && !dontCheckBalanceAfterSwap) {
|
|
206
|
+
const destTokenAddrIndex = exchangeData
|
|
207
|
+
.replace('0x', '')
|
|
208
|
+
.indexOf(destTokenAddress.replace('0x', ''));
|
|
209
|
+
destTokenPos = (destTokenAddrIndex - 24) / 2;
|
|
210
|
+
}
|
|
211
|
+
let fromAmountPos = 0;
|
|
212
|
+
if (insertFromAmount) {
|
|
213
|
+
if (exchangeParam.insertFromAmountPos) {
|
|
214
|
+
fromAmountPos = exchangeParam.insertFromAmountPos;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
const fromAmount = ethers_1.ethers.utils.defaultAbiCoder.encode(['uint256'], [swapExchange.srcAmount]);
|
|
218
|
+
const fromAmountIndex = exchangeData
|
|
219
|
+
.replace('0x', '')
|
|
220
|
+
.indexOf(fromAmount.replace('0x', ''));
|
|
221
|
+
fromAmountPos =
|
|
222
|
+
(fromAmountIndex !== -1 ? fromAmountIndex : exchangeData.length) / 2;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return this.buildCallData(targetExchange, exchangeData, fromAmountPos, destTokenPos, specialDexFlag || types_1.SpecialDex.DEFAULT, flag, undefined, returnAmountPos);
|
|
226
|
+
}
|
|
227
|
+
wrapAsVerticalBranch(callData, percentage, swap, wrapWasAddedInSwapExchange, curExchangeParam = null, addedUnwrapForDexWithNoNeedWrapNative = false) {
|
|
228
|
+
let srcTokenAddress = swap.srcToken;
|
|
229
|
+
let doesAnyDexOnSwapNeedsWrapNative;
|
|
230
|
+
// if (exchangeParamIndex > -1) { // TODO-multi: what this case is about?
|
|
231
|
+
if (curExchangeParam) {
|
|
232
|
+
doesAnyDexOnSwapNeedsWrapNative =
|
|
233
|
+
(0, utils_1.isETHAddress)(srcTokenAddress) &&
|
|
234
|
+
(curExchangeParam.needWrapNative ||
|
|
235
|
+
(!curExchangeParam.needWrapNative &&
|
|
236
|
+
addedUnwrapForDexWithNoNeedWrapNative));
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
doesAnyDexOnSwapNeedsWrapNative =
|
|
240
|
+
(0, utils_1.isETHAddress)(srcTokenAddress) && this.anyDexOnSwapNeedsWrapNative(swap);
|
|
241
|
+
}
|
|
242
|
+
if (doesAnyDexOnSwapNeedsWrapNative &&
|
|
243
|
+
(0, utils_1.isETHAddress)(srcTokenAddress) &&
|
|
244
|
+
!wrapWasAddedInSwapExchange) {
|
|
245
|
+
srcTokenAddress =
|
|
246
|
+
// exchangeParamIndex > -1 TODO-multi
|
|
247
|
+
curExchangeParam
|
|
248
|
+
? this.getWETHAddress(curExchangeParam)
|
|
249
|
+
: this.dexHelper.config.data.wrappedNativeTokenAddress;
|
|
250
|
+
}
|
|
251
|
+
let srcTokenAddressLowered = srcTokenAddress.toLowerCase();
|
|
252
|
+
let srcTokenPos;
|
|
253
|
+
if (percentage === constants_1.SWAP_EXCHANGE_100_PERCENTAGE) {
|
|
254
|
+
srcTokenPos = hexZeroPad(hexlify(0), 8);
|
|
255
|
+
}
|
|
256
|
+
else if ((0, utils_1.isETHAddress)(srcTokenAddressLowered)) {
|
|
257
|
+
srcTokenPos = constants_1.ETH_SRC_TOKEN_POS_FOR_MULTISWAP_METADATA;
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
const srcTokenAddrIndex = callData
|
|
261
|
+
.replace('0x', '')
|
|
262
|
+
.indexOf(srcTokenAddressLowered.replace('0x', ''));
|
|
263
|
+
srcTokenPos = hexZeroPad(hexlify(srcTokenAddrIndex / 2), 8);
|
|
264
|
+
}
|
|
265
|
+
return solidityPack(['bytes16', 'bytes8', 'bytes8', 'bytes'], [
|
|
266
|
+
hexZeroPad(hexlify(hexDataLength(callData)), 16), // calldata size
|
|
267
|
+
srcTokenPos, // srcTokenPos
|
|
268
|
+
hexZeroPad(hexlify(Math.round(percentage * 100)), 8), // percentage
|
|
269
|
+
callData, // swap calldata
|
|
270
|
+
]);
|
|
271
|
+
}
|
|
272
|
+
packVerticalBranchingData(swapCallData) {
|
|
273
|
+
return solidityPack(['bytes28', 'bytes4', 'bytes32', 'bytes32', 'bytes'], [
|
|
274
|
+
constants_1.ZEROS_28_BYTES, // empty bytes28
|
|
275
|
+
constants_1.ZEROS_4_BYTES, // fallback selector
|
|
276
|
+
hexZeroPad(hexlify(32), 32), // calldata offset
|
|
277
|
+
hexZeroPad(hexlify(hexDataLength(swapCallData)), 32), // calldata length
|
|
278
|
+
swapCallData, // calldata
|
|
279
|
+
]);
|
|
280
|
+
}
|
|
281
|
+
packVerticalBranchingCallData(verticalBranchingData, fromAmountPos, destTokenPos, flag) {
|
|
282
|
+
return solidityPack([
|
|
283
|
+
'bytes20',
|
|
284
|
+
'bytes4',
|
|
285
|
+
'bytes2',
|
|
286
|
+
'bytes2',
|
|
287
|
+
'bytes1',
|
|
288
|
+
'bytes1',
|
|
289
|
+
'bytes2',
|
|
290
|
+
'bytes',
|
|
291
|
+
], [
|
|
292
|
+
constants_1.ZEROS_20_BYTES, // zero address. go to vertical branch, so no call is made
|
|
293
|
+
hexZeroPad(hexlify(hexDataLength(verticalBranchingData)), 4), // dex calldata length
|
|
294
|
+
hexZeroPad(hexlify(fromAmountPos), 2), // fromAmountPos
|
|
295
|
+
hexZeroPad(hexlify(destTokenPos), 2), // destTokenPos
|
|
296
|
+
hexZeroPad(hexlify(0), 1), // returnAmountPos
|
|
297
|
+
hexZeroPad(hexlify(types_1.SpecialDex.EXECUTE_VERTICAL_BRANCHING), 1), // special
|
|
298
|
+
hexZeroPad(hexlify(flag), 2), // flag
|
|
299
|
+
verticalBranchingData, // dexes calldata
|
|
300
|
+
]);
|
|
301
|
+
}
|
|
302
|
+
buildVerticalBranchingCallData(singleRoutes, swap, swapCallData, flag, isRoot = false) {
|
|
303
|
+
const destTokenAddrLowered = swap.destToken.toLowerCase();
|
|
304
|
+
const isEthDest = (0, utils_1.isETHAddress)(destTokenAddrLowered);
|
|
305
|
+
let anyDexOnSwapNeedsWrapNative = false;
|
|
306
|
+
let anyDexOnSwapDoesntNeedWrapNative = false;
|
|
307
|
+
let destTokenPos;
|
|
308
|
+
if (isEthDest) {
|
|
309
|
+
if (!isRoot) {
|
|
310
|
+
anyDexOnSwapNeedsWrapNative = this.anyDexOnSwapNeedsWrapNative(swap);
|
|
311
|
+
anyDexOnSwapDoesntNeedWrapNative =
|
|
312
|
+
this.anyDexOnSwapDoesntNeedWrapNative(swap);
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
anyDexOnSwapNeedsWrapNative = singleRoutes.some(route => this.anyDexOnSwapNeedsWrapNative(route.swaps[route.swaps.length - 1]));
|
|
316
|
+
anyDexOnSwapDoesntNeedWrapNative = singleRoutes.some(route => this.anyDexOnSwapDoesntNeedWrapNative(route.swaps[route.swaps.length - 1]));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// 'bytes28', 'bytes4', 'bytes32', 'bytes32', 'bytes'
|
|
320
|
+
const data = this.packVerticalBranchingData(swapCallData);
|
|
321
|
+
if (isEthDest &&
|
|
322
|
+
anyDexOnSwapDoesntNeedWrapNative &&
|
|
323
|
+
!anyDexOnSwapNeedsWrapNative) {
|
|
324
|
+
destTokenPos = 0;
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
const destTokenAddrIndex = data
|
|
328
|
+
.replace('0x', '')
|
|
329
|
+
.indexOf((isEthDest
|
|
330
|
+
? this.dexHelper.config.data.wrappedNativeTokenAddress.toLowerCase()
|
|
331
|
+
: destTokenAddrLowered.toLowerCase()).replace('0x', ''));
|
|
332
|
+
destTokenPos = destTokenAddrIndex / 2 - 40;
|
|
333
|
+
}
|
|
334
|
+
const fromAmountPos = hexDataLength(data) - 64 - 28; // 64 (position), 28 (selector padding);
|
|
335
|
+
return this.packVerticalBranchingCallData(data, fromAmountPos, destTokenPos < 0 ? 0 : destTokenPos, flag);
|
|
336
|
+
}
|
|
337
|
+
buildSingleSwapExchangeCallData(singleRoutes, routeIndex, swapIndex, swapExchangeIndex, addedWrapToSwapExchangeMap, allowToAddWrap = true, prevBranchWasWrapped = false, unwrapToSwapMap, srcToken, destToken, maybeWethCallData, hasMultipleSwapExchanges, isMultiOrMegaSwap) {
|
|
338
|
+
const isSimpleSwap = singleRoutes.length === 1 && singleRoutes[0].swaps.length === 1;
|
|
339
|
+
let swapExchangeCallData = '';
|
|
340
|
+
const swap = singleRoutes[routeIndex].swaps[swapIndex];
|
|
341
|
+
const swapExchange = swap.swapExchanges[swapExchangeIndex];
|
|
342
|
+
const curExchangeParam = swapExchange.build.dexParams;
|
|
343
|
+
const approveFlag = swapExchange.build.approveFlag;
|
|
344
|
+
const dexCallData = this.buildDexCallData({
|
|
345
|
+
singleRoutes,
|
|
346
|
+
routeIndex,
|
|
347
|
+
swapIndex,
|
|
348
|
+
swapExchangeIndex,
|
|
349
|
+
isLastSwap: false,
|
|
350
|
+
destToken,
|
|
351
|
+
// TODO-multi to be removed after refactoring
|
|
352
|
+
routes: [],
|
|
353
|
+
exchangeParams: [],
|
|
354
|
+
exchangeParamIndex: constants_1.NOT_EXISTING_EXCHANGE_PARAM_INDEX,
|
|
355
|
+
flag: types_1.Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP,
|
|
356
|
+
});
|
|
357
|
+
if (curExchangeParam.preSwapUnwrapCalldata) {
|
|
358
|
+
const withdrawCallData = this.buildUnwrapEthCallData(this.getWETHAddress(curExchangeParam), curExchangeParam.preSwapUnwrapCalldata);
|
|
359
|
+
swapExchangeCallData = hexConcat([withdrawCallData, dexCallData]);
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
swapExchangeCallData = hexConcat([dexCallData]);
|
|
363
|
+
}
|
|
364
|
+
const isLastSwap = swapIndex === singleRoutes[routeIndex].swaps.length - 1;
|
|
365
|
+
if (curExchangeParam.transferSrcTokenBeforeSwap) {
|
|
366
|
+
const transferCallData = this.buildTransferCallData(this.erc20Interface.encodeFunctionData('transfer', [
|
|
367
|
+
curExchangeParam.transferSrcTokenBeforeSwap,
|
|
368
|
+
swapExchange.srcAmount,
|
|
369
|
+
]), (0, utils_1.isETHAddress)(swap.srcToken)
|
|
370
|
+
? this.getWETHAddress(curExchangeParam)
|
|
371
|
+
: swap.srcToken.toLowerCase());
|
|
372
|
+
swapExchangeCallData = hexConcat([
|
|
373
|
+
transferCallData,
|
|
374
|
+
swapExchangeCallData,
|
|
375
|
+
]);
|
|
376
|
+
}
|
|
377
|
+
if (!(0, utils_1.isETHAddress)(swap.srcToken) &&
|
|
378
|
+
!curExchangeParam.transferSrcTokenBeforeSwap &&
|
|
379
|
+
!curExchangeParam.skipApproval &&
|
|
380
|
+
curExchangeParam.approveData) {
|
|
381
|
+
const approveCallData = this.buildApproveCallData(curExchangeParam.approveData.target, curExchangeParam.approveData.token, approveFlag, curExchangeParam.permit2Approval);
|
|
382
|
+
swapExchangeCallData = hexConcat([approveCallData, swapExchangeCallData]);
|
|
383
|
+
}
|
|
384
|
+
if (curExchangeParam.needWrapNative) {
|
|
385
|
+
if ((0, utils_1.isETHAddress)(swap.srcToken)) {
|
|
386
|
+
let approveWethCalldata = '0x';
|
|
387
|
+
if (curExchangeParam.approveData &&
|
|
388
|
+
!curExchangeParam.transferSrcTokenBeforeSwap &&
|
|
389
|
+
!curExchangeParam.skipApproval) {
|
|
390
|
+
approveWethCalldata = this.buildApproveCallData(curExchangeParam.approveData.target, curExchangeParam.approveData.token, approveFlag, curExchangeParam.permit2Approval);
|
|
391
|
+
}
|
|
392
|
+
const isNotFirstSwap = swapIndex !== 0;
|
|
393
|
+
let skipWrap = false;
|
|
394
|
+
if (isNotFirstSwap) {
|
|
395
|
+
const prevSwap = singleRoutes[routeIndex].swaps[swapIndex - 1];
|
|
396
|
+
const anyDexOnSwapDoesntNeedWrapNative = this.anyDexOnSwapDoesntNeedWrapNative(prevSwap);
|
|
397
|
+
skipWrap = !anyDexOnSwapDoesntNeedWrapNative;
|
|
398
|
+
}
|
|
399
|
+
let depositCallData = '0x';
|
|
400
|
+
if (maybeWethCallData &&
|
|
401
|
+
maybeWethCallData.deposit &&
|
|
402
|
+
!this.doesRouteNeedsRootWrapEth(singleRoutes, srcToken) &&
|
|
403
|
+
allowToAddWrap &&
|
|
404
|
+
!addedWrapToSwapExchangeMap[`${routeIndex}_${swapIndex}_${swapExchangeIndex}`] &&
|
|
405
|
+
!skipWrap) {
|
|
406
|
+
depositCallData = this.buildWrapEthCallData(this.getWETHAddress(curExchangeParam), maybeWethCallData.deposit.calldata, types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP);
|
|
407
|
+
addedWrapToSwapExchangeMap[`${routeIndex}_${swapIndex}_${swapExchangeIndex}`] = true;
|
|
408
|
+
}
|
|
409
|
+
swapExchangeCallData = hexConcat([
|
|
410
|
+
approveWethCalldata,
|
|
411
|
+
depositCallData,
|
|
412
|
+
swapExchangeCallData,
|
|
413
|
+
]);
|
|
414
|
+
}
|
|
415
|
+
const needUnwrap = isMultiOrMegaSwap && hasMultipleSwapExchanges;
|
|
416
|
+
// unwrap after last swap
|
|
417
|
+
if (maybeWethCallData &&
|
|
418
|
+
maybeWethCallData.withdraw &&
|
|
419
|
+
((!needUnwrap && (0, utils_1.isETHAddress)(swap.destToken)) ||
|
|
420
|
+
(needUnwrap &&
|
|
421
|
+
(0, utils_1.isETHAddress)(swap.destToken) &&
|
|
422
|
+
this.anyDexOnSwapDoesntNeedWrapNative(swap)))) {
|
|
423
|
+
let withdrawCallData = '0x';
|
|
424
|
+
const customWethAddress = curExchangeParam.wethAddress;
|
|
425
|
+
const nextSwap = singleRoutes[routeIndex].swaps[swapIndex + 1];
|
|
426
|
+
const needUnwrapAll = isSimpleSwap ||
|
|
427
|
+
(isLastSwap
|
|
428
|
+
? !this.doesRouteNeedsRootUnwrapEth(singleRoutes, destToken)
|
|
429
|
+
: this.everyDexOnSwapNeedWrapNative(nextSwap) ||
|
|
430
|
+
this.everyDexOnSwapDoesntNeedWrapNative(nextSwap));
|
|
431
|
+
// check if current exchange is the last with needWrapNative
|
|
432
|
+
const needUnwrap = needUnwrapAll &&
|
|
433
|
+
this.isLastExchangeWithNeedWrapNative(swap, swapExchangeIndex);
|
|
434
|
+
if (customWethAddress || needUnwrap) {
|
|
435
|
+
unwrapToSwapMap[swapIndex] = true;
|
|
436
|
+
withdrawCallData = this.buildUnwrapEthCallData(this.getWETHAddress(curExchangeParam), maybeWethCallData.withdraw.calldata);
|
|
437
|
+
}
|
|
438
|
+
swapExchangeCallData = hexConcat([
|
|
439
|
+
swapExchangeCallData,
|
|
440
|
+
withdrawCallData,
|
|
441
|
+
]);
|
|
442
|
+
if (isSimpleSwap && (needUnwrap || customWethAddress)) {
|
|
443
|
+
const finalSpecialFlagCalldata = this.buildFinalSpecialFlagCalldata();
|
|
444
|
+
swapExchangeCallData = hexConcat([
|
|
445
|
+
swapExchangeCallData,
|
|
446
|
+
finalSpecialFlagCalldata,
|
|
447
|
+
]);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
let addedUnwrapForDexWithNoNeedWrapNative = false;
|
|
452
|
+
if ((0, utils_1.isETHAddress)(swap.srcToken) &&
|
|
453
|
+
maybeWethCallData &&
|
|
454
|
+
maybeWethCallData.withdraw &&
|
|
455
|
+
!curExchangeParam.needWrapNative &&
|
|
456
|
+
!unwrapToSwapMap[swapIndex - 1]) {
|
|
457
|
+
const prevSwap = singleRoutes[routeIndex].swaps[swapIndex - 1];
|
|
458
|
+
let eachDexOnPrevSwapReturnsWeth = false;
|
|
459
|
+
if (prevSwap && !prevBranchWasWrapped) {
|
|
460
|
+
eachDexOnPrevSwapReturnsWeth =
|
|
461
|
+
this.eachDexOnSwapNeedsWrapNative(prevSwap);
|
|
462
|
+
}
|
|
463
|
+
if (prevBranchWasWrapped || eachDexOnPrevSwapReturnsWeth) {
|
|
464
|
+
const withdrawCallData = this.buildUnwrapEthCallData(this.getWETHAddress(curExchangeParam), maybeWethCallData.withdraw.calldata);
|
|
465
|
+
swapExchangeCallData = hexConcat([
|
|
466
|
+
withdrawCallData,
|
|
467
|
+
swapExchangeCallData,
|
|
468
|
+
]);
|
|
469
|
+
addedUnwrapForDexWithNoNeedWrapNative = true;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (isLastSwap &&
|
|
473
|
+
!curExchangeParam.dexFuncHasRecipient &&
|
|
474
|
+
!(0, utils_1.isETHAddress)(swap.destToken) &&
|
|
475
|
+
destToken === swap.destToken) {
|
|
476
|
+
const transferCallData = this.buildTransferCallData(this.erc20Interface.encodeFunctionData('transfer', [
|
|
477
|
+
this.dexHelper.config.data.augustusV6Address,
|
|
478
|
+
swapExchange.destAmount,
|
|
479
|
+
]), swap.destToken);
|
|
480
|
+
swapExchangeCallData = hexConcat([
|
|
481
|
+
swapExchangeCallData,
|
|
482
|
+
transferCallData,
|
|
483
|
+
]);
|
|
484
|
+
}
|
|
485
|
+
if (!curExchangeParam.dexFuncHasRecipient &&
|
|
486
|
+
(0, utils_1.isETHAddress)(swap.destToken) &&
|
|
487
|
+
isLastSwap &&
|
|
488
|
+
// don't need to send eth without unwrapping, handling unwrap and sendEth in the end of root branch
|
|
489
|
+
!this.doesRouteNeedsRootUnwrapEth(singleRoutes, destToken)) {
|
|
490
|
+
const finalSpecialFlagCalldata = this.buildFinalSpecialFlagCalldata();
|
|
491
|
+
swapExchangeCallData = hexConcat([
|
|
492
|
+
swapExchangeCallData,
|
|
493
|
+
finalSpecialFlagCalldata,
|
|
494
|
+
]);
|
|
495
|
+
}
|
|
496
|
+
// if swap has multiple exchanges, then each exchange is executed as part of vertical branching
|
|
497
|
+
if (hasMultipleSwapExchanges) {
|
|
498
|
+
return this.wrapAsVerticalBranch(swapExchangeCallData, swapExchange.percent, swap, addedWrapToSwapExchangeMap[`${routeIndex}_${swapIndex}_${swapExchangeIndex}`], curExchangeParam, addedUnwrapForDexWithNoNeedWrapNative);
|
|
499
|
+
}
|
|
500
|
+
return swapExchangeCallData;
|
|
501
|
+
}
|
|
502
|
+
appendWrapEthCallData(calldata, maybeWethCallData, checkWethBalanceAfter = false) {
|
|
503
|
+
if (maybeWethCallData?.deposit) {
|
|
504
|
+
const callData = checkWethBalanceAfter
|
|
505
|
+
? this.addTokenAddressToCallData(maybeWethCallData.deposit.calldata, this.dexHelper.config.data.wrappedNativeTokenAddress.toLowerCase())
|
|
506
|
+
: maybeWethCallData.deposit.calldata;
|
|
507
|
+
const depositCallData = this.buildWrapEthCallData(this.dexHelper.config.data.wrappedNativeTokenAddress.toLowerCase(), callData, checkWethBalanceAfter
|
|
508
|
+
? types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP // 5
|
|
509
|
+
: types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP, // 9
|
|
510
|
+
checkWethBalanceAfter ? 4 : 0);
|
|
511
|
+
return hexConcat([calldata, depositCallData]);
|
|
512
|
+
}
|
|
513
|
+
return calldata;
|
|
514
|
+
}
|
|
515
|
+
eachDexOnSwapNeedsWrapNative(swap) {
|
|
516
|
+
return swap.swapExchanges.every(se => {
|
|
517
|
+
return (se.build.dexParams.needWrapNative && !se.build.dexParams.wethAddress);
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
anyDexOnSwapNeedsWrapNative(swap) {
|
|
521
|
+
return swap.swapExchanges
|
|
522
|
+
.map(s => s.build.dexParams.needWrapNative && !s.build.dexParams.wethAddress)
|
|
523
|
+
.includes(true);
|
|
524
|
+
}
|
|
525
|
+
isLastExchangeWithNeedWrapNative(swap, swapExchangeIndex) {
|
|
526
|
+
return (swap.swapExchanges
|
|
527
|
+
.map(t => t.build.dexParams.needWrapNative)
|
|
528
|
+
.reduceRight((acc, needWrapNative, index) => needWrapNative === true && acc === -1 ? index : acc, -1) === swapExchangeIndex);
|
|
529
|
+
}
|
|
530
|
+
anyDexOnSwapDoesntNeedWrapNative(swap) {
|
|
531
|
+
return swap.swapExchanges
|
|
532
|
+
.map(s => !s.build.dexParams.needWrapNative)
|
|
533
|
+
.includes(true);
|
|
534
|
+
}
|
|
535
|
+
everyDexOnSwapNeedWrapNative(swap) {
|
|
536
|
+
if (!swap) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
return swap.swapExchanges
|
|
540
|
+
.map(s => s.build.dexParams.needWrapNative)
|
|
541
|
+
.every(t => t === true);
|
|
542
|
+
}
|
|
543
|
+
everyDexOnSwapDoesntNeedWrapNative(swap) {
|
|
544
|
+
if (!swap) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
return swap.swapExchanges
|
|
548
|
+
.map(s => s.build.dexParams.needWrapNative)
|
|
549
|
+
.every(t => t === false);
|
|
550
|
+
}
|
|
551
|
+
doesSwapNeedToBeAsVerticalBranch(singleRoutes, routeIndex, swap) {
|
|
552
|
+
const isMegaSwap = singleRoutes.length > 1;
|
|
553
|
+
const isMultiSwap = !isMegaSwap && singleRoutes[routeIndex].swaps.length > 1;
|
|
554
|
+
return (isMultiSwap || isMegaSwap) && swap.swapExchanges.length > 1;
|
|
555
|
+
}
|
|
556
|
+
buildVerticalBranchingFlag(singleRoutes, swap, routeIndex, swapIndex, destToken) {
|
|
557
|
+
let flag = types_1.Flag.INSERT_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP; // 11
|
|
558
|
+
const isLastSwap = swapIndex === singleRoutes[routeIndex].swaps.length - 1;
|
|
559
|
+
if (isLastSwap) {
|
|
560
|
+
const isEthDest = (0, utils_1.isETHAddress)(destToken);
|
|
561
|
+
const lastSwap = singleRoutes[routeIndex].swaps[singleRoutes[routeIndex].swaps.length - 1];
|
|
562
|
+
const lastSwapExchanges = lastSwap.swapExchanges;
|
|
563
|
+
const anyDexLastSwapNeedUnwrap = lastSwapExchanges
|
|
564
|
+
.map(se => se.build.dexParams.needWrapNative &&
|
|
565
|
+
!se.build.dexParams.wethAddress)
|
|
566
|
+
.includes(true);
|
|
567
|
+
const noNeedUnwrap = isEthDest && !anyDexLastSwapNeedUnwrap;
|
|
568
|
+
if (noNeedUnwrap || !isEthDest) {
|
|
569
|
+
flag = types_1.Flag.INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP; // 3
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
const isEthDest = (0, utils_1.isETHAddress)(swap.destToken);
|
|
574
|
+
if (isEthDest) {
|
|
575
|
+
if (this.anyDexOnSwapDoesntNeedWrapNative(swap)) {
|
|
576
|
+
flag = types_1.Flag.INSERT_FROM_AMOUNT_CHECK_ETH_BALANCE_AFTER_SWAP; // 7
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return flag;
|
|
581
|
+
}
|
|
582
|
+
buildSingleSwapCallData(params) {
|
|
583
|
+
const { routeIndex, swapIndex, maybeWethCallData, wrapToSwapMap, unwrapToSwapMap, wrapToSwapExchangeMap, swap, srcToken, destToken, singleRoutes, } = params;
|
|
584
|
+
const isLastSwap = swapIndex === singleRoutes[routeIndex].swaps.length - 1;
|
|
585
|
+
const isMegaSwap = singleRoutes.length > 1;
|
|
586
|
+
const isMultiSwap = !isMegaSwap && singleRoutes[routeIndex].swaps.length > 1;
|
|
587
|
+
const { swapExchanges } = swap;
|
|
588
|
+
const applyVerticalBranching = this.doesSwapNeedToBeAsVerticalBranch(singleRoutes, routeIndex, swap);
|
|
589
|
+
const anyDexOnSwapDoesntNeedWrapNative = this.anyDexOnSwapDoesntNeedWrapNative(swap);
|
|
590
|
+
const needToAppendWrapCallData = (0, utils_1.isETHAddress)(swap.destToken) &&
|
|
591
|
+
anyDexOnSwapDoesntNeedWrapNative &&
|
|
592
|
+
!isLastSwap &&
|
|
593
|
+
maybeWethCallData?.deposit;
|
|
594
|
+
let swapCallData = swapExchanges.reduce((acc, _swapExchange, swapExchangeIndex) => {
|
|
595
|
+
return hexConcat([
|
|
596
|
+
acc,
|
|
597
|
+
this.buildSingleSwapExchangeCallData(singleRoutes, routeIndex, swapIndex, swapExchangeIndex, wrapToSwapExchangeMap, !wrapToSwapMap[swapIndex - 1], wrapToSwapMap[swapIndex - 1], unwrapToSwapMap, srcToken, destToken, maybeWethCallData, swap.swapExchanges.length > 1, isMultiSwap || isMegaSwap),
|
|
598
|
+
]);
|
|
599
|
+
}, '0x');
|
|
600
|
+
if (needToAppendWrapCallData) {
|
|
601
|
+
wrapToSwapMap[swapIndex] = true;
|
|
602
|
+
}
|
|
603
|
+
if (!isMultiSwap && !isMegaSwap) {
|
|
604
|
+
return needToAppendWrapCallData
|
|
605
|
+
? this.appendWrapEthCallData(swapCallData, maybeWethCallData)
|
|
606
|
+
: swapCallData;
|
|
607
|
+
}
|
|
608
|
+
if (applyVerticalBranching) {
|
|
609
|
+
const vertBranchingCallData = this.buildVerticalBranchingCallData(singleRoutes, swap, swapCallData, this.buildVerticalBranchingFlag(singleRoutes, swap, routeIndex, swapIndex, destToken));
|
|
610
|
+
return needToAppendWrapCallData
|
|
611
|
+
? this.appendWrapEthCallData(vertBranchingCallData, maybeWethCallData, true)
|
|
612
|
+
: vertBranchingCallData;
|
|
613
|
+
}
|
|
614
|
+
return needToAppendWrapCallData
|
|
615
|
+
? this.appendWrapEthCallData(swapCallData, maybeWethCallData)
|
|
616
|
+
: swapCallData;
|
|
617
|
+
}
|
|
618
|
+
buildSingleRouteCallData(singleRoutes, route, routeIndex, flags, sender, srcToken, destToken, maybeWethCallData) {
|
|
619
|
+
const isMegaSwap = singleRoutes.length > 1;
|
|
620
|
+
const { swaps } = route;
|
|
621
|
+
const appendedWrapToSwapExchangeMap = {};
|
|
622
|
+
const addedWrapToSwapMap = {};
|
|
623
|
+
const unwrapToSwapMap = {};
|
|
624
|
+
const callData = swaps.reduce((swapAcc, swap, swapIndex) => hexConcat([
|
|
625
|
+
swapAcc,
|
|
626
|
+
this.buildSingleSwapCallData({
|
|
627
|
+
singleRoutes,
|
|
628
|
+
routeIndex,
|
|
629
|
+
swapIndex,
|
|
630
|
+
flags,
|
|
631
|
+
sender,
|
|
632
|
+
wrapToSwapExchangeMap: appendedWrapToSwapExchangeMap,
|
|
633
|
+
wrapToSwapMap: addedWrapToSwapMap,
|
|
634
|
+
unwrapToSwapMap,
|
|
635
|
+
maybeWethCallData,
|
|
636
|
+
swap,
|
|
637
|
+
index: 0,
|
|
638
|
+
srcToken,
|
|
639
|
+
destToken,
|
|
640
|
+
// TODO-multi to be removed after refactoring
|
|
641
|
+
routes: [],
|
|
642
|
+
exchangeParams: [],
|
|
643
|
+
}),
|
|
644
|
+
]), '0x');
|
|
645
|
+
if (isMegaSwap) {
|
|
646
|
+
return this.wrapAsVerticalBranch(callData, route.percent, route.swaps[0], Object.values(addedWrapToSwapMap).includes(true) ||
|
|
647
|
+
Object.values(appendedWrapToSwapExchangeMap).includes(true), null);
|
|
648
|
+
}
|
|
649
|
+
return callData;
|
|
650
|
+
}
|
|
651
|
+
doesRouteNeedsRootWrapEth(singleRoutes, srcToken) {
|
|
652
|
+
if (!(0, utils_1.isETHAddress)(srcToken)) {
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
return singleRoutes.every(route => this.eachDexOnSwapNeedsWrapNative(route.swaps[0]));
|
|
656
|
+
}
|
|
657
|
+
doesRouteNeedsRootUnwrapEth(singleRoutes, destToken) {
|
|
658
|
+
if (!(0, utils_1.isETHAddress)(destToken)) {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
const res = singleRoutes.some(route => {
|
|
662
|
+
const lastSwap = route.swaps[route.swaps.length - 1];
|
|
663
|
+
const anyDexOnSwapNeedsWrapNative = this.anyDexOnSwapNeedsWrapNative(lastSwap);
|
|
664
|
+
return anyDexOnSwapNeedsWrapNative;
|
|
665
|
+
});
|
|
666
|
+
return res;
|
|
667
|
+
}
|
|
668
|
+
getAddress() {
|
|
669
|
+
return this.dexHelper.config.data.executorsAddresses[types_1.Executors.TWO];
|
|
670
|
+
}
|
|
671
|
+
buildByteCode(priceRoute, routes, exchangeParams, sender, maybeWethCallData) {
|
|
672
|
+
// TODO-multi: temporary to handle all cases for single-route after refactoring
|
|
673
|
+
const _routes = routes.filter(r => r.type === 'single-route');
|
|
674
|
+
const isMegaSwap = priceRoute.bestRoute.length > 1;
|
|
675
|
+
const isMultiSwap = !isMegaSwap && priceRoute.bestRoute[0].swaps.length > 1;
|
|
676
|
+
const needWrapEth = maybeWethCallData?.deposit && (0, utils_1.isETHAddress)(priceRoute.srcToken);
|
|
677
|
+
const needUnwrapEth = maybeWethCallData?.withdraw && (0, utils_1.isETHAddress)(priceRoute.destToken);
|
|
678
|
+
const needSendNativeEth = (0, utils_1.isETHAddress)(priceRoute.destToken);
|
|
679
|
+
const routeNeedsRootWrapEth = this.doesRouteNeedsRootWrapEth(_routes, priceRoute.srcToken);
|
|
680
|
+
const routeNeedsRootUnwrapEth = this.doesRouteNeedsRootUnwrapEth(_routes, priceRoute.destToken);
|
|
681
|
+
const flags = this.buildFlags(priceRoute.bestRoute, _routes, exchangeParams, priceRoute.srcToken, maybeWethCallData);
|
|
682
|
+
let swapsCalldata = _routes.reduce((routeAcc, route, routeIndex) => hexConcat([
|
|
683
|
+
routeAcc,
|
|
684
|
+
this.buildSingleRouteCallData(_routes, route, routeIndex, flags, sender, priceRoute.srcToken, priceRoute.destToken, maybeWethCallData),
|
|
685
|
+
]), '0x');
|
|
686
|
+
// hack to do wrap/unwrap before the priceRoute execution
|
|
687
|
+
// first make wrap/unwrap, then execute mega swap as vertical branch
|
|
688
|
+
if (isMegaSwap && (needWrapEth || needUnwrapEth)) {
|
|
689
|
+
const lastRoute = _routes[_routes.length - 1];
|
|
690
|
+
swapsCalldata = this.buildVerticalBranchingCallData(_routes, lastRoute.swaps[lastRoute.swaps.length - 1], swapsCalldata, needWrapEth
|
|
691
|
+
? types_1.Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP // 0
|
|
692
|
+
: types_1.Flag.DONT_INSERT_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP, // 8
|
|
693
|
+
true);
|
|
694
|
+
}
|
|
695
|
+
// ETH wrap
|
|
696
|
+
if (needWrapEth && routeNeedsRootWrapEth) {
|
|
697
|
+
let depositCallData = this.buildWrapEthCallData(this.dexHelper.config.data.wrappedNativeTokenAddress, maybeWethCallData.deposit.calldata, types_1.Flag.SEND_ETH_EQUAL_TO_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP);
|
|
698
|
+
if (!(isMegaSwap || isMultiSwap)) {
|
|
699
|
+
const swap = priceRoute.bestRoute[0].swaps[0];
|
|
700
|
+
const percent = exchangeParams.every(ep => ep.needWrapNative)
|
|
701
|
+
? 100
|
|
702
|
+
: swap.swapExchanges
|
|
703
|
+
.filter((_se, index) => {
|
|
704
|
+
return exchangeParams[index].needWrapNative;
|
|
705
|
+
})
|
|
706
|
+
.reduce((acc, se) => {
|
|
707
|
+
acc += se.percent;
|
|
708
|
+
return acc;
|
|
709
|
+
}, 0);
|
|
710
|
+
depositCallData = solidityPack(['bytes16', 'bytes16', 'bytes'], [
|
|
711
|
+
hexZeroPad(hexlify(hexDataLength(depositCallData)), 16),
|
|
712
|
+
hexZeroPad(hexlify(100 * percent), 16),
|
|
713
|
+
depositCallData,
|
|
714
|
+
]);
|
|
715
|
+
}
|
|
716
|
+
swapsCalldata = hexConcat([depositCallData, swapsCalldata]);
|
|
717
|
+
}
|
|
718
|
+
// ETH unwrap, only for multiswaps and mega swaps
|
|
719
|
+
if (needUnwrapEth &&
|
|
720
|
+
routeNeedsRootUnwrapEth &&
|
|
721
|
+
(isMultiSwap || isMegaSwap)) {
|
|
722
|
+
const withdrawCallData = this.buildUnwrapEthCallData(this.dexHelper.config.data.wrappedNativeTokenAddress, maybeWethCallData.withdraw.calldata);
|
|
723
|
+
swapsCalldata = hexConcat([swapsCalldata, withdrawCallData]);
|
|
724
|
+
}
|
|
725
|
+
// Special flag (send native) calldata, only for multiswaps and mega swaps
|
|
726
|
+
if (needSendNativeEth &&
|
|
727
|
+
routeNeedsRootUnwrapEth &&
|
|
728
|
+
(isMultiSwap || isMegaSwap)) {
|
|
729
|
+
const finalSpecialFlagCalldata = this.buildFinalSpecialFlagCalldata();
|
|
730
|
+
swapsCalldata = hexConcat([swapsCalldata, finalSpecialFlagCalldata]);
|
|
731
|
+
}
|
|
732
|
+
if (((needWrapEth || needUnwrapEth) && isMegaSwap) || isMultiSwap) {
|
|
733
|
+
swapsCalldata = this.wrapAsVerticalBranch(swapsCalldata, constants_1.SWAP_EXCHANGE_100_PERCENTAGE, _routes[0].swaps[0], false, null);
|
|
734
|
+
}
|
|
735
|
+
return solidityPack(['bytes32', 'bytes', 'bytes'], [
|
|
736
|
+
hexZeroPad(hexlify(32), 32), // calldata offset
|
|
737
|
+
hexZeroPad(hexlify(hexDataLength(swapsCalldata) + constants_1.BYTES_64_LENGTH), // calldata length (64 bytes = bytes12(0) + msg.sender)
|
|
738
|
+
32),
|
|
739
|
+
swapsCalldata, // calldata
|
|
740
|
+
]);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
exports.Executor02BytecodeBuilderMultiRoute = Executor02BytecodeBuilderMultiRoute;
|
|
744
|
+
//# sourceMappingURL=Executor02BytecodeBuilderMultiRoute.js.map
|