@pendle/core-v2 4.5.0 → 4.5.1-beta-1

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.
Files changed (41) hide show
  1. package/build/artifacts/contracts/core/StandardizedYield/implementations/PendleERC20WithSupplyCapSY.sol/PendleERC20WithSupplyCapSY.dbg.json +1 -1
  2. package/build/artifacts/contracts/interfaces/IPActionMiscV3.sol/IPActionMiscV3.dbg.json +1 -1
  3. package/build/artifacts/contracts/interfaces/IPActionMiscV3.sol/IPActionMiscV3.json +431 -0
  4. package/build/artifacts/contracts/interfaces/IPAllActionV3.sol/IPAllActionV3.dbg.json +1 -1
  5. package/build/artifacts/contracts/interfaces/IPAllActionV3.sol/IPAllActionV3.json +431 -0
  6. package/build/artifacts/contracts/offchain-helpers/PendlePoolDeployHelper.sol/PendlePoolDeployHelper.dbg.json +1 -1
  7. package/build/artifacts/contracts/offchain-helpers/PendlePoolDeployHelper.sol/PendlePoolDeployHelper.json +2 -2
  8. package/build/artifacts/contracts/offchain-helpers/router-static/base/ActionMarketAuxStatic.sol/ActionMarketAuxStatic.dbg.json +1 -1
  9. package/build/artifacts/contracts/router/ActionAddRemoveLiqV3.sol/ActionAddRemoveLiqV3.dbg.json +1 -1
  10. package/build/artifacts/contracts/router/ActionAddRemoveLiqV3.sol/ActionAddRemoveLiqV3.json +2 -2
  11. package/build/artifacts/contracts/router/ActionMiscV3.sol/ActionMiscV3.dbg.json +1 -1
  12. package/build/artifacts/contracts/router/ActionMiscV3.sol/ActionMiscV3.json +591 -2
  13. package/build/artifacts/contracts/router/ActionSwapPTV3.sol/ActionSwapPTV3.dbg.json +1 -1
  14. package/build/artifacts/contracts/router/ActionSwapPTV3.sol/ActionSwapPTV3.json +2 -2
  15. package/build/artifacts/contracts/router/ActionSwapYTV3.sol/ActionSwapYTV3.dbg.json +1 -1
  16. package/build/artifacts/contracts/router/ActionSwapYTV3.sol/ActionSwapYTV3.json +2 -2
  17. package/build/artifacts/contracts/router/base/ActionBase.sol/ActionBase.dbg.json +1 -1
  18. package/contracts/interfaces/IPActionMiscV3.sol +38 -0
  19. package/contracts/router/ActionMiscV3.sol +216 -36
  20. package/contracts/router/ActionSwapYTV3.sol +0 -85
  21. package/contracts/router/base/ActionBase.sol +106 -1
  22. package/deployments/merkle-distribution/2024-04-25.json +14930 -0
  23. package/package.json +1 -1
  24. package/typechain-types/ActionMiscV3.ts +379 -16
  25. package/typechain-types/IPActionMiscV3.ts +249 -16
  26. package/typechain-types/IPAllActionV3.ts +156 -0
  27. package/typechain-types/ISwellSimpleStakingERC20.ts +289 -0
  28. package/typechain-types/PendleSwellRswETHStakingSY.ts +1325 -0
  29. package/typechain-types/PendleSwellStakingERC20SY.ts +1299 -0
  30. package/typechain-types/factories/ActionAddRemoveLiqV3__factory.ts +1 -1
  31. package/typechain-types/factories/ActionMiscV3__factory.ts +590 -1
  32. package/typechain-types/factories/ActionSwapPTV3__factory.ts +1 -1
  33. package/typechain-types/factories/ActionSwapYTV3__factory.ts +1 -1
  34. package/typechain-types/factories/IPActionMiscV3__factory.ts +431 -0
  35. package/typechain-types/factories/IPAllActionV3__factory.ts +431 -0
  36. package/typechain-types/factories/ISwellSimpleStakingERC20__factory.ts +226 -0
  37. package/typechain-types/factories/PendlePoolDeployHelper__factory.ts +1 -1
  38. package/typechain-types/factories/PendleSwellRswETHStakingSY__factory.ts +1106 -0
  39. package/typechain-types/factories/PendleSwellStakingERC20SY__factory.ts +1112 -0
  40. package/typechain-types/hardhat.d.ts +27 -0
  41. package/typechain-types/index.ts +6 -0
@@ -79,18 +79,16 @@ contract ActionMiscV3 is IPActionMiscV3, ActionBase {
79
79
  address[] calldata yts,
80
80
  address[] calldata markets
81
81
  ) external {
82
- unchecked {
83
- for (uint256 i = 0; i < sys.length; ++i) {
84
- IStandardizedYield(sys[i]).claimRewards(user);
85
- }
86
-
87
- for (uint256 i = 0; i < yts.length; ++i) {
88
- IPYieldToken(yts[i]).redeemDueInterestAndRewards(user, true, true);
89
- }
90
-
91
- for (uint256 i = 0; i < markets.length; ++i) {
92
- IPMarket(markets[i]).redeemRewards(user);
93
- }
82
+ for (uint256 i = 0; i < sys.length; ++i) {
83
+ IStandardizedYield(sys[i]).claimRewards(user);
84
+ }
85
+
86
+ for (uint256 i = 0; i < yts.length; ++i) {
87
+ IPYieldToken(yts[i]).redeemDueInterestAndRewards(user, true, true);
88
+ }
89
+
90
+ for (uint256 i = 0; i < markets.length; ++i) {
91
+ IPMarket(markets[i]).redeemRewards(user);
94
92
  }
95
93
  }
96
94
 
@@ -118,40 +116,222 @@ contract ActionMiscV3 is IPActionMiscV3, ActionBase {
118
116
  netTokenOut = IStandardizedYield(SY).redeem(receiver, netSyInterm, tokenRedeemSy, minTokenOut, true);
119
117
  }
120
118
 
119
+ event ExitMultiplePreExpiry(
120
+ address indexed caller,
121
+ address indexed market,
122
+ address indexed token,
123
+ address receiver,
124
+ uint256 netLpToRemove,
125
+ uint256 netPtFromRemove,
126
+ uint256 netSyFromRemove,
127
+ uint256 netPyRedeem,
128
+ uint256 netSyFromRedeem,
129
+ uint256 netPtSwap,
130
+ uint256 netYtSwap,
131
+ uint256 netSyFromSwap,
132
+ uint256 netSyFee,
133
+ uint256 netTokenOut
134
+ );
135
+
136
+ event ExitMultiplePostExpiry(
137
+ address indexed caller,
138
+ address indexed market,
139
+ address indexed token,
140
+ address receiver,
141
+ uint256 netLpToRemove,
142
+ uint256 netPtFromRemove, //
143
+ uint256 netSyFromRemove, //
144
+ uint256 netPtRedeem,
145
+ uint256 netSyFromRedeem, //
146
+ uint256 netTokenOut //
147
+ );
148
+
149
+ // TODO: need to allow exit to SY as well
150
+
151
+ struct ExitMultipleParams {
152
+ address receiver;
153
+ address market;
154
+ uint256 netPtIn;
155
+ uint256 netYtIn;
156
+ uint256 netLpIn;
157
+ TokenOutput output;
158
+ LimitOrderData limit;
159
+ }
160
+
161
+ function exitMultiplePreExpiry(
162
+ address receiver,
163
+ address market,
164
+ uint256 netPtIn,
165
+ uint256 netYtIn,
166
+ uint256 netLpIn,
167
+ TokenOutput calldata output,
168
+ LimitOrderData calldata limit
169
+ )
170
+ external
171
+ returns (
172
+ uint256 netTokenOut,
173
+ uint256 netPtFromRemove,
174
+ uint256 netSyFromRemove,
175
+ uint256 netPyRedeem,
176
+ uint256 netSyFromRedeem,
177
+ uint256 netPtSwap,
178
+ uint256 netYtSwap,
179
+ uint256 netSyFromSwap,
180
+ uint256 netSyFee
181
+ )
182
+ {
183
+ (
184
+ netTokenOut,
185
+ netPtFromRemove,
186
+ netSyFromRemove,
187
+ netPyRedeem,
188
+ netSyFromRedeem,
189
+ netPtSwap,
190
+ netYtSwap,
191
+ netSyFromSwap,
192
+ netSyFee
193
+ ) = exitMultiplePreExpiryInner(receiver, market, netPtIn, netYtIn, netLpIn, output, limit);
194
+
195
+ emit ExitMultiplePreExpiry(
196
+ msg.sender,
197
+ market,
198
+ output.tokenOut,
199
+ receiver,
200
+ netLpIn,
201
+ netPtFromRemove,
202
+ netSyFromRemove,
203
+ netPyRedeem,
204
+ netSyFromRedeem,
205
+ netPtSwap,
206
+ netYtSwap,
207
+ netSyFromSwap,
208
+ netSyFee,
209
+ netTokenOut
210
+ );
211
+ }
212
+
213
+ function exitMultiplePreExpiryInner(
214
+ address receiver,
215
+ address market,
216
+ uint256 netPtIn,
217
+ uint256 netYtIn,
218
+ uint256 netLpIn,
219
+ TokenOutput calldata output,
220
+ LimitOrderData calldata limit
221
+ )
222
+ internal
223
+ returns (
224
+ uint256 netTokenOut,
225
+ uint256 netPtFromRemove,
226
+ uint256 netSyFromRemove,
227
+ uint256 netPyRedeem,
228
+ uint256 netSyFromRedeem,
229
+ uint256 netPtSwap,
230
+ uint256 netYtSwap,
231
+ uint256 netSyFromSwap,
232
+ uint256 netSyFee
233
+ )
234
+ {
235
+ // (IStandardizedYield SY, IPPrincipalToken PT, IPYieldToken YT) = IPMarket(market).readTokens();
236
+ // if (netLpIn > 0) {
237
+ // _transferFrom(IERC20(market), msg.sender, market, netLpIn);
238
+ // (netSyFromRemove, netPtFromRemove) = IPMarket(market).burn(address(SY), address(this), netLpIn);
239
+ // }
240
+ // if (netPtIn > 0) {
241
+ // _transferIn(address(PT), address(this), netPtIn);
242
+ // }
243
+ // netPyRedeem = PMath.min(netPtFromRemove + netPtIn, netYtIn);
244
+ // if (netPyRedeem > 0) {
245
+ // _transferOut(address(PT), address(YT), netPyRedeem);
246
+ // _transferFrom(YT, msg.sender, address(YT), netPyRedeem);
247
+ // netSyFromRedeem = IPYieldToken(YT).redeemPY(address(SY));
248
+ // }
249
+ // netPtSwap = netPtFromRemove + netPtIn - netPyRedeem;
250
+ // netYtSwap = netYtIn - netPyRedeem;
251
+ // if (netPtSwap > 0) {
252
+ // address ptEntry = _entry_swapExactPtForSy(market, limit);
253
+ // if (ptEntry != address(this)) _transferOut(address(PT), ptEntry, netPtSwap);
254
+ // (netSyFromSwap, netSyFee) = _swapExactPtForSy(address(SY), market, netPtSwap, 0, limit);
255
+ // } else if (netYtSwap > 0) {
256
+ // _transferFrom(YT, msg.sender, _entry_swapExactYtForSy(YT, limit), netYtSwap);
257
+ // (netSyFromSwap, netSyFee) = _swapExactYtForSy(address(SY), market, SY, YT, netYtSwap, 0, limit);
258
+ // }
259
+ // uint256 netSyRedeem = netSyFromRemove + netSyFromRedeem + netSyFromSwap;
260
+ // netTokenOut = _redeemSyToToken(receiver, address(SY), netSyRedeem, output, false);
261
+ }
262
+
263
+ // TODO: is netSyInterm necessary? can we return more?
264
+ // TODO: compare interface against existing functions, to see if it makes sense
265
+ function exitMultiplePostExpiry(
266
+ address receiver,
267
+ address market,
268
+ uint256 netPtIn,
269
+ uint256 netLpIn,
270
+ TokenOutput calldata output
271
+ )
272
+ external
273
+ returns (
274
+ uint256 netTokenOut,
275
+ uint256 netPtFromRemove,
276
+ uint256 netSyFromRemove,
277
+ uint256 netPtRedeem,
278
+ uint256 netSyFromRedeem
279
+ )
280
+ {
281
+ // * (done) maybe shouldn't reuse functions because of conflicting events
282
+ // * (KIV) expose all inner workings variables
283
+ // also: should match events with existing events
284
+ // events, no matter what is emitted, can be parsed dynamically on BE. Say if only PT is exited, it can be parsed
285
+ // as swapExact
286
+
287
+ (IStandardizedYield SY, IPPrincipalToken PT, IPYieldToken YT) = IPMarket(market).readTokens();
288
+
289
+ // uint256 netPtFromRemove;
290
+ // uint256 netSyFromRemove;
291
+
292
+ if (netLpIn > 0) {
293
+ _transferFrom(IERC20(market), msg.sender, market, netLpIn);
294
+ (netSyFromRemove, netPtFromRemove) = IPMarket(market).burn(address(SY), address(YT), netLpIn);
295
+ }
296
+
297
+ if (netPtIn > 0) {
298
+ _transferFrom(PT, msg.sender, address(YT), netPtIn);
299
+ }
300
+
301
+ netPtRedeem = netPtFromRemove + netPtIn;
302
+ netSyFromRedeem = IPYieldToken(YT).redeemPY(address(SY));
303
+
304
+ uint256 netSyRedeem = netSyFromRemove + netSyFromRedeem;
305
+ netTokenOut = _redeemSyToToken(receiver, address(SY), netSyRedeem, output, false);
306
+
307
+ emit ExitMultiplePostExpiry(
308
+ msg.sender,
309
+ market,
310
+ output.tokenOut,
311
+ receiver,
312
+ netLpIn,
313
+ netPtFromRemove,
314
+ netSyFromRemove,
315
+ netPtRedeem,
316
+ netSyFromRedeem,
317
+ netTokenOut
318
+ );
319
+ }
320
+
121
321
  // ----------------- MISC FUNCTIONS -----------------
122
322
 
123
323
  function boostMarkets(address[] memory markets) external {
124
- for (uint256 i = 0; i < markets.length; ) {
324
+ for (uint256 i = 0; i < markets.length; i++) {
125
325
  IPMarket(markets[i]).transferFrom(msg.sender, markets[i], 0);
126
- unchecked {
127
- i++;
128
- }
129
326
  }
130
327
  }
131
328
 
132
329
  function multicall(Call3[] calldata calls) external payable returns (Result[] memory res) {
133
330
  uint256 length = calls.length;
134
331
  res = new Result[](length);
135
- Call3 calldata call;
136
- for (uint256 i = 0; i < length; ) {
137
- call = calls[i];
138
-
139
- // delegatecall to itself, it turns allowing invoking functions from other actions
140
- (bool success, bytes memory result) = address(this).delegatecall(call.callData);
141
-
142
- if (!success && !call.allowFailure) {
143
- assembly {
144
- // We use Yul's revert() to bubble up errors from the target contract.
145
- revert(add(32, result), mload(result))
146
- }
147
- }
148
-
149
- res[i].success = success;
150
- res[i].returnData = result;
151
-
152
- unchecked {
153
- ++i;
154
- }
332
+ for (uint256 i = 0; i < length; i++) {
333
+ (bool success, bytes memory result) = _delegateToSelf(calls[i].callData, calls[i].allowFailure);
334
+ res[i] = Result(success, result);
155
335
  }
156
336
  }
157
337
 
@@ -52,51 +52,6 @@ contract ActionSwapYTV3 is CallbackHelper, IPActionSwapYTV3, ActionBase {
52
52
  emit SwapYtAndSy(msg.sender, market, receiver, netYtOut.Int(), exactSyIn.neg());
53
53
  }
54
54
 
55
- function _entry_swapExactSyForYt(IPYieldToken YT, LimitOrderData calldata limit) internal view returns (address) {
56
- return !_isEmptyLimit(limit) ? address(this) : address(YT);
57
- }
58
-
59
- function _swapExactSyForYt(
60
- address receiver,
61
- address market,
62
- IStandardizedYield SY,
63
- IPYieldToken YT,
64
- uint256 exactSyIn,
65
- uint256 minYtOut,
66
- ApproxParams calldata guessYtOut,
67
- LimitOrderData calldata limit
68
- ) internal returns (uint256 netYtOut, uint256 netSyFee) {
69
- uint256 netSyLeft = exactSyIn;
70
- bool doMarketOrder = true;
71
-
72
- if (!_isEmptyLimit(limit)) {
73
- (netSyLeft, netYtOut, netSyFee, doMarketOrder) = _fillLimit(receiver, SY, netSyLeft, limit);
74
- if (doMarketOrder) {
75
- _transferOut(address(SY), address(YT), netSyLeft);
76
- }
77
- }
78
-
79
- if (doMarketOrder) {
80
- (uint256 netYtOutMarket, ) = _readMarket(market).approxSwapExactSyForYt(
81
- YT.newIndex(),
82
- netSyLeft,
83
- block.timestamp,
84
- guessYtOut
85
- );
86
-
87
- (, uint256 netSyFeeMarket) = IPMarket(market).swapExactPtForSy(
88
- address(YT),
89
- netYtOutMarket, // exactPtIn = netYtOut
90
- _encodeSwapExactSyForYt(receiver, YT)
91
- );
92
-
93
- netYtOut += netYtOutMarket;
94
- netSyFee += netSyFeeMarket;
95
- }
96
-
97
- if (netYtOut < minYtOut) revert("Slippage: INSUFFICIENT_YT_OUT");
98
- }
99
-
100
55
  // ------------------ SWAP TOKEN FOR TOKEN ------------------
101
56
 
102
57
  function swapExactYtForToken(
@@ -138,46 +93,6 @@ contract ActionSwapYTV3 is CallbackHelper, IPActionSwapYTV3, ActionBase {
138
93
  emit SwapYtAndSy(msg.sender, market, receiver, exactYtIn.neg(), netSyOut.Int());
139
94
  }
140
95
 
141
- function _entry_swapExactYtForSy(IPYieldToken YT, LimitOrderData calldata limit) internal view returns (address) {
142
- return !_isEmptyLimit(limit) ? address(this) : address(YT);
143
- }
144
-
145
- function _swapExactYtForSy(
146
- address receiver,
147
- address market,
148
- IStandardizedYield SY,
149
- IPYieldToken YT,
150
- uint256 exactYtIn,
151
- uint256 minSyOut,
152
- LimitOrderData calldata limit
153
- ) internal returns (uint256 netSyOut, uint256 netSyFee) {
154
- uint256 netYtLeft = exactYtIn;
155
- bool doMarketOrder = true;
156
-
157
- if (!_isEmptyLimit(limit)) {
158
- (netYtLeft, netSyOut, netSyFee, doMarketOrder) = _fillLimit(receiver, YT, netYtLeft, limit);
159
- if (doMarketOrder) {
160
- _transferOut(address(YT), address(YT), netYtLeft);
161
- }
162
- }
163
-
164
- if (doMarketOrder) {
165
- uint256 preSyBalance = SY.balanceOf(receiver);
166
-
167
- (, uint256 netSyFeeMarket) = IPMarket(market).swapSyForExactPt(
168
- address(YT),
169
- netYtLeft, // exactPtOut = netYtLeft
170
- _encodeSwapYtForSy(receiver, YT)
171
- );
172
-
173
- // avoid stack issue
174
- netSyFee += netSyFeeMarket;
175
- netSyOut += SY.balanceOf(receiver) - preSyBalance;
176
- }
177
-
178
- if (netSyOut < minSyOut) revert("Slippage: INSUFFICIENT_SY_OUT");
179
- }
180
-
181
96
  // ------------------ SWAP PT FOR YT ------------------
182
97
 
183
98
  function swapExactPtForYt(
@@ -10,8 +10,10 @@ import "../../router/base/MarketApproxLib.sol";
10
10
 
11
11
  import "../../core/libraries/Errors.sol";
12
12
  import "../swap-aggregator/IPSwapAggregator.sol";
13
+ import "./CallbackHelper.sol";
13
14
 
14
- abstract contract ActionBase is TokenHelper, IPLimitOrderType {
15
+ abstract contract ActionBase is TokenHelper, CallbackHelper, IPLimitOrderType {
16
+ using MarketApproxPtInLib for MarketState;
15
17
  using MarketApproxPtOutLib for MarketState;
16
18
  using PMath for uint256;
17
19
  using PYIndexLib for IPYieldToken;
@@ -236,6 +238,93 @@ abstract contract ActionBase is TokenHelper, IPLimitOrderType {
236
238
  if (netPtOut < minPtOut) revert("Slippage: INSUFFICIENT_PT_OUT");
237
239
  }
238
240
 
241
+ // ----------------- YT SWAP -----------------
242
+
243
+ function _entry_swapExactYtForSy(IPYieldToken YT, LimitOrderData calldata limit) internal view returns (address) {
244
+ return !_isEmptyLimit(limit) ? address(this) : address(YT);
245
+ }
246
+
247
+ function _swapExactYtForSy(
248
+ address receiver,
249
+ address market,
250
+ IStandardizedYield SY,
251
+ IPYieldToken YT,
252
+ uint256 exactYtIn,
253
+ uint256 minSyOut,
254
+ LimitOrderData calldata limit
255
+ ) internal returns (uint256 netSyOut, uint256 netSyFee) {
256
+ uint256 netYtLeft = exactYtIn;
257
+ bool doMarketOrder = true;
258
+
259
+ if (!_isEmptyLimit(limit)) {
260
+ (netYtLeft, netSyOut, netSyFee, doMarketOrder) = _fillLimit(receiver, YT, netYtLeft, limit);
261
+ if (doMarketOrder) {
262
+ _transferOut(address(YT), address(YT), netYtLeft);
263
+ }
264
+ }
265
+
266
+ if (doMarketOrder) {
267
+ uint256 preSyBalance = SY.balanceOf(receiver);
268
+
269
+ (, uint256 netSyFeeMarket) = IPMarket(market).swapSyForExactPt(
270
+ address(YT),
271
+ netYtLeft, // exactPtOut = netYtLeft
272
+ _encodeSwapYtForSy(receiver, YT)
273
+ );
274
+
275
+ // avoid stack issue
276
+ netSyFee += netSyFeeMarket;
277
+ netSyOut += SY.balanceOf(receiver) - preSyBalance;
278
+ }
279
+
280
+ if (netSyOut < minSyOut) revert("Slippage: INSUFFICIENT_SY_OUT");
281
+ }
282
+
283
+ function _entry_swapExactSyForYt(IPYieldToken YT, LimitOrderData calldata limit) internal view returns (address) {
284
+ return !_isEmptyLimit(limit) ? address(this) : address(YT);
285
+ }
286
+
287
+ function _swapExactSyForYt(
288
+ address receiver,
289
+ address market,
290
+ IStandardizedYield SY,
291
+ IPYieldToken YT,
292
+ uint256 exactSyIn,
293
+ uint256 minYtOut,
294
+ ApproxParams calldata guessYtOut,
295
+ LimitOrderData calldata limit
296
+ ) internal returns (uint256 netYtOut, uint256 netSyFee) {
297
+ uint256 netSyLeft = exactSyIn;
298
+ bool doMarketOrder = true;
299
+
300
+ if (!_isEmptyLimit(limit)) {
301
+ (netSyLeft, netYtOut, netSyFee, doMarketOrder) = _fillLimit(receiver, SY, netSyLeft, limit);
302
+ if (doMarketOrder) {
303
+ _transferOut(address(SY), address(YT), netSyLeft);
304
+ }
305
+ }
306
+
307
+ if (doMarketOrder) {
308
+ (uint256 netYtOutMarket, ) = _readMarket(market).approxSwapExactSyForYt(
309
+ YT.newIndex(),
310
+ netSyLeft,
311
+ block.timestamp,
312
+ guessYtOut
313
+ );
314
+
315
+ (, uint256 netSyFeeMarket) = IPMarket(market).swapExactPtForSy(
316
+ address(YT),
317
+ netYtOutMarket, // exactPtIn = netYtOut
318
+ _encodeSwapExactSyForYt(receiver, YT)
319
+ );
320
+
321
+ netYtOut += netYtOutMarket;
322
+ netSyFee += netSyFeeMarket;
323
+ }
324
+
325
+ if (netYtOut < minYtOut) revert("Slippage: INSUFFICIENT_YT_OUT");
326
+ }
327
+
239
328
  // ----------------- LIMIT ORDERS -----------------
240
329
  function _fillLimit(
241
330
  address receiver,
@@ -284,4 +373,20 @@ abstract contract ActionBase is TokenHelper, IPLimitOrderType {
284
373
  function _isEmptyLimit(LimitOrderData calldata a) internal pure returns (bool) {
285
374
  return a.normalFills.length == 0 && a.flashFills.length == 0;
286
375
  }
376
+
377
+ // ----------------- DELEGATE CALL -----------------
378
+
379
+ function _delegateToSelf(
380
+ bytes memory data,
381
+ bool allowFailure
382
+ ) internal returns (bool success, bytes memory result) {
383
+ (success, result) = address(this).delegatecall(data);
384
+
385
+ if (!success && !allowFailure) {
386
+ assembly {
387
+ // We use Yul's revert() to bubble up errors from the target contract.
388
+ revert(add(32, result), mload(result))
389
+ }
390
+ }
391
+ }
287
392
  }