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