@uniswap/universal-router-sdk 4.6.1 → 4.7.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.
@@ -3,7 +3,7 @@ import { abi } from '@uniswap/universal-router/artifacts/contracts/UniversalRout
3
3
  import { Interface } from '@ethersproject/abi';
4
4
  import { BigNumber, ethers } from 'ethers';
5
5
  import { toHex, Trade as Trade$1, encodeRouteToPath, Pool as Pool$1, NonfungiblePositionManager, Multicall, Route as Route$1 } from '@uniswap/v3-sdk';
6
- import { Pool, Trade as Trade$2, V4Planner, Route, Actions, encodeRouteToPath as encodeRouteToPath$1, V4PositionManager, V4BaseActionsParser } from '@uniswap/v4-sdk';
6
+ import { Pool, Route, Trade as Trade$2, V4Planner, Actions, encodeRouteToPath as encodeRouteToPath$1, V4PositionManager, V4BaseActionsParser } from '@uniswap/v4-sdk';
7
7
  import { TradeType, Percent, validateAndParseAddress, CHAIN_TO_ADDRESSES_MAP, CurrencyAmount, Ether, Token } from '@uniswap/sdk-core';
8
8
  import { defaultAbiCoder } from 'ethers/lib/utils';
9
9
  import { Trade, Pair, Route as Route$2 } from '@uniswap/v2-sdk';
@@ -385,17 +385,13 @@ function getPathCurrency(currency, pool) {
385
385
  } else if (pool.involvesToken(currency.wrapped)) {
386
386
  return currency.wrapped;
387
387
  // return native currency if pool involves native version of wrapped currency (only applies to V4)
388
- } else if (pool instanceof Pool) {
389
- if (pool.token0.wrapped.equals(currency)) {
390
- return pool.token0;
391
- } else if (pool.token1.wrapped.equals(currency)) {
392
- return pool.token1;
393
- }
394
- // otherwise the token is invalid
388
+ } else if (pool instanceof Pool && pool.token0.wrapped.equals(currency)) {
389
+ return pool.token0;
390
+ } else if (pool instanceof Pool && pool.token1.wrapped.equals(currency)) {
391
+ return pool.token1;
395
392
  } else {
396
393
  throw new Error("Expected currency " + currency.symbol + " to be either " + pool.token0.symbol + " or " + pool.token1.symbol);
397
394
  }
398
- return currency; // this line needed for typescript to compile
399
395
  }
400
396
 
401
397
  var RouterActionType;
@@ -404,7 +400,7 @@ var RouterActionType;
404
400
  RouterActionType["UnwrapWETH"] = "UnwrapWETH";
405
401
  })(RouterActionType || (RouterActionType = {}));
406
402
 
407
- var _routerConfigs, _routerConfigs2, _routerConfigs3, _routerConfigs4, _routerConfigs5, _routerConfigs6, _routerConfigs7, _routerConfigs8, _routerConfigs9, _routerConfigs10, _routerConfigs11, _routerConfigs12, _routerConfigs13, _routerConfigs14, _routerConfigs15, _routerConfigs16, _routerConfigs17, _routerConfigs18, _routerConfigs19, _routerConfigs20, _CHAIN_CONFIGS;
403
+ var _routerConfigs, _routerConfigs2, _routerConfigs3, _routerConfigs4, _routerConfigs5, _routerConfigs6, _routerConfigs7, _routerConfigs8, _routerConfigs9, _routerConfigs10, _routerConfigs11, _routerConfigs12, _routerConfigs13, _routerConfigs14, _routerConfigs15, _routerConfigs16, _routerConfigs17, _routerConfigs18, _routerConfigs19, _routerConfigs20, _routerConfigs21, _CHAIN_CONFIGS;
408
404
  var UniversalRouterVersion;
409
405
  (function (UniversalRouterVersion) {
410
406
  UniversalRouterVersion["V1_2"] = "1.2";
@@ -592,6 +588,15 @@ var CHAIN_CONFIGS = (_CHAIN_CONFIGS = {}, _CHAIN_CONFIGS[1] = {
592
588
  address: '0xcA7577Afb670147c7b211C798B97118bd36058F3',
593
589
  creationBlock: 1490973
594
590
  }, _routerConfigs20)
591
+ }, _CHAIN_CONFIGS[130] = {
592
+ weth: '0x4200000000000000000000000000000000000006',
593
+ routerConfigs: (_routerConfigs21 = {}, _routerConfigs21[UniversalRouterVersion.V1_2] = {
594
+ address: '0x4D73A4411CA1c660035e4AECC8270E5DdDEC8C17',
595
+ creationBlock: 23678
596
+ }, _routerConfigs21[UniversalRouterVersion.V2_0] = {
597
+ address: '0x4D73A4411CA1c660035e4AECC8270E5DdDEC8C17',
598
+ creationBlock: 23678
599
+ }, _routerConfigs21)
595
600
  }, _CHAIN_CONFIGS);
596
601
  var UNIVERSAL_ROUTER_ADDRESS = function UNIVERSAL_ROUTER_ADDRESS(version, chainId) {
597
602
  if (!(chainId in CHAIN_CONFIGS)) throw new Error("Universal Router not deployed on chain " + chainId);
@@ -612,6 +617,10 @@ var E_ETH_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
612
617
  var SENDER_AS_RECIPIENT = '0x0000000000000000000000000000000000000001';
613
618
  var ROUTER_AS_RECIPIENT = '0x0000000000000000000000000000000000000002';
614
619
 
620
+ function getCurrencyAddress(currency) {
621
+ return currency.isNative ? ETH_ADDRESS : currency.wrapped.address;
622
+ }
623
+
615
624
  function encodeFeeBips(fee) {
616
625
  return toHex(fee.multiply(10000).quotient);
617
626
  }
@@ -625,7 +634,11 @@ var UniswapTrade = /*#__PURE__*/function () {
625
634
  this.options = options;
626
635
  this.tradeType = RouterActionType.UniswapTrade;
627
636
  if (!!options.fee && !!options.flatFee) throw new Error('Only one fee option permitted');
628
- if (this.inputRequiresWrap) this.payerIsUser = false;else if (this.options.useRouterBalance) this.payerIsUser = false;else this.payerIsUser = true;
637
+ if (this.inputRequiresWrap || this.inputRequiresUnwrap || this.options.useRouterBalance) {
638
+ this.payerIsUser = false;
639
+ } else {
640
+ this.payerIsUser = true;
641
+ }
629
642
  }
630
643
  var _proto = UniswapTrade.prototype;
631
644
  _proto.encode = function encode(planner, _config) {
@@ -634,6 +647,10 @@ var UniswapTrade = /*#__PURE__*/function () {
634
647
  if (this.inputRequiresWrap) {
635
648
  // TODO: optimize if only one v2 pool we can directly send this to the pool
636
649
  planner.addCommand(CommandType.WRAP_ETH, [ROUTER_AS_RECIPIENT, this.trade.maximumAmountIn(this.options.slippageTolerance).quotient.toString()]);
650
+ } else if (this.inputRequiresUnwrap) {
651
+ // send wrapped token to router to unwrap
652
+ planner.addCommand(CommandType.PERMIT2_TRANSFER_FROM, [this.trade.inputAmount.currency.address, ROUTER_AS_RECIPIENT, this.trade.maximumAmountIn(this.options.slippageTolerance).quotient.toString()]);
653
+ planner.addCommand(CommandType.UNWRAP_WETH, [ROUTER_AS_RECIPIENT, 0]);
637
654
  }
638
655
  // The overall recipient at the end of the trade, SENDER_AS_RECIPIENT uses the msg.sender
639
656
  this.options.recipient = (_this$options$recipie = this.options.recipient) != null ? _this$options$recipie : SENDER_AS_RECIPIENT;
@@ -642,7 +659,7 @@ var UniswapTrade = /*#__PURE__*/function () {
642
659
  // as it's still more gas-expensive even in this case, but has benefits
643
660
  // in that the reversion probability is lower
644
661
  var performAggregatedSlippageCheck = this.trade.tradeType === TradeType.EXACT_INPUT && this.trade.routes.length > 2;
645
- var routerMustCustody = performAggregatedSlippageCheck || this.outputRequiresUnwrap || hasFeeOption(this.options);
662
+ var routerMustCustody = performAggregatedSlippageCheck || this.outputRequiresTransition || hasFeeOption(this.options);
646
663
  for (var _iterator = _createForOfIteratorHelperLoose(this.trade.swaps), _step; !(_step = _iterator()).done;) {
647
664
  var swap = _step.value;
648
665
  switch (swap.route.protocol) {
@@ -665,11 +682,13 @@ var UniswapTrade = /*#__PURE__*/function () {
665
682
  var minimumAmountOut = BigNumber.from(this.trade.minimumAmountOut(this.options.slippageTolerance).quotient.toString());
666
683
  // The router custodies for 3 reasons: to unwrap, to take a fee, and/or to do a slippage check
667
684
  if (routerMustCustody) {
685
+ var pools = this.trade.swaps[0].route.pools;
686
+ var pathOutputCurrencyAddress = getCurrencyAddress(getPathCurrency(this.trade.outputAmount.currency, pools[pools.length - 1]));
668
687
  // If there is a fee, that percentage is sent to the fee recipient
669
688
  // In the case where ETH is the output currency, the fee is taken in WETH (for gas reasons)
670
689
  if (!!this.options.fee) {
671
690
  var feeBips = encodeFeeBips(this.options.fee.fee);
672
- planner.addCommand(CommandType.PAY_PORTION, [this.trade.outputAmount.currency.wrapped.address, this.options.fee.recipient, feeBips]);
691
+ planner.addCommand(CommandType.PAY_PORTION, [pathOutputCurrencyAddress, this.options.fee.recipient, feeBips]);
673
692
  // If the trade is exact output, and a fee was taken, we must adjust the amount out to be the amount after the fee
674
693
  // Otherwise we continue as expected with the trade's normal expected output
675
694
  if (this.trade.tradeType === TradeType.EXACT_OUTPUT) {
@@ -681,7 +700,7 @@ var UniswapTrade = /*#__PURE__*/function () {
681
700
  if (!!this.options.flatFee) {
682
701
  var feeAmount = this.options.flatFee.amount;
683
702
  if (minimumAmountOut.lt(feeAmount)) throw new Error('Flat fee amount greater than minimumAmountOut');
684
- planner.addCommand(CommandType.TRANSFER, [this.trade.outputAmount.currency.wrapped.address, this.options.flatFee.recipient, feeAmount]);
703
+ planner.addCommand(CommandType.TRANSFER, [pathOutputCurrencyAddress, this.options.flatFee.recipient, feeAmount]);
685
704
  // If the trade is exact output, and a fee was taken, we must adjust the amount out to be the amount after the fee
686
705
  // Otherwise we continue as expected with the trade's normal expected output
687
706
  if (this.trade.tradeType === TradeType.EXACT_OUTPUT) {
@@ -692,14 +711,23 @@ var UniswapTrade = /*#__PURE__*/function () {
692
711
  // by this if-else clause.
693
712
  if (this.outputRequiresUnwrap) {
694
713
  planner.addCommand(CommandType.UNWRAP_WETH, [this.options.recipient, minimumAmountOut]);
714
+ } else if (this.outputRequiresWrap) {
715
+ planner.addCommand(CommandType.WRAP_ETH, [this.options.recipient, CONTRACT_BALANCE]);
695
716
  } else {
696
- planner.addCommand(CommandType.SWEEP, [this.trade.outputAmount.currency.wrapped.address, this.options.recipient, minimumAmountOut]);
717
+ planner.addCommand(CommandType.SWEEP, [getCurrencyAddress(this.trade.outputAmount.currency), this.options.recipient, minimumAmountOut]);
697
718
  }
698
719
  }
699
- if (this.inputRequiresWrap && (this.trade.tradeType === TradeType.EXACT_OUTPUT || riskOfPartialFill(this.trade))) {
700
- // for exactOutput swaps that take native currency as input
701
- // we need to send back the change to the user
702
- planner.addCommand(CommandType.UNWRAP_WETH, [this.options.recipient, 0]);
720
+ // for exactOutput swaps with native input or that perform an inputToken transition (wrap or unwrap)
721
+ // we need to send back the change to the user
722
+ if (this.trade.tradeType === TradeType.EXACT_OUTPUT || riskOfPartialFill(this.trade)) {
723
+ if (this.inputRequiresWrap) {
724
+ planner.addCommand(CommandType.UNWRAP_WETH, [this.options.recipient, 0]);
725
+ } else if (this.inputRequiresUnwrap) {
726
+ planner.addCommand(CommandType.WRAP_ETH, [this.options.recipient, CONTRACT_BALANCE]);
727
+ } else if (this.trade.inputAmount.currency.isNative) {
728
+ // must refund extra native currency sent along for native v4 trades (no input transition)
729
+ planner.addCommand(CommandType.SWEEP, [ETH_ADDRESS, this.options.recipient, 0]);
730
+ }
703
731
  }
704
732
  if (this.options.safeMode) planner.addCommand(CommandType.SWEEP, [ETH_ADDRESS, this.options.recipient, 0]);
705
733
  };
@@ -716,24 +744,42 @@ var UniswapTrade = /*#__PURE__*/function () {
716
744
  }, {
717
745
  key: "inputRequiresWrap",
718
746
  get: function get() {
719
- if (!this.isAllV4) {
720
- return this.trade.inputAmount.currency.isNative;
747
+ if (this.isAllV4) {
748
+ return this.trade.inputAmount.currency.isNative && !this.trade.swaps[0].route.pathInput.isNative;
721
749
  } else {
722
- // We only support wrapping all ETH or no ETH currently. We cannot support splitting where half needs to be wrapped
723
- // If the input currency is ETH and the input of the first path is not ETH it must be WETH that needs wrapping
724
- return this.trade.inputAmount.currency.isNative && !this.trade.swaps[0].route.input.isNative;
750
+ return this.trade.inputAmount.currency.isNative;
751
+ }
752
+ }
753
+ }, {
754
+ key: "inputRequiresUnwrap",
755
+ get: function get() {
756
+ if (this.isAllV4) {
757
+ return !this.trade.inputAmount.currency.isNative && this.trade.swaps[0].route.pathInput.isNative;
725
758
  }
759
+ return false;
760
+ }
761
+ }, {
762
+ key: "outputRequiresWrap",
763
+ get: function get() {
764
+ if (this.isAllV4) {
765
+ return !this.trade.outputAmount.currency.isNative && this.trade.swaps[0].route.pathOutput.isNative;
766
+ }
767
+ return false;
726
768
  }
727
769
  }, {
728
770
  key: "outputRequiresUnwrap",
729
771
  get: function get() {
730
- if (!this.isAllV4) {
731
- return this.trade.outputAmount.currency.isNative;
772
+ if (this.isAllV4) {
773
+ return this.trade.outputAmount.currency.isNative && !this.trade.swaps[0].route.pathOutput.isNative;
732
774
  } else {
733
- // If the output currency is ETH and the output of the swap is not ETH it must be WETH that needs unwrapping
734
- return this.trade.outputAmount.currency.isNative && !this.trade.swaps[0].route.output.isNative;
775
+ return this.trade.outputAmount.currency.isNative;
735
776
  }
736
777
  }
778
+ }, {
779
+ key: "outputRequiresTransition",
780
+ get: function get() {
781
+ return this.outputRequiresWrap || this.outputRequiresUnwrap;
782
+ }
737
783
  }]);
738
784
  return UniswapTrade;
739
785
  }();
@@ -777,23 +823,25 @@ function addV3Swap(planner, _ref2, tradeType, options, payerIsUser, routerMustCu
777
823
  }
778
824
  function addV4Swap(planner, _ref3, tradeType, options, payerIsUser, routerMustCustody) {
779
825
  var _options$recipient;
780
- var route = _ref3.route,
781
- inputAmount = _ref3.inputAmount,
782
- outputAmount = _ref3.outputAmount;
826
+ var inputAmount = _ref3.inputAmount,
827
+ outputAmount = _ref3.outputAmount,
828
+ route = _ref3.route;
829
+ // create a deep copy of pools since v4Planner encoding tampers with array
830
+ var pools = route.pools.map(function (p) {
831
+ return p;
832
+ });
833
+ var v4Route = new Route(pools, inputAmount.currency, outputAmount.currency);
783
834
  var trade = Trade$2.createUncheckedTrade({
784
- route: route,
835
+ route: v4Route,
785
836
  inputAmount: inputAmount,
786
837
  outputAmount: outputAmount,
787
838
  tradeType: tradeType
788
839
  });
789
840
  var slippageToleranceOnSwap = routerMustCustody && tradeType == TradeType.EXACT_INPUT ? undefined : options.slippageTolerance;
790
- var inputWethFromRouter = inputAmount.currency.isNative && !route.input.isNative;
791
- if (inputWethFromRouter && !payerIsUser) throw new Error('Inconsistent payer');
792
841
  var v4Planner = new V4Planner();
793
842
  v4Planner.addTrade(trade, slippageToleranceOnSwap);
794
- v4Planner.addSettle(inputWethFromRouter ? inputAmount.currency.wrapped : inputAmount.currency, payerIsUser);
795
- options.recipient = (_options$recipient = options.recipient) != null ? _options$recipient : SENDER_AS_RECIPIENT;
796
- v4Planner.addTake(outputAmount.currency, routerMustCustody ? ROUTER_AS_RECIPIENT : options.recipient);
843
+ v4Planner.addSettle(trade.route.pathInput, payerIsUser);
844
+ v4Planner.addTake(trade.route.pathOutput, routerMustCustody ? ROUTER_AS_RECIPIENT : (_options$recipient = options.recipient) != null ? _options$recipient : SENDER_AS_RECIPIENT);
797
845
  planner.addCommand(CommandType.V4_SWAP, [v4Planner.finalize()]);
798
846
  }
799
847
  // encode a mixed route swap, i.e. including both v2 and v3 pools