@uniswap/router-sdk 1.2.0 → 1.4.0

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.
@@ -14,11 +14,14 @@ var sdkCore = require('@uniswap/sdk-core');
14
14
  var IPeripheryPaymentsWithFeeExtended_json = require('@uniswap/swap-router-contracts/artifacts/contracts/interfaces/IPeripheryPaymentsWithFeeExtended.sol/IPeripheryPaymentsWithFeeExtended.json');
15
15
  var ISwapRouter02_json = require('@uniswap/swap-router-contracts/artifacts/contracts/interfaces/ISwapRouter02.sol/ISwapRouter02.json');
16
16
  var v2Sdk = require('@uniswap/v2-sdk');
17
+ var solidity = require('@ethersproject/solidity');
17
18
 
18
19
  var MSG_SENDER = '0x0000000000000000000000000000000000000001';
19
20
  var ADDRESS_THIS = '0x0000000000000000000000000000000000000002';
20
21
  var ZERO = /*#__PURE__*/JSBI.BigInt(0);
21
- var ONE = /*#__PURE__*/JSBI.BigInt(1);
22
+ var ONE = /*#__PURE__*/JSBI.BigInt(1); // = 1 << 23 or 100000000000000000000000
23
+
24
+ var V2_FEE_PATH_PLACEHOLDER = 8388608;
22
25
 
23
26
  (function (ApprovalTypes) {
24
27
  ApprovalTypes[ApprovalTypes["NOT_REQUIRED"] = 0] = "NOT_REQUIRED";
@@ -279,6 +282,24 @@ function _createClass(Constructor, protoProps, staticProps) {
279
282
  return Constructor;
280
283
  }
281
284
 
285
+ function _extends() {
286
+ _extends = Object.assign || function (target) {
287
+ for (var i = 1; i < arguments.length; i++) {
288
+ var source = arguments[i];
289
+
290
+ for (var key in source) {
291
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
292
+ target[key] = source[key];
293
+ }
294
+ }
295
+ }
296
+
297
+ return target;
298
+ };
299
+
300
+ return _extends.apply(this, arguments);
301
+ }
302
+
282
303
  function _inheritsLoose(subClass, superClass) {
283
304
  subClass.prototype = Object.create(superClass.prototype);
284
305
  subClass.prototype.constructor = subClass;
@@ -1093,9 +1114,690 @@ try {
1093
1114
  }
1094
1115
  });
1095
1116
 
1117
+ /**
1118
+ * Represents a list of pools or pairs through which a swap can occur
1119
+ * @template TInput The input token
1120
+ * @template TOutput The output token
1121
+ */
1122
+
1123
+ var MixedRouteSDK = /*#__PURE__*/function () {
1124
+ /**
1125
+ * Creates an instance of route.
1126
+ * @param pools An array of `TPool` objects (pools or pairs), ordered by the route the swap will take
1127
+ * @param input The input token
1128
+ * @param output The output token
1129
+ */
1130
+ function MixedRouteSDK(pools, input, output) {
1131
+ this._midPrice = null;
1132
+ !(pools.length > 0) ? invariant(false, 'POOLS') : void 0;
1133
+ var chainId = pools[0].chainId;
1134
+ var allOnSameChain = pools.every(function (pool) {
1135
+ return pool.chainId === chainId;
1136
+ });
1137
+ !allOnSameChain ? invariant(false, 'CHAIN_IDS') : void 0;
1138
+ var wrappedInput = input.wrapped;
1139
+ !pools[0].involvesToken(wrappedInput) ? invariant(false, 'INPUT') : void 0;
1140
+ !pools[pools.length - 1].involvesToken(output.wrapped) ? invariant(false, 'OUTPUT') : void 0;
1141
+ /**
1142
+ * Normalizes token0-token1 order and selects the next token/fee step to add to the path
1143
+ * */
1144
+
1145
+ var tokenPath = [wrappedInput];
1146
+
1147
+ for (var _iterator = _createForOfIteratorHelperLoose(pools.entries()), _step; !(_step = _iterator()).done;) {
1148
+ var _step$value = _step.value,
1149
+ i = _step$value[0],
1150
+ pool = _step$value[1];
1151
+ var currentInputToken = tokenPath[i];
1152
+ !(currentInputToken.equals(pool.token0) || currentInputToken.equals(pool.token1)) ? invariant(false, 'PATH') : void 0;
1153
+ var nextToken = currentInputToken.equals(pool.token0) ? pool.token1 : pool.token0;
1154
+ tokenPath.push(nextToken);
1155
+ }
1156
+
1157
+ this.pools = pools;
1158
+ this.path = tokenPath;
1159
+ this.input = input;
1160
+ this.output = output != null ? output : tokenPath[tokenPath.length - 1];
1161
+ }
1162
+
1163
+ _createClass(MixedRouteSDK, [{
1164
+ key: "chainId",
1165
+ get: function get() {
1166
+ return this.pools[0].chainId;
1167
+ }
1168
+ /**
1169
+ * Returns the mid price of the route
1170
+ */
1171
+
1172
+ }, {
1173
+ key: "midPrice",
1174
+ get: function get() {
1175
+ if (this._midPrice !== null) return this._midPrice;
1176
+ var price = this.pools.slice(1).reduce(function (_ref, pool) {
1177
+ var nextInput = _ref.nextInput,
1178
+ price = _ref.price;
1179
+ return nextInput.equals(pool.token0) ? {
1180
+ nextInput: pool.token1,
1181
+ price: price.multiply(pool.token0Price)
1182
+ } : {
1183
+ nextInput: pool.token0,
1184
+ price: price.multiply(pool.token1Price)
1185
+ };
1186
+ }, this.pools[0].token0.equals(this.input.wrapped) ? {
1187
+ nextInput: this.pools[0].token1,
1188
+ price: this.pools[0].token0Price
1189
+ } : {
1190
+ nextInput: this.pools[0].token0,
1191
+ price: this.pools[0].token1Price
1192
+ }).price;
1193
+ return this._midPrice = new sdkCore.Price(this.input, this.output, price.denominator, price.numerator);
1194
+ }
1195
+ }]);
1196
+
1197
+ return MixedRouteSDK;
1198
+ }();
1199
+
1200
+ /**
1201
+ * Trades comparator, an extension of the input output comparator that also considers other dimensions of the trade in ranking them
1202
+ * @template TInput The input token, either Ether or an ERC-20
1203
+ * @template TOutput The output token, either Ether or an ERC-20
1204
+ * @template TTradeType The trade type, either exact input or exact output
1205
+ * @param a The first trade to compare
1206
+ * @param b The second trade to compare
1207
+ * @returns A sorted ordering for two neighboring elements in a trade array
1208
+ */
1209
+
1210
+ function tradeComparator(a, b) {
1211
+ // must have same input and output token for comparison
1212
+ !a.inputAmount.currency.equals(b.inputAmount.currency) ? invariant(false, 'INPUT_CURRENCY') : void 0;
1213
+ !a.outputAmount.currency.equals(b.outputAmount.currency) ? invariant(false, 'OUTPUT_CURRENCY') : void 0;
1214
+
1215
+ if (a.outputAmount.equalTo(b.outputAmount)) {
1216
+ if (a.inputAmount.equalTo(b.inputAmount)) {
1217
+ // consider the number of hops since each hop costs gas
1218
+ var aHops = a.swaps.reduce(function (total, cur) {
1219
+ return total + cur.route.path.length;
1220
+ }, 0);
1221
+ var bHops = b.swaps.reduce(function (total, cur) {
1222
+ return total + cur.route.path.length;
1223
+ }, 0);
1224
+ return aHops - bHops;
1225
+ } // trade A requires less input than trade B, so A should come first
1226
+
1227
+
1228
+ if (a.inputAmount.lessThan(b.inputAmount)) {
1229
+ return -1;
1230
+ } else {
1231
+ return 1;
1232
+ }
1233
+ } else {
1234
+ // tradeA has less output than trade B, so should come second
1235
+ if (a.outputAmount.lessThan(b.outputAmount)) {
1236
+ return 1;
1237
+ } else {
1238
+ return -1;
1239
+ }
1240
+ }
1241
+ }
1242
+ /**
1243
+ * Represents a trade executed against a set of routes where some percentage of the input is
1244
+ * split across each route.
1245
+ *
1246
+ * Each route has its own set of pools. Pools can not be re-used across routes.
1247
+ *
1248
+ * Does not account for slippage, i.e., changes in price environment that can occur between
1249
+ * the time the trade is submitted and when it is executed.
1250
+ * @notice This class is functionally the same as the `Trade` class in the `@uniswap/v3-sdk` package, aside from typing and some input validation.
1251
+ * @template TInput The input token, either Ether or an ERC-20
1252
+ * @template TOutput The output token, either Ether or an ERC-20
1253
+ * @template TTradeType The trade type, either exact input or exact output
1254
+ */
1255
+
1256
+ var MixedRouteTrade = /*#__PURE__*/function () {
1257
+ /**
1258
+ * Construct a trade by passing in the pre-computed property values
1259
+ * @param routes The routes through which the trade occurs
1260
+ * @param tradeType The type of trade, exact input or exact output
1261
+ */
1262
+ function MixedRouteTrade(_ref) {
1263
+ var routes = _ref.routes,
1264
+ tradeType = _ref.tradeType;
1265
+ var inputCurrency = routes[0].inputAmount.currency;
1266
+ var outputCurrency = routes[0].outputAmount.currency;
1267
+ !routes.every(function (_ref2) {
1268
+ var route = _ref2.route;
1269
+ return inputCurrency.wrapped.equals(route.input.wrapped);
1270
+ }) ? invariant(false, 'INPUT_CURRENCY_MATCH') : void 0;
1271
+ !routes.every(function (_ref3) {
1272
+ var route = _ref3.route;
1273
+ return outputCurrency.wrapped.equals(route.output.wrapped);
1274
+ }) ? invariant(false, 'OUTPUT_CURRENCY_MATCH') : void 0;
1275
+ var numPools = routes.map(function (_ref4) {
1276
+ var route = _ref4.route;
1277
+ return route.pools.length;
1278
+ }).reduce(function (total, cur) {
1279
+ return total + cur;
1280
+ }, 0);
1281
+ var poolAddressSet = new Set();
1282
+
1283
+ for (var _iterator = _createForOfIteratorHelperLoose(routes), _step; !(_step = _iterator()).done;) {
1284
+ var route = _step.value.route;
1285
+
1286
+ for (var _iterator2 = _createForOfIteratorHelperLoose(route.pools), _step2; !(_step2 = _iterator2()).done;) {
1287
+ var pool = _step2.value;
1288
+ pool instanceof v3Sdk.Pool ? poolAddressSet.add(v3Sdk.Pool.getAddress(pool.token0, pool.token1, pool.fee)) : poolAddressSet.add(v2Sdk.Pair.getAddress(pool.token0, pool.token1));
1289
+ }
1290
+ }
1291
+
1292
+ !(numPools == poolAddressSet.size) ? invariant(false, 'POOLS_DUPLICATED') : void 0;
1293
+ !(tradeType === sdkCore.TradeType.EXACT_INPUT) ? invariant(false, 'TRADE_TYPE') : void 0;
1294
+ this.swaps = routes;
1295
+ this.tradeType = tradeType;
1296
+ }
1297
+ /**
1298
+ * @deprecated Deprecated in favor of 'swaps' property. If the trade consists of multiple routes
1299
+ * this will return an error.
1300
+ *
1301
+ * When the trade consists of just a single route, this returns the route of the trade,
1302
+ * i.e. which pools the trade goes through.
1303
+ */
1304
+
1305
+
1306
+ /**
1307
+ * Constructs a trade by simulating swaps through the given route
1308
+ * @template TInput The input token, either Ether or an ERC-20.
1309
+ * @template TOutput The output token, either Ether or an ERC-20.
1310
+ * @template TTradeType The type of the trade, either exact in or exact out.
1311
+ * @param route route to swap through
1312
+ * @param amount the amount specified, either input or output, depending on tradeType
1313
+ * @param tradeType whether the trade is an exact input or exact output swap
1314
+ * @returns The route
1315
+ */
1316
+ MixedRouteTrade.fromRoute =
1317
+ /*#__PURE__*/
1318
+ function () {
1319
+ var _fromRoute = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(route, amount, tradeType) {
1320
+ var amounts, inputAmount, outputAmount, i, pool, _yield$pool$getOutput, _outputAmount;
1321
+
1322
+ return runtime_1.wrap(function _callee$(_context) {
1323
+ while (1) {
1324
+ switch (_context.prev = _context.next) {
1325
+ case 0:
1326
+ amounts = new Array(route.path.length);
1327
+ !(tradeType === sdkCore.TradeType.EXACT_INPUT) ? invariant(false, 'TRADE_TYPE') : void 0;
1328
+ !amount.currency.equals(route.input) ? invariant(false, 'INPUT') : void 0;
1329
+ amounts[0] = amount.wrapped;
1330
+ i = 0;
1331
+
1332
+ case 5:
1333
+ if (!(i < route.path.length - 1)) {
1334
+ _context.next = 15;
1335
+ break;
1336
+ }
1337
+
1338
+ pool = route.pools[i];
1339
+ _context.next = 9;
1340
+ return pool.getOutputAmount(amounts[i]);
1341
+
1342
+ case 9:
1343
+ _yield$pool$getOutput = _context.sent;
1344
+ _outputAmount = _yield$pool$getOutput[0];
1345
+ amounts[i + 1] = _outputAmount;
1346
+
1347
+ case 12:
1348
+ i++;
1349
+ _context.next = 5;
1350
+ break;
1351
+
1352
+ case 15:
1353
+ inputAmount = sdkCore.CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator);
1354
+ outputAmount = sdkCore.CurrencyAmount.fromFractionalAmount(route.output, amounts[amounts.length - 1].numerator, amounts[amounts.length - 1].denominator);
1355
+ return _context.abrupt("return", new MixedRouteTrade({
1356
+ routes: [{
1357
+ inputAmount: inputAmount,
1358
+ outputAmount: outputAmount,
1359
+ route: route
1360
+ }],
1361
+ tradeType: tradeType
1362
+ }));
1363
+
1364
+ case 18:
1365
+ case "end":
1366
+ return _context.stop();
1367
+ }
1368
+ }
1369
+ }, _callee);
1370
+ }));
1371
+
1372
+ function fromRoute(_x, _x2, _x3) {
1373
+ return _fromRoute.apply(this, arguments);
1374
+ }
1375
+
1376
+ return fromRoute;
1377
+ }()
1378
+ /**
1379
+ * Constructs a trade from routes by simulating swaps
1380
+ *
1381
+ * @template TInput The input token, either Ether or an ERC-20.
1382
+ * @template TOutput The output token, either Ether or an ERC-20.
1383
+ * @template TTradeType The type of the trade, either exact in or exact out.
1384
+ * @param routes the routes to swap through and how much of the amount should be routed through each
1385
+ * @param tradeType whether the trade is an exact input or exact output swap
1386
+ * @returns The trade
1387
+ */
1388
+ ;
1389
+
1390
+ MixedRouteTrade.fromRoutes =
1391
+ /*#__PURE__*/
1392
+ function () {
1393
+ var _fromRoutes = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(routes, tradeType) {
1394
+ var populatedRoutes, _iterator3, _step3, _step3$value, route, amount, amounts, inputAmount, outputAmount, i, pool, _yield$pool$getOutput2, _outputAmount2;
1395
+
1396
+ return runtime_1.wrap(function _callee2$(_context2) {
1397
+ while (1) {
1398
+ switch (_context2.prev = _context2.next) {
1399
+ case 0:
1400
+ populatedRoutes = [];
1401
+ !(tradeType === sdkCore.TradeType.EXACT_INPUT) ? invariant(false, 'TRADE_TYPE') : void 0;
1402
+ _iterator3 = _createForOfIteratorHelperLoose(routes);
1403
+
1404
+ case 3:
1405
+ if ((_step3 = _iterator3()).done) {
1406
+ _context2.next = 26;
1407
+ break;
1408
+ }
1409
+
1410
+ _step3$value = _step3.value, route = _step3$value.route, amount = _step3$value.amount;
1411
+ amounts = new Array(route.path.length);
1412
+ inputAmount = void 0;
1413
+ outputAmount = void 0;
1414
+ !amount.currency.equals(route.input) ? invariant(false, 'INPUT') : void 0;
1415
+ inputAmount = sdkCore.CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator);
1416
+ amounts[0] = sdkCore.CurrencyAmount.fromFractionalAmount(route.input.wrapped, amount.numerator, amount.denominator);
1417
+ i = 0;
1418
+
1419
+ case 12:
1420
+ if (!(i < route.path.length - 1)) {
1421
+ _context2.next = 22;
1422
+ break;
1423
+ }
1424
+
1425
+ pool = route.pools[i];
1426
+ _context2.next = 16;
1427
+ return pool.getOutputAmount(amounts[i]);
1428
+
1429
+ case 16:
1430
+ _yield$pool$getOutput2 = _context2.sent;
1431
+ _outputAmount2 = _yield$pool$getOutput2[0];
1432
+ amounts[i + 1] = _outputAmount2;
1433
+
1434
+ case 19:
1435
+ i++;
1436
+ _context2.next = 12;
1437
+ break;
1438
+
1439
+ case 22:
1440
+ outputAmount = sdkCore.CurrencyAmount.fromFractionalAmount(route.output, amounts[amounts.length - 1].numerator, amounts[amounts.length - 1].denominator);
1441
+ populatedRoutes.push({
1442
+ route: route,
1443
+ inputAmount: inputAmount,
1444
+ outputAmount: outputAmount
1445
+ });
1446
+
1447
+ case 24:
1448
+ _context2.next = 3;
1449
+ break;
1450
+
1451
+ case 26:
1452
+ return _context2.abrupt("return", new MixedRouteTrade({
1453
+ routes: populatedRoutes,
1454
+ tradeType: tradeType
1455
+ }));
1456
+
1457
+ case 27:
1458
+ case "end":
1459
+ return _context2.stop();
1460
+ }
1461
+ }
1462
+ }, _callee2);
1463
+ }));
1464
+
1465
+ function fromRoutes(_x4, _x5) {
1466
+ return _fromRoutes.apply(this, arguments);
1467
+ }
1468
+
1469
+ return fromRoutes;
1470
+ }()
1471
+ /**
1472
+ * Creates a trade without computing the result of swapping through the route. Useful when you have simulated the trade
1473
+ * elsewhere and do not have any tick data
1474
+ * @template TInput The input token, either Ether or an ERC-20
1475
+ * @template TOutput The output token, either Ether or an ERC-20
1476
+ * @template TTradeType The type of the trade, either exact in or exact out
1477
+ * @param constructorArguments The arguments passed to the trade constructor
1478
+ * @returns The unchecked trade
1479
+ */
1480
+ ;
1481
+
1482
+ MixedRouteTrade.createUncheckedTrade = function createUncheckedTrade(constructorArguments) {
1483
+ return new MixedRouteTrade(_extends({}, constructorArguments, {
1484
+ routes: [{
1485
+ inputAmount: constructorArguments.inputAmount,
1486
+ outputAmount: constructorArguments.outputAmount,
1487
+ route: constructorArguments.route
1488
+ }]
1489
+ }));
1490
+ }
1491
+ /**
1492
+ * Creates a trade without computing the result of swapping through the routes. Useful when you have simulated the trade
1493
+ * elsewhere and do not have any tick data
1494
+ * @template TInput The input token, either Ether or an ERC-20
1495
+ * @template TOutput The output token, either Ether or an ERC-20
1496
+ * @template TTradeType The type of the trade, either exact in or exact out
1497
+ * @param constructorArguments The arguments passed to the trade constructor
1498
+ * @returns The unchecked trade
1499
+ */
1500
+ ;
1501
+
1502
+ MixedRouteTrade.createUncheckedTradeWithMultipleRoutes = function createUncheckedTradeWithMultipleRoutes(constructorArguments) {
1503
+ return new MixedRouteTrade(constructorArguments);
1504
+ }
1505
+ /**
1506
+ * Get the minimum amount that must be received from this trade for the given slippage tolerance
1507
+ * @param slippageTolerance The tolerance of unfavorable slippage from the execution price of this trade
1508
+ * @returns The amount out
1509
+ */
1510
+ ;
1511
+
1512
+ var _proto = MixedRouteTrade.prototype;
1513
+
1514
+ _proto.minimumAmountOut = function minimumAmountOut(slippageTolerance, amountOut) {
1515
+ if (amountOut === void 0) {
1516
+ amountOut = this.outputAmount;
1517
+ }
1518
+
1519
+ !!slippageTolerance.lessThan(ZERO) ? invariant(false, 'SLIPPAGE_TOLERANCE') : void 0; /// does not support exactOutput, as enforced in the constructor
1520
+
1521
+ var slippageAdjustedAmountOut = new sdkCore.Fraction(ONE).add(slippageTolerance).invert().multiply(amountOut.quotient).quotient;
1522
+ return sdkCore.CurrencyAmount.fromRawAmount(amountOut.currency, slippageAdjustedAmountOut);
1523
+ }
1524
+ /**
1525
+ * Get the maximum amount in that can be spent via this trade for the given slippage tolerance
1526
+ * @param slippageTolerance The tolerance of unfavorable slippage from the execution price of this trade
1527
+ * @returns The amount in
1528
+ */
1529
+ ;
1530
+
1531
+ _proto.maximumAmountIn = function maximumAmountIn(slippageTolerance, amountIn) {
1532
+ if (amountIn === void 0) {
1533
+ amountIn = this.inputAmount;
1534
+ }
1535
+
1536
+ !!slippageTolerance.lessThan(ZERO) ? invariant(false, 'SLIPPAGE_TOLERANCE') : void 0;
1537
+ return amountIn; /// does not support exactOutput
1538
+ }
1539
+ /**
1540
+ * Return the execution price after accounting for slippage tolerance
1541
+ * @param slippageTolerance the allowed tolerated slippage
1542
+ * @returns The execution price
1543
+ */
1544
+ ;
1545
+
1546
+ _proto.worstExecutionPrice = function worstExecutionPrice(slippageTolerance) {
1547
+ return new sdkCore.Price(this.inputAmount.currency, this.outputAmount.currency, this.maximumAmountIn(slippageTolerance).quotient, this.minimumAmountOut(slippageTolerance).quotient);
1548
+ }
1549
+ /**
1550
+ * Given a list of pools, and a fixed amount in, returns the top `maxNumResults` trades that go from an input token
1551
+ * amount to an output token, making at most `maxHops` hops.
1552
+ * Note this does not consider aggregation, as routes are linear. It's possible a better route exists by splitting
1553
+ * the amount in among multiple routes.
1554
+ * @param pools the pools to consider in finding the best trade
1555
+ * @param nextAmountIn exact amount of input currency to spend
1556
+ * @param currencyOut the desired currency out
1557
+ * @param maxNumResults maximum number of results to return
1558
+ * @param maxHops maximum number of hops a returned trade can make, e.g. 1 hop goes through a single pool
1559
+ * @param currentPools used in recursion; the current list of pools
1560
+ * @param currencyAmountIn used in recursion; the original value of the currencyAmountIn parameter
1561
+ * @param bestTrades used in recursion; the current list of best trades
1562
+ * @returns The exact in trade
1563
+ */
1564
+ ;
1565
+
1566
+ MixedRouteTrade.bestTradeExactIn =
1567
+ /*#__PURE__*/
1568
+ function () {
1569
+ var _bestTradeExactIn = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(pools, currencyAmountIn, currencyOut, _temp, // used in recursion.
1570
+ currentPools, nextAmountIn, bestTrades) {
1571
+ var _ref5, _ref5$maxNumResults, maxNumResults, _ref5$maxHops, maxHops, amountIn, tokenOut, i, pool, amountOut, _yield$pool$getOutput3, poolsExcludingThisPool;
1572
+
1573
+ return runtime_1.wrap(function _callee3$(_context3) {
1574
+ while (1) {
1575
+ switch (_context3.prev = _context3.next) {
1576
+ case 0:
1577
+ _ref5 = _temp === void 0 ? {} : _temp, _ref5$maxNumResults = _ref5.maxNumResults, maxNumResults = _ref5$maxNumResults === void 0 ? 3 : _ref5$maxNumResults, _ref5$maxHops = _ref5.maxHops, maxHops = _ref5$maxHops === void 0 ? 3 : _ref5$maxHops;
1578
+
1579
+ if (currentPools === void 0) {
1580
+ currentPools = [];
1581
+ }
1582
+
1583
+ if (nextAmountIn === void 0) {
1584
+ nextAmountIn = currencyAmountIn;
1585
+ }
1586
+
1587
+ if (bestTrades === void 0) {
1588
+ bestTrades = [];
1589
+ }
1590
+
1591
+ !(pools.length > 0) ? invariant(false, 'POOLS') : void 0;
1592
+ !(maxHops > 0) ? invariant(false, 'MAX_HOPS') : void 0;
1593
+ !(currencyAmountIn === nextAmountIn || currentPools.length > 0) ? invariant(false, 'INVALID_RECURSION') : void 0;
1594
+ amountIn = nextAmountIn.wrapped;
1595
+ tokenOut = currencyOut.wrapped;
1596
+ i = 0;
1597
+
1598
+ case 10:
1599
+ if (!(i < pools.length)) {
1600
+ _context3.next = 49;
1601
+ break;
1602
+ }
1603
+
1604
+ pool = pools[i]; // pool irrelevant
1605
+
1606
+ if (!(!pool.token0.equals(amountIn.currency) && !pool.token1.equals(amountIn.currency))) {
1607
+ _context3.next = 14;
1608
+ break;
1609
+ }
1610
+
1611
+ return _context3.abrupt("continue", 46);
1612
+
1613
+ case 14:
1614
+ if (!(pool instanceof v2Sdk.Pair)) {
1615
+ _context3.next = 17;
1616
+ break;
1617
+ }
1618
+
1619
+ if (!(pool.reserve0.equalTo(ZERO) || pool.reserve1.equalTo(ZERO))) {
1620
+ _context3.next = 17;
1621
+ break;
1622
+ }
1623
+
1624
+ return _context3.abrupt("continue", 46);
1625
+
1626
+ case 17:
1627
+ amountOut = void 0;
1628
+ _context3.prev = 18;
1629
+ _context3.next = 22;
1630
+ return pool.getOutputAmount(amountIn);
1631
+
1632
+ case 22:
1633
+ _yield$pool$getOutput3 = _context3.sent;
1634
+ amountOut = _yield$pool$getOutput3[0];
1635
+ _context3.next = 31;
1636
+ break;
1637
+
1638
+ case 26:
1639
+ _context3.prev = 26;
1640
+ _context3.t0 = _context3["catch"](18);
1641
+
1642
+ if (!_context3.t0.isInsufficientInputAmountError) {
1643
+ _context3.next = 30;
1644
+ break;
1645
+ }
1646
+
1647
+ return _context3.abrupt("continue", 46);
1648
+
1649
+ case 30:
1650
+ throw _context3.t0;
1651
+
1652
+ case 31:
1653
+ if (!(amountOut.currency.isToken && amountOut.currency.equals(tokenOut))) {
1654
+ _context3.next = 42;
1655
+ break;
1656
+ }
1657
+
1658
+ _context3.t1 = sdkCore.sortedInsert;
1659
+ _context3.t2 = bestTrades;
1660
+ _context3.next = 36;
1661
+ return MixedRouteTrade.fromRoute(new MixedRouteSDK([].concat(currentPools, [pool]), currencyAmountIn.currency, currencyOut), currencyAmountIn, sdkCore.TradeType.EXACT_INPUT);
1662
+
1663
+ case 36:
1664
+ _context3.t3 = _context3.sent;
1665
+ _context3.t4 = maxNumResults;
1666
+ _context3.t5 = tradeComparator;
1667
+ (0, _context3.t1)(_context3.t2, _context3.t3, _context3.t4, _context3.t5);
1668
+ _context3.next = 46;
1669
+ break;
1670
+
1671
+ case 42:
1672
+ if (!(maxHops > 1 && pools.length > 1)) {
1673
+ _context3.next = 46;
1674
+ break;
1675
+ }
1676
+
1677
+ poolsExcludingThisPool = pools.slice(0, i).concat(pools.slice(i + 1, pools.length)); // otherwise, consider all the other paths that lead from this token as long as we have not exceeded maxHops
1678
+
1679
+ _context3.next = 46;
1680
+ return MixedRouteTrade.bestTradeExactIn(poolsExcludingThisPool, currencyAmountIn, currencyOut, {
1681
+ maxNumResults: maxNumResults,
1682
+ maxHops: maxHops - 1
1683
+ }, [].concat(currentPools, [pool]), amountOut, bestTrades);
1684
+
1685
+ case 46:
1686
+ i++;
1687
+ _context3.next = 10;
1688
+ break;
1689
+
1690
+ case 49:
1691
+ return _context3.abrupt("return", bestTrades);
1692
+
1693
+ case 50:
1694
+ case "end":
1695
+ return _context3.stop();
1696
+ }
1697
+ }
1698
+ }, _callee3, null, [[18, 26]]);
1699
+ }));
1700
+
1701
+ function bestTradeExactIn(_x6, _x7, _x8, _x9, _x10, _x11, _x12) {
1702
+ return _bestTradeExactIn.apply(this, arguments);
1703
+ }
1704
+
1705
+ return bestTradeExactIn;
1706
+ }();
1707
+
1708
+ _createClass(MixedRouteTrade, [{
1709
+ key: "route",
1710
+ get: function get() {
1711
+ !(this.swaps.length == 1) ? invariant(false, 'MULTIPLE_ROUTES') : void 0;
1712
+ return this.swaps[0].route;
1713
+ }
1714
+ /**
1715
+ * The input amount for the trade assuming no slippage.
1716
+ */
1717
+
1718
+ }, {
1719
+ key: "inputAmount",
1720
+ get: function get() {
1721
+ if (this._inputAmount) {
1722
+ return this._inputAmount;
1723
+ }
1724
+
1725
+ var inputCurrency = this.swaps[0].inputAmount.currency;
1726
+ var totalInputFromRoutes = this.swaps.map(function (_ref6) {
1727
+ var inputAmount = _ref6.inputAmount;
1728
+ return inputAmount;
1729
+ }).reduce(function (total, cur) {
1730
+ return total.add(cur);
1731
+ }, sdkCore.CurrencyAmount.fromRawAmount(inputCurrency, 0));
1732
+ this._inputAmount = totalInputFromRoutes;
1733
+ return this._inputAmount;
1734
+ }
1735
+ /**
1736
+ * The output amount for the trade assuming no slippage.
1737
+ */
1738
+
1739
+ }, {
1740
+ key: "outputAmount",
1741
+ get: function get() {
1742
+ if (this._outputAmount) {
1743
+ return this._outputAmount;
1744
+ }
1745
+
1746
+ var outputCurrency = this.swaps[0].outputAmount.currency;
1747
+ var totalOutputFromRoutes = this.swaps.map(function (_ref7) {
1748
+ var outputAmount = _ref7.outputAmount;
1749
+ return outputAmount;
1750
+ }).reduce(function (total, cur) {
1751
+ return total.add(cur);
1752
+ }, sdkCore.CurrencyAmount.fromRawAmount(outputCurrency, 0));
1753
+ this._outputAmount = totalOutputFromRoutes;
1754
+ return this._outputAmount;
1755
+ }
1756
+ /**
1757
+ * The price expressed in terms of output amount/input amount.
1758
+ */
1759
+
1760
+ }, {
1761
+ key: "executionPrice",
1762
+ get: function get() {
1763
+ var _this$_executionPrice;
1764
+
1765
+ return (_this$_executionPrice = this._executionPrice) != null ? _this$_executionPrice : this._executionPrice = new sdkCore.Price(this.inputAmount.currency, this.outputAmount.currency, this.inputAmount.quotient, this.outputAmount.quotient);
1766
+ }
1767
+ /**
1768
+ * Returns the percent difference between the route's mid price and the price impact
1769
+ */
1770
+
1771
+ }, {
1772
+ key: "priceImpact",
1773
+ get: function get() {
1774
+ if (this._priceImpact) {
1775
+ return this._priceImpact;
1776
+ }
1777
+
1778
+ var spotOutputAmount = sdkCore.CurrencyAmount.fromRawAmount(this.outputAmount.currency, 0);
1779
+
1780
+ for (var _iterator4 = _createForOfIteratorHelperLoose(this.swaps), _step4; !(_step4 = _iterator4()).done;) {
1781
+ var _step4$value = _step4.value,
1782
+ route = _step4$value.route,
1783
+ inputAmount = _step4$value.inputAmount;
1784
+ var midPrice = route.midPrice;
1785
+ spotOutputAmount = spotOutputAmount.add(midPrice.quote(inputAmount));
1786
+ }
1787
+
1788
+ var priceImpact = spotOutputAmount.subtract(this.outputAmount).divide(spotOutputAmount);
1789
+ this._priceImpact = new sdkCore.Percent(priceImpact.numerator, priceImpact.denominator);
1790
+ return this._priceImpact;
1791
+ }
1792
+ }]);
1793
+
1794
+ return MixedRouteTrade;
1795
+ }();
1796
+
1096
1797
  (function (Protocol) {
1097
1798
  Protocol["V2"] = "V2";
1098
1799
  Protocol["V3"] = "V3";
1800
+ Protocol["MIXED"] = "MIXED";
1099
1801
  })(exports.Protocol || (exports.Protocol = {}));
1100
1802
 
1101
1803
  var RouteV2 = /*#__PURE__*/function (_V2RouteSDK) {
@@ -1126,28 +1828,45 @@ var RouteV3 = /*#__PURE__*/function (_V3RouteSDK) {
1126
1828
  }
1127
1829
 
1128
1830
  return RouteV3;
1129
- }(v3Sdk.Route);
1831
+ }(v3Sdk.Route); // Mixed route wrapper
1832
+
1833
+ var MixedRoute = /*#__PURE__*/function (_MixedRouteSDK) {
1834
+ _inheritsLoose(MixedRoute, _MixedRouteSDK);
1835
+
1836
+ function MixedRoute(mixedRoute) {
1837
+ var _this3;
1838
+
1839
+ _this3 = _MixedRouteSDK.call(this, mixedRoute.pools, mixedRoute.input, mixedRoute.output) || this;
1840
+ _this3.protocol = exports.Protocol.MIXED;
1841
+ return _this3;
1842
+ }
1843
+
1844
+ return MixedRoute;
1845
+ }(MixedRouteSDK);
1130
1846
 
1131
1847
  var Trade = /*#__PURE__*/function () {
1132
1848
  // construct a trade across v2 and v3 routes from pre-computed amounts
1133
1849
  function Trade(_ref) {
1134
1850
  var v2Routes = _ref.v2Routes,
1135
1851
  v3Routes = _ref.v3Routes,
1136
- tradeType = _ref.tradeType;
1852
+ tradeType = _ref.tradeType,
1853
+ mixedRoutes = _ref.mixedRoutes;
1137
1854
  this.swaps = [];
1138
1855
  this.routes = []; // wrap v2 routes
1139
1856
 
1140
1857
  for (var _iterator = _createForOfIteratorHelperLoose(v2Routes), _step; !(_step = _iterator()).done;) {
1141
1858
  var _step$value = _step.value,
1142
1859
  routev2 = _step$value.routev2,
1143
- inputAmount = _step$value.inputAmount,
1144
- outputAmount = _step$value.outputAmount;
1145
- var route = new RouteV2(routev2);
1146
- this.routes.push(route);
1860
+ _inputAmount = _step$value.inputAmount,
1861
+ _outputAmount = _step$value.outputAmount;
1862
+
1863
+ var _route = new RouteV2(routev2);
1864
+
1865
+ this.routes.push(_route);
1147
1866
  this.swaps.push({
1148
- route: route,
1149
- inputAmount: inputAmount,
1150
- outputAmount: outputAmount
1867
+ route: _route,
1868
+ inputAmount: _inputAmount,
1869
+ outputAmount: _outputAmount
1151
1870
  });
1152
1871
  } // wrap v3 routes
1153
1872
 
@@ -1155,17 +1874,34 @@ var Trade = /*#__PURE__*/function () {
1155
1874
  for (var _iterator2 = _createForOfIteratorHelperLoose(v3Routes), _step2; !(_step2 = _iterator2()).done;) {
1156
1875
  var _step2$value = _step2.value,
1157
1876
  routev3 = _step2$value.routev3,
1158
- _inputAmount = _step2$value.inputAmount,
1159
- _outputAmount = _step2$value.outputAmount;
1877
+ _inputAmount2 = _step2$value.inputAmount,
1878
+ _outputAmount2 = _step2$value.outputAmount;
1160
1879
 
1161
- var _route = new RouteV3(routev3);
1880
+ var _route2 = new RouteV3(routev3);
1162
1881
 
1163
- this.routes.push(_route);
1882
+ this.routes.push(_route2);
1164
1883
  this.swaps.push({
1165
- route: _route,
1166
- inputAmount: _inputAmount,
1167
- outputAmount: _outputAmount
1884
+ route: _route2,
1885
+ inputAmount: _inputAmount2,
1886
+ outputAmount: _outputAmount2
1168
1887
  });
1888
+ } // wrap mixedRoutes
1889
+
1890
+
1891
+ if (mixedRoutes) {
1892
+ for (var _iterator3 = _createForOfIteratorHelperLoose(mixedRoutes), _step3; !(_step3 = _iterator3()).done;) {
1893
+ var _step3$value = _step3.value,
1894
+ mixedRoute = _step3$value.mixedRoute,
1895
+ inputAmount = _step3$value.inputAmount,
1896
+ outputAmount = _step3$value.outputAmount;
1897
+ var route = new MixedRoute(mixedRoute);
1898
+ this.routes.push(route);
1899
+ this.swaps.push({
1900
+ route: route,
1901
+ inputAmount: inputAmount,
1902
+ outputAmount: outputAmount
1903
+ });
1904
+ }
1169
1905
  }
1170
1906
 
1171
1907
  this.tradeType = tradeType; // each route must have the same input and output currency
@@ -1189,17 +1925,19 @@ var Trade = /*#__PURE__*/function () {
1189
1925
  }, 0);
1190
1926
  var poolAddressSet = new Set();
1191
1927
 
1192
- for (var _iterator3 = _createForOfIteratorHelperLoose(this.swaps), _step3; !(_step3 = _iterator3()).done;) {
1193
- var _route2 = _step3.value.route;
1928
+ for (var _iterator4 = _createForOfIteratorHelperLoose(this.swaps), _step4; !(_step4 = _iterator4()).done;) {
1929
+ var _route3 = _step4.value.route;
1194
1930
 
1195
- for (var _iterator4 = _createForOfIteratorHelperLoose(_route2.pools), _step4; !(_step4 = _iterator4()).done;) {
1196
- var pool = _step4.value;
1931
+ for (var _iterator5 = _createForOfIteratorHelperLoose(_route3.pools), _step5; !(_step5 = _iterator5()).done;) {
1932
+ var pool = _step5.value;
1197
1933
 
1198
- if (_route2.protocol == exports.Protocol.V3) {
1934
+ if (pool instanceof v3Sdk.Pool) {
1199
1935
  poolAddressSet.add(v3Sdk.Pool.getAddress(pool.token0, pool.token1, pool.fee));
1200
- } else {
1936
+ } else if (pool instanceof v2Sdk.Pair) {
1201
1937
  var pair = pool;
1202
1938
  poolAddressSet.add(v2Sdk.Pair.getAddress(pair.token0, pair.token1));
1939
+ } else {
1940
+ throw new Error('Unexpected pool type in route when constructing trade object');
1203
1941
  }
1204
1942
  }
1205
1943
  }
@@ -1261,8 +1999,8 @@ var Trade = /*#__PURE__*/function () {
1261
1999
  };
1262
2000
 
1263
2001
  Trade.fromRoutes = /*#__PURE__*/function () {
1264
- var _fromRoutes = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(v2Routes, v3Routes, tradeType) {
1265
- var populatedV2Routes, populatedV3Routes, _iterator5, _step5, _step5$value, routev2, amount, v2Trade, inputAmount, outputAmount, _iterator6, _step6, _step6$value, routev3, _amount, v3Trade, _inputAmount2, _outputAmount2;
2002
+ var _fromRoutes = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(v2Routes, v3Routes, tradeType, mixedRoutes) {
2003
+ var populatedV2Routes, populatedV3Routes, populatedMixedRoutes, _iterator6, _step6, _step6$value, routev2, _amount, v2Trade, _inputAmount3, _outputAmount3, _iterator7, _step7, _step7$value, routev3, _amount2, v3Trade, _inputAmount4, _outputAmount4, _iterator8, _step8, _step8$value, mixedRoute, amount, mixedRouteTrade, inputAmount, outputAmount;
1266
2004
 
1267
2005
  return runtime_1.wrap(function _callee$(_context) {
1268
2006
  while (1) {
@@ -1270,51 +2008,84 @@ var Trade = /*#__PURE__*/function () {
1270
2008
  case 0:
1271
2009
  populatedV2Routes = [];
1272
2010
  populatedV3Routes = [];
2011
+ populatedMixedRoutes = [];
1273
2012
 
1274
- for (_iterator5 = _createForOfIteratorHelperLoose(v2Routes); !(_step5 = _iterator5()).done;) {
1275
- _step5$value = _step5.value, routev2 = _step5$value.routev2, amount = _step5$value.amount;
1276
- v2Trade = new v2Sdk.Trade(routev2, amount, tradeType);
1277
- inputAmount = v2Trade.inputAmount, outputAmount = v2Trade.outputAmount;
2013
+ for (_iterator6 = _createForOfIteratorHelperLoose(v2Routes); !(_step6 = _iterator6()).done;) {
2014
+ _step6$value = _step6.value, routev2 = _step6$value.routev2, _amount = _step6$value.amount;
2015
+ v2Trade = new v2Sdk.Trade(routev2, _amount, tradeType);
2016
+ _inputAmount3 = v2Trade.inputAmount, _outputAmount3 = v2Trade.outputAmount;
1278
2017
  populatedV2Routes.push({
1279
2018
  routev2: routev2,
1280
- inputAmount: inputAmount,
1281
- outputAmount: outputAmount
2019
+ inputAmount: _inputAmount3,
2020
+ outputAmount: _outputAmount3
1282
2021
  });
1283
2022
  }
1284
2023
 
1285
- _iterator6 = _createForOfIteratorHelperLoose(v3Routes);
2024
+ _iterator7 = _createForOfIteratorHelperLoose(v3Routes);
1286
2025
 
1287
- case 4:
1288
- if ((_step6 = _iterator6()).done) {
1289
- _context.next = 13;
2026
+ case 5:
2027
+ if ((_step7 = _iterator7()).done) {
2028
+ _context.next = 14;
1290
2029
  break;
1291
2030
  }
1292
2031
 
1293
- _step6$value = _step6.value, routev3 = _step6$value.routev3, _amount = _step6$value.amount;
1294
- _context.next = 8;
1295
- return v3Sdk.Trade.fromRoute(routev3, _amount, tradeType);
2032
+ _step7$value = _step7.value, routev3 = _step7$value.routev3, _amount2 = _step7$value.amount;
2033
+ _context.next = 9;
2034
+ return v3Sdk.Trade.fromRoute(routev3, _amount2, tradeType);
1296
2035
 
1297
- case 8:
2036
+ case 9:
1298
2037
  v3Trade = _context.sent;
1299
- _inputAmount2 = v3Trade.inputAmount, _outputAmount2 = v3Trade.outputAmount;
2038
+ _inputAmount4 = v3Trade.inputAmount, _outputAmount4 = v3Trade.outputAmount;
1300
2039
  populatedV3Routes.push({
1301
2040
  routev3: routev3,
1302
- inputAmount: _inputAmount2,
1303
- outputAmount: _outputAmount2
2041
+ inputAmount: _inputAmount4,
2042
+ outputAmount: _outputAmount4
1304
2043
  });
1305
2044
 
1306
- case 11:
1307
- _context.next = 4;
2045
+ case 12:
2046
+ _context.next = 5;
1308
2047
  break;
1309
2048
 
1310
- case 13:
2049
+ case 14:
2050
+ if (!mixedRoutes) {
2051
+ _context.next = 25;
2052
+ break;
2053
+ }
2054
+
2055
+ _iterator8 = _createForOfIteratorHelperLoose(mixedRoutes);
2056
+
2057
+ case 16:
2058
+ if ((_step8 = _iterator8()).done) {
2059
+ _context.next = 25;
2060
+ break;
2061
+ }
2062
+
2063
+ _step8$value = _step8.value, mixedRoute = _step8$value.mixedRoute, amount = _step8$value.amount;
2064
+ _context.next = 20;
2065
+ return MixedRouteTrade.fromRoute(mixedRoute, amount, tradeType);
2066
+
2067
+ case 20:
2068
+ mixedRouteTrade = _context.sent;
2069
+ inputAmount = mixedRouteTrade.inputAmount, outputAmount = mixedRouteTrade.outputAmount;
2070
+ populatedMixedRoutes.push({
2071
+ mixedRoute: mixedRoute,
2072
+ inputAmount: inputAmount,
2073
+ outputAmount: outputAmount
2074
+ });
2075
+
2076
+ case 23:
2077
+ _context.next = 16;
2078
+ break;
2079
+
2080
+ case 25:
1311
2081
  return _context.abrupt("return", new Trade({
1312
2082
  v2Routes: populatedV2Routes,
1313
2083
  v3Routes: populatedV3Routes,
2084
+ mixedRoutes: populatedMixedRoutes,
1314
2085
  tradeType: tradeType
1315
2086
  }));
1316
2087
 
1317
- case 14:
2088
+ case 26:
1318
2089
  case "end":
1319
2090
  return _context.stop();
1320
2091
  }
@@ -1322,7 +2093,7 @@ var Trade = /*#__PURE__*/function () {
1322
2093
  }, _callee);
1323
2094
  }));
1324
2095
 
1325
- function fromRoutes(_x, _x2, _x3) {
2096
+ function fromRoutes(_x, _x2, _x3, _x4) {
1326
2097
  return _fromRoutes.apply(this, arguments);
1327
2098
  }
1328
2099
 
@@ -1331,14 +2102,18 @@ var Trade = /*#__PURE__*/function () {
1331
2102
 
1332
2103
  Trade.fromRoute = /*#__PURE__*/function () {
1333
2104
  var _fromRoute = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(route, amount, tradeType) {
1334
- var v2Routes, v3Routes, v2Trade, inputAmount, outputAmount, v3Trade, _inputAmount3, _outputAmount3;
2105
+ var v2Routes, v3Routes, mixedRoutes, v2Trade, inputAmount, outputAmount, v3Trade, _inputAmount5, _outputAmount5, mixedRouteTrade, _inputAmount6, _outputAmount6;
1335
2106
 
1336
2107
  return runtime_1.wrap(function _callee2$(_context2) {
1337
2108
  while (1) {
1338
2109
  switch (_context2.prev = _context2.next) {
1339
2110
  case 0:
2111
+ v2Routes = [];
2112
+ v3Routes = [];
2113
+ mixedRoutes = [];
2114
+
1340
2115
  if (!(route instanceof v2Sdk.Route)) {
1341
- _context2.next = 7;
2116
+ _context2.next = 9;
1342
2117
  break;
1343
2118
  }
1344
2119
 
@@ -1349,32 +2124,61 @@ var Trade = /*#__PURE__*/function () {
1349
2124
  inputAmount: inputAmount,
1350
2125
  outputAmount: outputAmount
1351
2126
  }];
1352
- v3Routes = [];
1353
- _context2.next = 13;
2127
+ _context2.next = 26;
1354
2128
  break;
1355
2129
 
1356
- case 7:
1357
- _context2.next = 9;
2130
+ case 9:
2131
+ if (!(route instanceof v3Sdk.Route)) {
2132
+ _context2.next = 17;
2133
+ break;
2134
+ }
2135
+
2136
+ _context2.next = 12;
1358
2137
  return v3Sdk.Trade.fromRoute(route, amount, tradeType);
1359
2138
 
1360
- case 9:
2139
+ case 12:
1361
2140
  v3Trade = _context2.sent;
1362
- _inputAmount3 = v3Trade.inputAmount, _outputAmount3 = v3Trade.outputAmount;
2141
+ _inputAmount5 = v3Trade.inputAmount, _outputAmount5 = v3Trade.outputAmount;
1363
2142
  v3Routes = [{
1364
2143
  routev3: route,
1365
- inputAmount: _inputAmount3,
1366
- outputAmount: _outputAmount3
2144
+ inputAmount: _inputAmount5,
2145
+ outputAmount: _outputAmount5
1367
2146
  }];
1368
- v2Routes = [];
2147
+ _context2.next = 26;
2148
+ break;
2149
+
2150
+ case 17:
2151
+ if (!(route instanceof MixedRouteSDK)) {
2152
+ _context2.next = 25;
2153
+ break;
2154
+ }
2155
+
2156
+ _context2.next = 20;
2157
+ return MixedRouteTrade.fromRoute(route, amount, tradeType);
2158
+
2159
+ case 20:
2160
+ mixedRouteTrade = _context2.sent;
2161
+ _inputAmount6 = mixedRouteTrade.inputAmount, _outputAmount6 = mixedRouteTrade.outputAmount;
2162
+ mixedRoutes = [{
2163
+ mixedRoute: route,
2164
+ inputAmount: _inputAmount6,
2165
+ outputAmount: _outputAmount6
2166
+ }];
2167
+ _context2.next = 26;
2168
+ break;
2169
+
2170
+ case 25:
2171
+ throw new Error('Invalid route type');
1369
2172
 
1370
- case 13:
2173
+ case 26:
1371
2174
  return _context2.abrupt("return", new Trade({
1372
2175
  v2Routes: v2Routes,
1373
2176
  v3Routes: v3Routes,
2177
+ mixedRoutes: mixedRoutes,
1374
2178
  tradeType: tradeType
1375
2179
  }));
1376
2180
 
1377
- case 14:
2181
+ case 27:
1378
2182
  case "end":
1379
2183
  return _context2.stop();
1380
2184
  }
@@ -1382,7 +2186,7 @@ var Trade = /*#__PURE__*/function () {
1382
2186
  }, _callee2);
1383
2187
  }));
1384
2188
 
1385
- function fromRoute(_x4, _x5, _x6) {
2189
+ function fromRoute(_x5, _x6, _x7) {
1386
2190
  return _fromRoute.apply(this, arguments);
1387
2191
  }
1388
2192
 
@@ -1447,10 +2251,10 @@ var Trade = /*#__PURE__*/function () {
1447
2251
 
1448
2252
  var spotOutputAmount = sdkCore.CurrencyAmount.fromRawAmount(this.outputAmount.currency, 0);
1449
2253
 
1450
- for (var _iterator7 = _createForOfIteratorHelperLoose(this.swaps), _step7; !(_step7 = _iterator7()).done;) {
1451
- var _step7$value = _step7.value,
1452
- route = _step7$value.route,
1453
- inputAmount = _step7$value.inputAmount;
2254
+ for (var _iterator9 = _createForOfIteratorHelperLoose(this.swaps), _step9; !(_step9 = _iterator9()).done;) {
2255
+ var _step9$value = _step9.value,
2256
+ route = _step9$value.route,
2257
+ inputAmount = _step9$value.inputAmount;
1454
2258
  var midPrice = route.midPrice;
1455
2259
  spotOutputAmount = spotOutputAmount.add(midPrice.quote(inputAmount));
1456
2260
  }
@@ -1464,6 +2268,97 @@ var Trade = /*#__PURE__*/function () {
1464
2268
  return Trade;
1465
2269
  }();
1466
2270
 
2271
+ /**
2272
+ * Converts a route to a hex encoded path
2273
+ * @notice only supports exactIn route encodings
2274
+ * @param route the mixed path to convert to an encoded path
2275
+ * @returns the exactIn encoded path
2276
+ */
2277
+
2278
+ function encodeMixedRouteToPath(route) {
2279
+ var firstInputToken = route.input.wrapped;
2280
+
2281
+ var _route$pools$reduce = route.pools.reduce(function (_ref, pool, index) {
2282
+ var inputToken = _ref.inputToken,
2283
+ path = _ref.path,
2284
+ types = _ref.types;
2285
+ var outputToken = pool.token0.equals(inputToken) ? pool.token1 : pool.token0;
2286
+
2287
+ if (index === 0) {
2288
+ return {
2289
+ inputToken: outputToken,
2290
+ types: ['address', 'uint24', 'address'],
2291
+ path: [inputToken.address, pool instanceof v3Sdk.Pool ? pool.fee : V2_FEE_PATH_PLACEHOLDER, outputToken.address]
2292
+ };
2293
+ } else {
2294
+ return {
2295
+ inputToken: outputToken,
2296
+ types: [].concat(types, ['uint24', 'address']),
2297
+ path: [].concat(path, [pool instanceof v3Sdk.Pool ? pool.fee : V2_FEE_PATH_PLACEHOLDER, outputToken.address])
2298
+ };
2299
+ }
2300
+ }, {
2301
+ inputToken: firstInputToken,
2302
+ path: [],
2303
+ types: []
2304
+ }),
2305
+ path = _route$pools$reduce.path,
2306
+ types = _route$pools$reduce.types;
2307
+
2308
+ return solidity.pack(types, path);
2309
+ }
2310
+
2311
+ /**
2312
+ * Utility function to return each consecutive section of Pools or Pairs in a MixedRoute
2313
+ * @param route
2314
+ * @returns a nested array of Pools or Pairs in the order of the route
2315
+ */
2316
+
2317
+ var partitionMixedRouteByProtocol = function partitionMixedRouteByProtocol(route) {
2318
+ var acc = [];
2319
+ var left = 0;
2320
+ var right = 0;
2321
+
2322
+ while (right < route.pools.length) {
2323
+ if (route.pools[left] instanceof v3Sdk.Pool && route.pools[right] instanceof v2Sdk.Pair || route.pools[left] instanceof v2Sdk.Pair && route.pools[right] instanceof v3Sdk.Pool) {
2324
+ acc.push(route.pools.slice(left, right));
2325
+ left = right;
2326
+ } // seek forward with right pointer
2327
+
2328
+
2329
+ right++;
2330
+
2331
+ if (right === route.pools.length) {
2332
+ /// we reached the end, take the rest
2333
+ acc.push(route.pools.slice(left, right));
2334
+ }
2335
+ }
2336
+
2337
+ return acc;
2338
+ };
2339
+ /**
2340
+ * Simple utility function to get the output of an array of Pools or Pairs
2341
+ * @param pools
2342
+ * @param firstInputToken
2343
+ * @returns the output token of the last pool in the array
2344
+ */
2345
+
2346
+ var getOutputOfPools = function getOutputOfPools(pools, firstInputToken) {
2347
+ var _pools$reduce = pools.reduce(function (_ref, pool) {
2348
+ var inputToken = _ref.inputToken;
2349
+ if (!pool.involvesToken(inputToken)) throw new Error('PATH');
2350
+ var outputToken = pool.token0.equals(inputToken) ? pool.token1 : pool.token0;
2351
+ return {
2352
+ inputToken: outputToken
2353
+ };
2354
+ }, {
2355
+ inputToken: firstInputToken
2356
+ }),
2357
+ outputToken = _pools$reduce.inputToken;
2358
+
2359
+ return outputToken;
2360
+ };
2361
+
1467
2362
  var ZERO$1 = /*#__PURE__*/JSBI.BigInt(0);
1468
2363
  var REFUND_ETH_PRICE_IMPACT_THRESHOLD = /*#__PURE__*/new sdkCore.Percent( /*#__PURE__*/JSBI.BigInt(50), /*#__PURE__*/JSBI.BigInt(100));
1469
2364
  /**
@@ -1475,6 +2370,15 @@ var SwapRouter = /*#__PURE__*/function () {
1475
2370
  * Cannot be constructed.
1476
2371
  */
1477
2372
  function SwapRouter() {}
2373
+ /**
2374
+ * @notice Generates the calldata for a Swap with a V2 Route.
2375
+ * @param trade The V2Trade to encode.
2376
+ * @param options SwapOptions to use for the trade.
2377
+ * @param routerMustCustody Flag for whether funds should be sent to the router
2378
+ * @param performAggregatedSlippageCheck Flag for whether we want to perform an aggregated slippage check
2379
+ * @returns A string array of calldatas for the trade.
2380
+ */
2381
+
1478
2382
 
1479
2383
  SwapRouter.encodeV2Swap = function encodeV2Swap(trade, options, routerMustCustody, performAggregatedSlippageCheck) {
1480
2384
  var amountIn = v3Sdk.toHex(trade.maximumAmountIn(options.slippageTolerance).quotient);
@@ -1491,7 +2395,16 @@ var SwapRouter = /*#__PURE__*/function () {
1491
2395
  var exactOutputParams = [amountOut, amountIn, path, recipient];
1492
2396
  return SwapRouter.INTERFACE.encodeFunctionData('swapTokensForExactTokens', exactOutputParams);
1493
2397
  }
1494
- };
2398
+ }
2399
+ /**
2400
+ * @notice Generates the calldata for a Swap with a V3 Route.
2401
+ * @param trade The V3Trade to encode.
2402
+ * @param options SwapOptions to use for the trade.
2403
+ * @param routerMustCustody Flag for whether funds should be sent to the router
2404
+ * @param performAggregatedSlippageCheck Flag for whether we want to perform an aggregated slippage check
2405
+ * @returns A string array of calldatas for the trade.
2406
+ */
2407
+ ;
1495
2408
 
1496
2409
  SwapRouter.encodeV3Swap = function encodeV3Swap(trade, options, routerMustCustody, performAggregatedSlippageCheck) {
1497
2410
  var calldatas = [];
@@ -1554,36 +2467,145 @@ var SwapRouter = /*#__PURE__*/function () {
1554
2467
  }
1555
2468
  }
1556
2469
 
2470
+ return calldatas;
2471
+ }
2472
+ /**
2473
+ * @notice Generates the calldata for a MixedRouteSwap. Since single hop routes are not MixedRoutes, we will instead generate
2474
+ * them via the existing encodeV3Swap and encodeV2Swap methods.
2475
+ * @param trade The MixedRouteTrade to encode.
2476
+ * @param options SwapOptions to use for the trade.
2477
+ * @param routerMustCustody Flag for whether funds should be sent to the router
2478
+ * @param performAggregatedSlippageCheck Flag for whether we want to perform an aggregated slippage check
2479
+ * @returns A string array of calldatas for the trade.
2480
+ */
2481
+ ;
2482
+
2483
+ SwapRouter.encodeMixedRouteSwap = function encodeMixedRouteSwap(trade, options, routerMustCustody, performAggregatedSlippageCheck) {
2484
+ var calldatas = [];
2485
+ !(trade.tradeType === sdkCore.TradeType.EXACT_INPUT) ? invariant(false, 'TRADE_TYPE') : void 0;
2486
+
2487
+ for (var _iterator2 = _createForOfIteratorHelperLoose(trade.swaps), _step2; !(_step2 = _iterator2()).done;) {
2488
+ var _step2$value = _step2.value,
2489
+ route = _step2$value.route,
2490
+ inputAmount = _step2$value.inputAmount,
2491
+ outputAmount = _step2$value.outputAmount;
2492
+ var amountIn = v3Sdk.toHex(trade.maximumAmountIn(options.slippageTolerance, inputAmount).quotient);
2493
+ var amountOut = v3Sdk.toHex(trade.minimumAmountOut(options.slippageTolerance, outputAmount).quotient); // flag for whether the trade is single hop or not
2494
+
2495
+ var singleHop = route.pools.length === 1;
2496
+ var recipient = routerMustCustody ? ADDRESS_THIS : typeof options.recipient === 'undefined' ? MSG_SENDER : sdkCore.validateAndParseAddress(options.recipient);
2497
+
2498
+ var mixedRouteIsAllV3 = function mixedRouteIsAllV3(route) {
2499
+ return route.pools.every(function (pool) {
2500
+ return pool instanceof v3Sdk.Pool;
2501
+ });
2502
+ };
2503
+
2504
+ if (singleHop) {
2505
+ /// For single hop, since it isn't really a mixedRoute, we'll just mimic behavior of V3 or V2
2506
+ /// We don't use encodeV3Swap() or encodeV2Swap() because casting the trade to a V3Trade or V2Trade is overcomplex
2507
+ if (mixedRouteIsAllV3(route)) {
2508
+ var exactInputSingleParams = {
2509
+ tokenIn: route.path[0].address,
2510
+ tokenOut: route.path[1].address,
2511
+ fee: route.pools[0].fee,
2512
+ recipient: recipient,
2513
+ amountIn: amountIn,
2514
+ amountOutMinimum: performAggregatedSlippageCheck ? 0 : amountOut,
2515
+ sqrtPriceLimitX96: 0
2516
+ };
2517
+ calldatas.push(SwapRouter.INTERFACE.encodeFunctionData('exactInputSingle', [exactInputSingleParams]));
2518
+ } else {
2519
+ var path = route.path.map(function (token) {
2520
+ return token.address;
2521
+ });
2522
+ var exactInputParams = [amountIn, performAggregatedSlippageCheck ? 0 : amountOut, path, recipient];
2523
+ calldatas.push(SwapRouter.INTERFACE.encodeFunctionData('swapExactTokensForTokens', exactInputParams));
2524
+ }
2525
+ } else {
2526
+ (function () {
2527
+ var sections = partitionMixedRouteByProtocol(route);
2528
+
2529
+ var isLastSectionInRoute = function isLastSectionInRoute(i) {
2530
+ return i === sections.length - 1;
2531
+ };
2532
+
2533
+ var outputToken = void 0;
2534
+ var inputToken = route.input.wrapped;
2535
+
2536
+ for (var i = 0; i < sections.length; i++) {
2537
+ var section = sections[i]; /// Now, we get output of this section
2538
+
2539
+ outputToken = getOutputOfPools(section, inputToken);
2540
+ var newRouteOriginal = new MixedRouteSDK([].concat(section), section[0].token0.equals(inputToken) ? section[0].token0 : section[0].token1, outputToken);
2541
+ var newRoute = new MixedRoute(newRouteOriginal); /// Previous output is now input
2542
+
2543
+ inputToken = outputToken;
2544
+
2545
+ if (mixedRouteIsAllV3(newRoute)) {
2546
+ var _path = encodeMixedRouteToPath(newRoute);
2547
+
2548
+ var _exactInputParams = {
2549
+ path: _path,
2550
+ // By default router holds funds until the last swap, then it is sent to the recipient
2551
+ // special case exists where we are unwrapping WETH output, in which case `routerMustCustody` is set to true
2552
+ // and router still holds the funds. That logic bundled into how the value of `recipient` is calculated
2553
+ recipient: isLastSectionInRoute(i) ? recipient : ADDRESS_THIS,
2554
+ amountIn: i == 0 ? amountIn : 0,
2555
+ amountOutMinimum: !isLastSectionInRoute(i) ? 0 : amountOut
2556
+ };
2557
+ calldatas.push(SwapRouter.INTERFACE.encodeFunctionData('exactInput', [_exactInputParams]));
2558
+ } else {
2559
+ var _exactInputParams2 = [i == 0 ? amountIn : 0, !isLastSectionInRoute(i) ? 0 : amountOut, newRoute.path.map(function (token) {
2560
+ return token.address;
2561
+ }), isLastSectionInRoute(i) ? recipient : ADDRESS_THIS];
2562
+ calldatas.push(SwapRouter.INTERFACE.encodeFunctionData('swapExactTokensForTokens', _exactInputParams2));
2563
+ }
2564
+ }
2565
+ })();
2566
+ }
2567
+ }
2568
+
1557
2569
  return calldatas;
1558
2570
  };
1559
2571
 
1560
2572
  SwapRouter.encodeSwaps = function encodeSwaps(trades, options, isSwapAndAdd) {
1561
- // If dealing with an instance of the aggregated Trade object, unbundle it to individual V2Trade and V3Trade objects.
2573
+ // If dealing with an instance of the aggregated Trade object, unbundle it to individual trade objects.
1562
2574
  if (trades instanceof Trade) {
1563
2575
  !trades.swaps.every(function (swap) {
1564
- return swap.route.protocol == exports.Protocol.V3 || swap.route.protocol == exports.Protocol.V2;
2576
+ return swap.route.protocol == exports.Protocol.V3 || swap.route.protocol == exports.Protocol.V2 || swap.route.protocol == exports.Protocol.MIXED;
1565
2577
  }) ? invariant(false, 'UNSUPPORTED_PROTOCOL') : void 0;
1566
- var v2Andv3Trades = [];
2578
+ var individualTrades = [];
1567
2579
 
1568
- for (var _iterator2 = _createForOfIteratorHelperLoose(trades.swaps), _step2; !(_step2 = _iterator2()).done;) {
1569
- var _step2$value = _step2.value,
1570
- route = _step2$value.route,
1571
- inputAmount = _step2$value.inputAmount,
1572
- outputAmount = _step2$value.outputAmount;
2580
+ for (var _iterator3 = _createForOfIteratorHelperLoose(trades.swaps), _step3; !(_step3 = _iterator3()).done;) {
2581
+ var _step3$value = _step3.value,
2582
+ route = _step3$value.route,
2583
+ inputAmount = _step3$value.inputAmount,
2584
+ outputAmount = _step3$value.outputAmount;
1573
2585
 
1574
2586
  if (route.protocol == exports.Protocol.V2) {
1575
- v2Andv3Trades.push(new v2Sdk.Trade(route, trades.tradeType == sdkCore.TradeType.EXACT_INPUT ? inputAmount : outputAmount, trades.tradeType));
2587
+ individualTrades.push(new v2Sdk.Trade(route, trades.tradeType == sdkCore.TradeType.EXACT_INPUT ? inputAmount : outputAmount, trades.tradeType));
1576
2588
  } else if (route.protocol == exports.Protocol.V3) {
1577
- v2Andv3Trades.push(v3Sdk.Trade.createUncheckedTrade({
2589
+ individualTrades.push(v3Sdk.Trade.createUncheckedTrade({
2590
+ route: route,
2591
+ inputAmount: inputAmount,
2592
+ outputAmount: outputAmount,
2593
+ tradeType: trades.tradeType
2594
+ }));
2595
+ } else if (route.protocol == exports.Protocol.MIXED) {
2596
+ individualTrades.push( /// we can change the naming of this function on MixedRouteTrade if needed
2597
+ MixedRouteTrade.createUncheckedTrade({
1578
2598
  route: route,
1579
2599
  inputAmount: inputAmount,
1580
2600
  outputAmount: outputAmount,
1581
2601
  tradeType: trades.tradeType
1582
2602
  }));
2603
+ } else {
2604
+ throw new Error('UNSUPPORTED_TRADE_PROTOCOL');
1583
2605
  }
1584
2606
  }
1585
2607
 
1586
- trades = v2Andv3Trades;
2608
+ trades = individualTrades;
1587
2609
  }
1588
2610
 
1589
2611
  if (!Array.isArray(trades)) {
@@ -1591,7 +2613,7 @@ var SwapRouter = /*#__PURE__*/function () {
1591
2613
  }
1592
2614
 
1593
2615
  var numberOfTrades = trades.reduce(function (numberOfTrades, trade) {
1594
- return numberOfTrades + (trade instanceof v3Sdk.Trade ? trade.swaps.length : 1);
2616
+ return numberOfTrades + (trade instanceof v3Sdk.Trade || trade instanceof MixedRouteTrade ? trade.swaps.length : 1);
1595
2617
  }, 0);
1596
2618
  var sampleTrade = trades[0]; // All trades should have the same starting/ending currency and trade type
1597
2619
 
@@ -1624,16 +2646,23 @@ var SwapRouter = /*#__PURE__*/function () {
1624
2646
  calldatas.push(v3Sdk.SelfPermit.encodePermit(sampleTrade.inputAmount.currency, options.inputTokenPermit));
1625
2647
  }
1626
2648
 
1627
- for (var _iterator3 = _createForOfIteratorHelperLoose(trades), _step3; !(_step3 = _iterator3()).done;) {
1628
- var trade = _step3.value;
2649
+ for (var _iterator4 = _createForOfIteratorHelperLoose(trades), _step4; !(_step4 = _iterator4()).done;) {
2650
+ var trade = _step4.value;
1629
2651
 
1630
2652
  if (trade instanceof v2Sdk.Trade) {
1631
2653
  calldatas.push(SwapRouter.encodeV2Swap(trade, options, routerMustCustody, performAggregatedSlippageCheck));
1632
- } else {
1633
- for (var _iterator4 = _createForOfIteratorHelperLoose(SwapRouter.encodeV3Swap(trade, options, routerMustCustody, performAggregatedSlippageCheck)), _step4; !(_step4 = _iterator4()).done;) {
1634
- var calldata = _step4.value;
2654
+ } else if (trade instanceof v3Sdk.Trade) {
2655
+ for (var _iterator5 = _createForOfIteratorHelperLoose(SwapRouter.encodeV3Swap(trade, options, routerMustCustody, performAggregatedSlippageCheck)), _step5; !(_step5 = _iterator5()).done;) {
2656
+ var calldata = _step5.value;
1635
2657
  calldatas.push(calldata);
1636
2658
  }
2659
+ } else if (trade instanceof MixedRouteTrade) {
2660
+ for (var _iterator6 = _createForOfIteratorHelperLoose(SwapRouter.encodeMixedRouteSwap(trade, options, routerMustCustody, performAggregatedSlippageCheck)), _step6; !(_step6 = _iterator6()).done;) {
2661
+ var _calldata = _step6.value;
2662
+ calldatas.push(_calldata);
2663
+ }
2664
+ } else {
2665
+ throw new Error('Unsupported trade object');
1637
2666
  }
1638
2667
  }
1639
2668
 
@@ -1661,7 +2690,7 @@ var SwapRouter = /*#__PURE__*/function () {
1661
2690
  }
1662
2691
  /**
1663
2692
  * Produces the on-chain method name to call and the hex encoded parameters to pass as arguments for a given trade.
1664
- * @param trade to produce call parameters for
2693
+ * @param trades to produce call parameters for
1665
2694
  * @param options options for the call parameters
1666
2695
  */
1667
2696
  ;
@@ -1698,7 +2727,7 @@ var SwapRouter = /*#__PURE__*/function () {
1698
2727
  }
1699
2728
  /**
1700
2729
  * Produces the on-chain method name to call and the hex encoded parameters to pass as arguments for a given trade.
1701
- * @param trade to produce call parameters for
2730
+ * @param trades to produce call parameters for
1702
2731
  * @param options options for the call parameters
1703
2732
  */
1704
2733
  ;
@@ -1813,6 +2842,9 @@ SwapRouter.INTERFACE = /*#__PURE__*/new abi.Interface(ISwapRouter02_json.abi);
1813
2842
  exports.ADDRESS_THIS = ADDRESS_THIS;
1814
2843
  exports.ApproveAndCall = ApproveAndCall;
1815
2844
  exports.MSG_SENDER = MSG_SENDER;
2845
+ exports.MixedRoute = MixedRoute;
2846
+ exports.MixedRouteSDK = MixedRouteSDK;
2847
+ exports.MixedRouteTrade = MixedRouteTrade;
1816
2848
  exports.MulticallExtended = MulticallExtended;
1817
2849
  exports.ONE = ONE;
1818
2850
  exports.PaymentsExtended = PaymentsExtended;
@@ -1820,6 +2852,11 @@ exports.RouteV2 = RouteV2;
1820
2852
  exports.RouteV3 = RouteV3;
1821
2853
  exports.SwapRouter = SwapRouter;
1822
2854
  exports.Trade = Trade;
2855
+ exports.V2_FEE_PATH_PLACEHOLDER = V2_FEE_PATH_PLACEHOLDER;
1823
2856
  exports.ZERO = ZERO;
2857
+ exports.encodeMixedRouteToPath = encodeMixedRouteToPath;
2858
+ exports.getOutputOfPools = getOutputOfPools;
1824
2859
  exports.isMint = isMint;
2860
+ exports.partitionMixedRouteByProtocol = partitionMixedRouteByProtocol;
2861
+ exports.tradeComparator = tradeComparator;
1825
2862
  //# sourceMappingURL=router-sdk.cjs.development.js.map