CVE-2022-48216: Improper Locking (CWE-667)
value: Uniswap Universal Router before 1.1.0 mishandles reentrancy. This would have allowed theft of funds.
CWE description: The product does not properly acquire or release a lock on a resource, leading to unexpected resource state changes and behaviors.
CVSS v3 base score: 7.5
Published: 2023-01-04T16:15Z
Repository: https://github.com/Uniswap/universal-router
Language: Other
Files changed: contracts/UniversalRouter.sol, contracts/base/ReentrancyLock.sol, contracts/test/ReenteringProtocol.sol, test/integration-tests/UniversalRouter.test.ts, test/integration-tests/gas-tests/__snapshots__/CheckOwnership.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/CryptoPunk.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/Foundation.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/LooksRare.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/NFT20.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/NFTX.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/Payments.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/Seaport.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/Sudoswap.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/Uniswap.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/UniversalRouter.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/UniversalVSSwapRouter.gas.test.ts.snap, test/integration-tests/gas-tests/__snapshots__/X2Y2.gas.test.ts.snap, test/integration-tests/shared/deployUniversalRouter.ts
Commit date: 2022-11-28 18:42:02 -0300
Commit message: [to consider] dirty reentrancy lock (#189)

* Gas costs for clean reentrancy lock

* Gas costs for direct reentrancy lock

* Reentrancy test

* bytecode increase
Diff: diff --git a/contracts/UniversalRouter.sol b/contracts/UniversalRouter.sol
index 5ee881e..ac3c5dc 100644
--- a/contracts/UniversalRouter.sol
+++ b/contracts/UniversalRouter.sol
@@ -5,12 +5,13 @@ import {Dispatcher} from './base/Dispatcher.sol';
 import {RewardsCollector} from './base/RewardsCollector.sol';
 import {RouterParameters, RouterImmutables} from './base/RouterImmutables.sol';
 import {Constants} from './libraries/Constants.sol';
 import {Commands} from './libraries/Commands.sol';
 import {IUniversalRouter} from './interfaces/IUniversalRouter.sol';
+import {ReentrancyLock} from './base/ReentrancyLock.sol';
 
-contract UniversalRouter is RouterImmutables, IUniversalRouter, Dispatcher, RewardsCollector {
+contract UniversalRouter is RouterImmutables, IUniversalRouter, Dispatcher, RewardsCollector, ReentrancyLock {
     modifier checkDeadline(uint256 deadline) {
         if (block.timestamp > deadline) revert TransactionDeadlinePassed();
         _;
     }
 
@@ -24,11 +25,11 @@ contract UniversalRouter is RouterImmutables, IUniversalRouter, Dispatcher, Rewa
     {
         execute(commands, inputs);
     }
 
     /// @inheritdoc IUniversalRouter
-    function execute(bytes calldata commands, bytes[] calldata inputs) public payable {
+    function execute(bytes calldata commands, bytes[] calldata inputs) public payable isNotLocked {
         bool success;
         bytes memory output;
         uint256 numCommands = commands.length;
         if (inputs.length != numCommands) revert LengthMismatch();
 
diff --git a/contracts/base/ReentrancyLock.sol b/contracts/base/ReentrancyLock.sol
new file mode 100644
index 0000000..be001c1
--- /dev/null
+++ b/contracts/base/ReentrancyLock.sol
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+pragma solidity ^0.8.17;
+
+contract ReentrancyLock {
+    error ContractLocked();
+
+    uint256 private isLocked = 1;
+
+    modifier isNotLocked() {
+        if (isLocked != 1) revert ContractLocked();
+        isLocked = 2;
+        _;
+        isLocked = 1;
+    }
+}
diff --git a/contracts/test/ReenteringProtocol.sol b/contracts/test/ReenteringProtocol.sol
new file mode 100644
index 0000000..97772e7
--- /dev/null
+++ b/contracts/test/ReenteringProtocol.sol
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+pragma solidity ^0.8.15;
+
+contract ReenteringProtocol {
+    error NotAllowedReenter();
+
+    function callAndReenter(address universalRouter, bytes calldata data) public payable {
+        (bool success,) = universalRouter.call(data);
+        if (!success) revert NotAllowedReenter();
+    }
+}
diff --git a/test/integration-tests/UniversalRouter.test.ts b/test/integration-tests/UniversalRouter.test.ts
index 3a7b35c..d86618e 100644
--- a/test/integration-tests/UniversalRouter.test.ts
+++ b/test/integration-tests/UniversalRouter.test.ts
@@ -1,9 +1,10 @@
 import { UniversalRouter, Permit2, ERC20, MockLooksRareRewardsDistributor, ERC721 } from '../../typechain'
 import { BigNumber, BigNumberish } from 'ethers'
 import { Pair } from '@uniswap/v2-sdk'
 import { expect } from './shared/expect'
+import { abi as ROUTER_ABI } from '../../artifacts/contracts/UniversalRouter.sol/UniversalRouter.json'
 import { abi as TOKEN_ABI } from '../../artifacts/solmate/tokens/ERC20.sol/ERC20.json'
 import NFTX_ZAP_ABI from './shared/abis/NFTXZap.json'
 import deployUniversalRouter, { deployPermit2 } from './shared/deployUniversalRouter'
 import {
   ADDRESS_THIS,
@@ -14,10 +15,11 @@ import {
   NFTX_COVEN_VAULT_ID,
   ROUTER_REWARDS_DISTRIBUTOR,
   SOURCE_MSG_SENDER,
   MAX_UINT160,
   MAX_UINT,
+  ETH_ADDRESS,
 } from './shared/constants'
 import {
   seaportOrders,
   seaportInterface,
   getOrderParams,
@@ -32,10 +34,11 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
 import { expandTo18DecimalsBN } from './shared/helpers'
 import hre from 'hardhat'
 
 const { ethers } = hre
 const nftxZapInterface = new ethers.utils.Interface(NFTX_ZAP_ABI)
+const routerInterface = new ethers.utils.Interface(ROUTER_ABI)
 
 describe('UniversalRouter', () => {
   let alice: SignerWithAddress
   let router: UniversalRouter
   let permit2: Permit2
@@ -129,10 +132,41 @@ describe('UniversalRouter', () => {
       planner.addCommand(CommandType.SWEEP, [WETH.address, alice.address, 1])
       const { commands, inputs } = planner
       await expect(router['execute(bytes,bytes[])'](commands, inputs)).to.be.revertedWith('InvalidBips()')
     })
 
+    it('reverts if a malicious contract tries to reenter', async () => {
+      const reentrantProtocol = await (await ethers.getContractFactory('ReenteringProtocol')).deploy()
+
+      router = (
+        await deployUniversalRouter(
+          permit2,
+          mockLooksRareRewardsDistributor.address,
+          mockLooksRareToken.address,
+          reentrantProtocol.address
+        )
+      ).connect(alice) as UniversalRouter
+
+      planner.addCommand(CommandType.SWEEP, [ETH_ADDRESS, alice.address, 0])
+      let { commands, inputs } = planner
+
+      const sweepCalldata = routerInterface.encodeFunctionData('execute(bytes,bytes[])', [commands, inputs])
+      const reentrantCalldata = reentrantProtocol.interface.encodeFunctionData('callAndReenter', [
+        router.address,
+        sweepCalldata,
+      ])
+
+      planner = new RoutePlanner()
+      planner.addCommand(CommandType.NFTX, [0, reentrantCalldata])
+      ;({ commands, inputs } = planner)
+
+      const notAllowedReenterSelector = '0xb418cb98'
+      await expect(router['execute(bytes,bytes[])'](commands, inputs)).to.be.revertedWith(
+        `ExecutionFailed(0, "` + notAllowedReenterSelector + `")`
+      )
+    })
+
     describe('partial fills', async () => {
       let nftxValue: BigNumber
       let numCovens: number
       let value: BigNumber
       let invalidSeaportCalldata: string
diff --git a/test/integration-tests/gas-tests/__snapshots__/CheckOwnership.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/CheckOwnership.gas.test.ts.snap
index 1ca2903..e77dc36 100644
--- a/test/integration-tests/gas-tests/__snapshots__/CheckOwnership.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/CheckOwnership.gas.test.ts.snap
@@ -1,29 +1,29 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Check Ownership Gas gas: checks ownership after a seaport trade, one NFT 1`] = `
 Object {
   "calldataByteLength": 2212,
-  "gasUsed": 203708,
+  "gasUsed": 206020,
 }
 `;
 
 exports[`Check Ownership Gas gas: checks ownership after a seaport trade, two NFTs 1`] = `
 Object {
   "calldataByteLength": 5028,
-  "gasUsed": 339196,
+  "gasUsed": 341508,
 }
 `;
 
 exports[`Check Ownership Gas gas: does not check ownership after a seaport trade, one NFT 1`] = `
 Object {
   "calldataByteLength": 2052,
-  "gasUsed": 200173,
+  "gasUsed": 202485,
 }
 `;
 
 exports[`Check Ownership Gas gas: just ownership check 1`] = `
 Object {
   "calldataByteLength": 356,
-  "gasUsed": 30615,
+  "gasUsed": 32927,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/CryptoPunk.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/CryptoPunk.gas.test.ts.snap
index f7ed9a1..1495893 100644
--- a/test/integration-tests/gas-tests/__snapshots__/CryptoPunk.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/CryptoPunk.gas.test.ts.snap
@@ -1,8 +1,8 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Cryptopunks purchases 1 cryptopunk gas 1`] = `
 Object {
   "calldataByteLength": 356,
-  "gasUsed": 105779,
+  "gasUsed": 109868,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/Foundation.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/Foundation.gas.test.ts.snap
index 408dcf5..096b1f8 100644
--- a/test/integration-tests/gas-tests/__snapshots__/Foundation.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/Foundation.gas.test.ts.snap
@@ -1,8 +1,8 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Foundation Gas Tests Buy a mental worlds NFT from Foundation gas: token id 32 of mental worlds 1`] = `
 Object {
   "calldataByteLength": 612,
-  "gasUsed": 179658,
+  "gasUsed": 183748,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/LooksRare.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/LooksRare.gas.test.ts.snap
index e60866a..b345633 100644
--- a/test/integration-tests/gas-tests/__snapshots__/LooksRare.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/LooksRare.gas.test.ts.snap
@@ -1,15 +1,15 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`LooksRare Gas Tests ERC-721 Purchase gas: buy 1 ERC-721 on looks rare 1`] = `
 Object {
   "calldataByteLength": 1316,
-  "gasUsed": 246469,
+  "gasUsed": 248781,
 }
 `;
 
 exports[`LooksRare Gas Tests ERC-1155 Purchase gas: buy 1 ERC-1155 on looks rare 1`] = `
 Object {
   "calldataByteLength": 1348,
-  "gasUsed": 266494,
+  "gasUsed": 268806,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/NFT20.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/NFT20.gas.test.ts.snap
index b0c9e30..6bc03d2 100644
--- a/test/integration-tests/gas-tests/__snapshots__/NFT20.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/NFT20.gas.test.ts.snap
@@ -1,8 +1,8 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`NFT20 Buy 3 alphabetties from NFT20 gas: purchases token ids 129, 193, 278 of Alphabetties 1`] = `
 Object {
   "calldataByteLength": 836,
-  "gasUsed": 391360,
+  "gasUsed": 393672,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/NFTX.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/NFTX.gas.test.ts.snap
index e19852b..7fdacc5 100644
--- a/test/integration-tests/gas-tests/__snapshots__/NFTX.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/NFTX.gas.test.ts.snap
@@ -1,8 +1,8 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`NFTX Gas Tests gas: buyAndRedeem w/ specific selection 1`] = `
 Object {
   "calldataByteLength": 740,
-  "gasUsed": 490835,
+  "gasUsed": 494924,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/Payments.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/Payments.gas.test.ts.snap
index ac85725..196214e 100644
--- a/test/integration-tests/gas-tests/__snapshots__/Payments.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/Payments.gas.test.ts.snap
@@ -1,50 +1,50 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Payments Gas Tests Individual Command Tests gas: SWEEP with ERC20 1`] = `
 Object {
   "calldataByteLength": 356,
-  "gasUsed": 37194,
+  "gasUsed": 39506,
 }
 `;
 
 exports[`Payments Gas Tests Individual Command Tests gas: SWEEP_WITH_FEE 1`] = `
 Object {
   "calldataByteLength": 516,
-  "gasUsed": 66436,
+  "gasUsed": 68748,
 }
 `;
 
 exports[`Payments Gas Tests Individual Command Tests gas: TRANSFER with ERC20 1`] = `
 Object {
   "calldataByteLength": 356,
-  "gasUsed": 36168,
+  "gasUsed": 38480,
 }
 `;
 
 exports[`Payments Gas Tests Individual Command Tests gas: TRANSFER with ETH 1`] = `
 Object {
   "calldataByteLength": 356,
-  "gasUsed": 31759,
+  "gasUsed": 34071,
 }
 `;
 
 exports[`Payments Gas Tests Individual Command Tests gas: UNWRAP_WETH 1`] = `
 Object {
   "calldataByteLength": 324,
-  "gasUsed": 44647,
+  "gasUsed": 46959,
 }
 `;
 
 exports[`Payments Gas Tests Individual Command Tests gas: UNWRAP_WETH_WITH_FEE 1`] = `
 Object {
   "calldataByteLength": 644,
-  "gasUsed": 52003,
+  "gasUsed": 54315,
 }
 `;
 
 exports[`Payments Gas Tests Individual Command Tests gas: WRAP_ETH 1`] = `
 Object {
   "calldataByteLength": 324,
-  "gasUsed": 53491,
+  "gasUsed": 57580,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/Router.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/Router.gas.test.ts.snap
deleted file mode 100644
index d21ac83..0000000
--- a/test/integration-tests/gas-tests/__snapshots__/Router.gas.test.ts.snap
+++ /dev/null
@@ -1,17 +0,0 @@
-// Just Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Router Gas Tests gas: bytecode size 1`] = `17011`;
-
-exports[`Router Gas Tests trading for NFTs gas: ERC20 --> ETH --> Seaport NFT 1`] = `
-Object {
-  "calldataByteLength": 2500,
-  "gasUsed": 301927,
-}
-`;
-
-exports[`Router Gas Tests trading for NFTs gas: ETH --> Seaport NFT 1`] = `
-Object {
-  "calldataByteLength": 2052,
-  "gasUsed": 200173,
-}
-`;
diff --git a/test/integration-tests/gas-tests/__snapshots__/Seaport.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/Seaport.gas.test.ts.snap
index e35d2d6..4c4691d 100644
--- a/test/integration-tests/gas-tests/__snapshots__/Seaport.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/Seaport.gas.test.ts.snap
@@ -1,15 +1,15 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Seaport Gas Tests gas: fulfillAdvancedOrder 1`] = `
 Object {
   "calldataByteLength": 2052,
-  "gasUsed": 200173,
+  "gasUsed": 202485,
 }
 `;
 
 exports[`Seaport Gas Tests gas: fulfillAvailableAdvancedOrders 1 orders 1`] = `
 Object {
   "calldataByteLength": 4708,
-  "gasUsed": 332120,
+  "gasUsed": 334432,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/Sudoswap.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/Sudoswap.gas.test.ts.snap
index 055c892..a0f75e8 100644
--- a/test/integration-tests/gas-tests/__snapshots__/Sudoswap.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/Sudoswap.gas.test.ts.snap
@@ -1,8 +1,8 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Sudoswap Gas Tests Buy 3 sudolets from sudoswap gas: purchases token ids 80, 35, 93 of Sudolets 1`] = `
 Object {
   "calldataByteLength": 836,
-  "gasUsed": 190323,
+  "gasUsed": 192635,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/Uniswap.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/Uniswap.gas.test.ts.snap
index f574df8..299b83c 100644
--- a/test/integration-tests/gas-tests/__snapshots__/Uniswap.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/Uniswap.gas.test.ts.snap
@@ -1,81 +1,81 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Interleaving routes gas: V2, then V3 1`] = `
 Object {
   "calldataByteLength": 836,
-  "gasUsed": 197181,
+  "gasUsed": 199493,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Interleaving routes gas: V3, then V2 1`] = `
 Object {
   "calldataByteLength": 836,
-  "gasUsed": 189735,
+  "gasUsed": 192047,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Split routes gas: ERC20 --> ERC20 split V2 and V2 different routes, different input tokens, each two hop, with batch permit 1`] = `
 Object {
   "calldataByteLength": 1540,
-  "gasUsed": 306351,
+  "gasUsed": 308663,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Split routes gas: ERC20 --> ERC20 split V2 and V2 different routes, each two hop, with explicit permit 1`] = `
 Object {
   "calldataByteLength": 1220,
-  "gasUsed": 314308,
+  "gasUsed": 316620,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Split routes gas: ERC20 --> ERC20 split V2 and V2 different routes, each two hop, with explicit permit transfer from batch 1`] = `
 Object {
   "calldataByteLength": 1284,
-  "gasUsed": 316090,
+  "gasUsed": 318402,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Split routes gas: ERC20 --> ERC20 split V2 and V2 different routes, each two hop, without explicit permit 1`] = `
 Object {
   "calldataByteLength": 900,
-  "gasUsed": 310075,
+  "gasUsed": 312387,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Split routes gas: ERC20 --> ERC20 split V2 and V3, one hop 1`] = `
 Object {
   "calldataByteLength": 996,
-  "gasUsed": 180414,
+  "gasUsed": 182726,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Split routes gas: ERC20 --> ERC20 split V2 and V3, one hop, ADDRESS_THIS flag 1`] = `
 Object {
   "calldataByteLength": 996,
-  "gasUsed": 180189,
+  "gasUsed": 182501,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Split routes gas: ERC20 --> ETH split V2 and V3, exactOut, one hop 1`] = `
 Object {
   "calldataByteLength": 964,
-  "gasUsed": 197847,
+  "gasUsed": 200159,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Split routes gas: ERC20 --> ETH split V2 and V3, one hop 1`] = `
 Object {
   "calldataByteLength": 964,
-  "gasUsed": 188177,
+  "gasUsed": 190489,
 }
 `;
 
 exports[`Uniswap Gas Tests Mixing V2 and V3 with Universal Router. Split routes gas: ETH --> ERC20 split V2 and V3, one hop 1`] = `
 Object {
   "calldataByteLength": 1124,
-  "gasUsed": 214422,
+  "gasUsed": 218512,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Router02. gas: ERC20 --> ERC20 exactIn, one trade, one hop 1`] = `
 Object {
@@ -113,102 +113,102 @@ Object {
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ERC20 gas: exactIn trade, where an output fee is taken 1`] = `
 Object {
   "calldataByteLength": 836,
-  "gasUsed": 128473,
+  "gasUsed": 130785,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ERC20 gas: exactIn, one trade, one hop 1`] = `
 Object {
   "calldataByteLength": 516,
-  "gasUsed": 107645,
+  "gasUsed": 109957,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ERC20 gas: exactIn, one trade, three hops 1`] = `
 Object {
   "calldataByteLength": 580,
-  "gasUsed": 246066,
+  "gasUsed": 248378,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ERC20 gas: exactIn, one trade, three hops, no deadline 1`] = `
 Object {
   "calldataByteLength": 548,
-  "gasUsed": 245808,
+  "gasUsed": 248126,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ERC20 gas: exactIn, one trade, two hops 1`] = `
 Object {
   "calldataByteLength": 548,
-  "gasUsed": 178544,
+  "gasUsed": 180856,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ERC20 gas: exactIn, one trade, two hops, MSG_SENDER flag 1`] = `
 Object {
   "calldataByteLength": 548,
-  "gasUsed": 178544,
+  "gasUsed": 180856,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ERC20 gas: exactOut, one trade, one hop 1`] = `
 Object {
   "calldataByteLength": 516,
-  "gasUsed": 107030,
+  "gasUsed": 109342,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ERC20 gas: exactOut, one trade, three hops 1`] = `
 Object {
   "calldataByteLength": 580,
-  "gasUsed": 250553,
+  "gasUsed": 252865,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ERC20 gas: exactOut, one trade, two hops 1`] = `
 Object {
   "calldataByteLength": 548,
-  "gasUsed": 180512,
+  "gasUsed": 182824,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ETH gas: exactIn, one trade, one hop 1`] = `
 Object {
   "calldataByteLength": 644,
-  "gasUsed": 124271,
+  "gasUsed": 126583,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ETH gas: exactOut, one trade, one hop 1`] = `
 Object {
   "calldataByteLength": 804,
-  "gasUsed": 129272,
+  "gasUsed": 131584,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ERC20 --> ETH gas: exactOut, with ETH fee 1`] = `
 Object {
   "calldataByteLength": 964,
-  "gasUsed": 144977,
+  "gasUsed": 147289,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ETH --> ERC20 gas: exactIn, one trade, one hop 1`] = `
 Object {
   "calldataByteLength": 644,
-  "gasUsed": 107952,
+  "gasUsed": 110264,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV2 with Universal Router. ETH --> ERC20 gas: exactOut, one trade, one hop 1`] = `
 Object {
   "calldataByteLength": 772,
-  "gasUsed": 138445,
+  "gasUsed": 142535,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Router02. gas: ERC20 --> ERC20 exactIn, one trade, one hop 1`] = `
 Object {
@@ -253,71 +253,71 @@ Object {
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ERC20 --> ERC20 gas: exactIn, one trade, one hop 1`] = `
 Object {
   "calldataByteLength": 516,
-  "gasUsed": 116041,
+  "gasUsed": 118353,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ERC20 --> ERC20 gas: exactIn, one trade, three hops 1`] = `
 Object {
   "calldataByteLength": 548,
-  "gasUsed": 277424,
+  "gasUsed": 279736,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ERC20 --> ERC20 gas: exactIn, one trade, two hops 1`] = `
 Object {
   "calldataByteLength": 548,
-  "gasUsed": 192408,
+  "gasUsed": 194720,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ERC20 --> ERC20 gas: exactOut, one trade, one hop 1`] = `
 Object {
   "calldataByteLength": 516,
-  "gasUsed": 117315,
+  "gasUsed": 119627,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ERC20 --> ERC20 gas: exactOut, one trade, three hops 1`] = `
 Object {
   "calldataByteLength": 548,
-  "gasUsed": 421870,
+  "gasUsed": 424182,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ERC20 --> ERC20 gas: exactOut, one trade, two hops 1`] = `
 Object {
   "calldataByteLength": 548,
-  "gasUsed": 314568,
+  "gasUsed": 316880,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ERC20 --> ETH gas: exactIn swap 1`] = `
 Object {
   "calldataByteLength": 644,
-  "gasUsed": 132715,
+  "gasUsed": 135027,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ERC20 --> ETH gas: exactOut swap 1`] = `
 Object {
   "calldataByteLength": 644,
-  "gasUsed": 134061,
+  "gasUsed": 136373,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ETH --> ERC20 gas: exactIn swap 1`] = `
 Object {
   "calldataByteLength": 644,
-  "gasUsed": 245799,
+  "gasUsed": 248111,
 }
 `;
 
 exports[`Uniswap Gas Tests Trade on UniswapV3 with Universal Router. ETH --> ERC20 gas: exactOut swap 1`] = `
 Object {
   "calldataByteLength": 772,
-  "gasUsed": 140449,
+  "gasUsed": 144539,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/UniversalRouter.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/UniversalRouter.gas.test.ts.snap
index fc2c601..f66a5a2 100644
--- a/test/integration-tests/gas-tests/__snapshots__/UniversalRouter.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/UniversalRouter.gas.test.ts.snap
@@ -1,17 +1,17 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`UniversalRouter Gas Tests gas: bytecode size 1`] = `17017`;
+exports[`UniversalRouter Gas Tests gas: bytecode size 1`] = `17322`;
 
 exports[`UniversalRouter Gas Tests trading for NFTs gas: ERC20 --> ETH --> Seaport NFT 1`] = `
 Object {
   "calldataByteLength": 2500,
-  "gasUsed": 301863,
+  "gasUsed": 304175,
 }
 `;
 
 exports[`UniversalRouter Gas Tests trading for NFTs gas: ETH --> Seaport NFT 1`] = `
 Object {
   "calldataByteLength": 2052,
-  "gasUsed": 200173,
+  "gasUsed": 202485,
 }
 `;
diff --git a/test/integration-tests/gas-tests/__snapshots__/UniversalVSSwapRouter.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/UniversalVSSwapRouter.gas.test.ts.snap
index afb7e08..e51f6a0 100644
--- a/test/integration-tests/gas-tests/__snapshots__/UniversalVSSwapRouter.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/UniversalVSSwapRouter.gas.test.ts.snap
@@ -5,34 +5,34 @@ Object {
   "calldataByteLength": 68,
   "gasUsed": 60311,
 }
 `;
 
-exports[`Uniswap UX Tests gas: Comparisons Casual Swapper - 3 swaps Permit2 Max Approval Swap 1`] = `1172093`;
+exports[`Uniswap UX Tests gas: Comparisons Casual Swapper - 3 swaps Permit2 Max Approval Swap 1`] = `1179047`;
 
-exports[`Uniswap UX Tests gas: Comparisons Casual Swapper - 3 swaps Permit2 Sign Per Swap 1`] = `1209450`;
+exports[`Uniswap UX Tests gas: Comparisons Casual Swapper - 3 swaps Permit2 Sign Per Swap 1`] = `1216404`;
 
 exports[`Uniswap UX Tests gas: Comparisons Casual Swapper - 3 swaps SwapRouter02 1`] = `1172945`;
 
-exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper - 10 swaps Permit2 Max Approval Swap 1`] = `3262025`;
+exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper - 10 swaps Permit2 Max Approval Swap 1`] = `3285205`;
 
-exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper - 10 swaps Permit2 Sign Per Swap 1`] = `3428830`;
+exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper - 10 swaps Permit2 Sign Per Swap 1`] = `3452010`;
 
 exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper - 10 swaps SwapRouter02 1`] = `278117`;
 
-exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper across 3 swap router versions - 15 swaps across 3 versions Permit2 Max Approval Swap 1`] = `4355287`;
+exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper across 3 swap router versions - 15 swaps across 3 versions Permit2 Max Approval Swap 1`] = `4390057`;
 
-exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper across 3 swap router versions - 15 swaps across 3 versions Permit2 Sign Per Swap 1`] = `4576897`;
+exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper across 3 swap router versions - 15 swaps across 3 versions Permit2 Sign Per Swap 1`] = `4611667`;
 
 exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper across 3 swap router versions - 15 swaps across 3 versions SwapRouter02 1`] = `4470036`;
 
-exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Complex Swap Permit2 Max Approval Swap 1`] = `538455`;
+exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Complex Swap Permit2 Max Approval Swap 1`] = `540773`;
 
-exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Complex Swap Permit2 Sign Per Swap 1`] = `538773`;
+exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Complex Swap Permit2 Sign Per Swap 1`] = `541091`;
 
 exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Complex Swap SwapRouter02 1`] = `520492`;
 
-exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Simple Swap Permit2 Max Approval Swap 1`] = `312301`;
+exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Simple Swap Permit2 Max Approval Swap 1`] = `314619`;
 
-exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Simple Swap Permit2 Sign Per Swap 1`] = `312237`;
+exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Simple Swap Permit2 Sign Per Swap 1`] = `314555`;
 
 exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Simple Swap SwapRouter02 1`] = `278117`;
diff --git a/test/integration-tests/gas-tests/__snapshots__/X2Y2.gas.test.ts.snap b/test/integration-tests/gas-tests/__snapshots__/X2Y2.gas.test.ts.snap
index ec92cda..d847d32 100644
--- a/test/integration-tests/gas-tests/__snapshots__/X2Y2.gas.test.ts.snap
+++ b/test/integration-tests/gas-tests/__snapshots__/X2Y2.gas.test.ts.snap
@@ -1,15 +1,15 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`X2Y2 ERC-721 purchase gas: purchases 1 ERC-721 on X2Y2 1`] = `
 Object {
   "calldataByteLength": 2212,
-  "gasUsed": 212190,
+  "gasUsed": 214502,
 }
 `;
 
 exports[`X2Y2 ERC-1155 purchase gas: purchases 1 ERC-1155 on X2Y2 1`] = `
 Object {
   "calldataByteLength": 2276,
-  "gasUsed": 213385,
+  "gasUsed": 215697,
 }
 `;
diff --git a/test/integration-tests/shared/deployUniversalRouter.ts b/test/integration-tests/shared/deployUniversalRouter.ts
index 9a87037..74859eb 100644
--- a/test/integration-tests/shared/deployUniversalRouter.ts
+++ b/test/integration-tests/shared/deployUniversalRouter.ts
@@ -12,17 +12,18 @@ import {
 } from './constants'
 
 export async function deployRouter(
   permit2: Permit2,
   mockLooksRareRewardsDistributor?: string,
-  mockLooksRareToken?: string
+  mockLooksRareToken?: string,
+  mockReentrantProtocol?: string
 ): Promise<UniversalRouter> {
   const routerParameters = {
     permit2: permit2.address,
     weth9: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
     seaport: '0x00000000006c3852cbEf3e08E8dF289169EdE581',
-    nftxZap: '0x0fc584529a2AEfA997697FAfAcbA5831faC0c22d',
+    nftxZap: mockReentrantProtocol ?? '0x0fc584529a2AEfA997697FAfAcbA5831faC0c22d',
     x2y2: '0x74312363e45DCaBA76c59ec49a7Aa8A65a67EeD3',
     foundation: '0xcDA72070E455bb31C7690a170224Ce43623d0B6f',
     sudoswap: '0x2B2e8cDA09bBA9660dCA5cB6233787738Ad68329',
     nft20Zap: '0xA42f6cADa809Bcf417DeefbdD69C5C5A909249C0',
     cryptopunks: '0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB',

Vulnerable code: contract UniversalRouter is RouterImmutables, IUniversalRouter, Dispatcher, RewardsCollector {
    function execute(bytes calldata commands, bytes[] calldata inputs) public payable {
  "gasUsed": 203708,
  "gasUsed": 339196,
  "gasUsed": 200173,
  "gasUsed": 30615,
  "gasUsed": 105779,
  "gasUsed": 179658,
  "gasUsed": 246469,
  "gasUsed": 266494,
  "gasUsed": 391360,
  "gasUsed": 490835,
  "gasUsed": 37194,
  "gasUsed": 66436,
  "gasUsed": 36168,
  "gasUsed": 31759,
  "gasUsed": 44647,
  "gasUsed": 52003,
  "gasUsed": 53491,
// Just Snapshot v1, https://goo.gl/fbAQLP

exports[`Router Gas Tests gas: bytecode size 1`] = `17011`;

exports[`Router Gas Tests trading for NFTs gas: ERC20 --> ETH --> Seaport NFT 1`] = `
Object {
  "calldataByteLength": 2500,
  "gasUsed": 301927,
}
`;

exports[`Router Gas Tests trading for NFTs gas: ETH --> Seaport NFT 1`] = `
Object {
  "calldataByteLength": 2052,
  "gasUsed": 200173,
}
`;
  "gasUsed": 200173,
  "gasUsed": 332120,
  "gasUsed": 190323,
  "gasUsed": 197181,
  "gasUsed": 189735,
  "gasUsed": 306351,
  "gasUsed": 314308,
  "gasUsed": 316090,
  "gasUsed": 310075,
  "gasUsed": 180414,
  "gasUsed": 180189,
  "gasUsed": 197847,
  "gasUsed": 188177,
  "gasUsed": 214422,
  "gasUsed": 128473,
  "gasUsed": 107645,
  "gasUsed": 246066,
  "gasUsed": 245808,
  "gasUsed": 178544,
  "gasUsed": 178544,
  "gasUsed": 107030,
  "gasUsed": 250553,
  "gasUsed": 180512,
  "gasUsed": 124271,
  "gasUsed": 129272,
  "gasUsed": 144977,
  "gasUsed": 107952,
  "gasUsed": 138445,
  "gasUsed": 116041,
  "gasUsed": 277424,
  "gasUsed": 192408,
  "gasUsed": 117315,
  "gasUsed": 421870,
  "gasUsed": 314568,
  "gasUsed": 132715,
  "gasUsed": 134061,
  "gasUsed": 245799,
  "gasUsed": 140449,
exports[`UniversalRouter Gas Tests gas: bytecode size 1`] = `17017`;
  "gasUsed": 301863,
  "gasUsed": 200173,
exports[`Uniswap UX Tests gas: Comparisons Casual Swapper - 3 swaps Permit2 Max Approval Swap 1`] = `1172093`;
exports[`Uniswap UX Tests gas: Comparisons Casual Swapper - 3 swaps Permit2 Sign Per Swap 1`] = `1209450`;
exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper - 10 swaps Permit2 Max Approval Swap 1`] = `3262025`;
exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper - 10 swaps Permit2 Sign Per Swap 1`] = `3428830`;
exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper across 3 swap router versions - 15 swaps across 3 versions Permit2 Max Approval Swap 1`] = `4355287`;
exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper across 3 swap router versions - 15 swaps across 3 versions Permit2 Sign Per Swap 1`] = `4576897`;
exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Complex Swap Permit2 Max Approval Swap 1`] = `538455`;
exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Complex Swap Permit2 Sign Per Swap 1`] = `538773`;
exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Simple Swap Permit2 Max Approval Swap 1`] = `312301`;
exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Simple Swap Permit2 Sign Per Swap 1`] = `312237`;
  "gasUsed": 212190,
  "gasUsed": 213385,
  mockLooksRareToken?: string
    nftxZap: '0x0fc584529a2AEfA997697FAfAcbA5831faC0c22d',
Fixed code: import {ReentrancyLock} from './base/ReentrancyLock.sol';
contract UniversalRouter is RouterImmutables, IUniversalRouter, Dispatcher, RewardsCollector, ReentrancyLock {
    function execute(bytes calldata commands, bytes[] calldata inputs) public payable isNotLocked {
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.17;

contract ReentrancyLock {
    error ContractLocked();

    uint256 private isLocked = 1;

    modifier isNotLocked() {
        if (isLocked != 1) revert ContractLocked();
        isLocked = 2;
        _;
        isLocked = 1;
    }
}
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.15;

contract ReenteringProtocol {
    error NotAllowedReenter();

    function callAndReenter(address universalRouter, bytes calldata data) public payable {
        (bool success,) = universalRouter.call(data);
        if (!success) revert NotAllowedReenter();
    }
}
import { abi as ROUTER_ABI } from '../../artifacts/contracts/UniversalRouter.sol/UniversalRouter.json'
  ETH_ADDRESS,
const routerInterface = new ethers.utils.Interface(ROUTER_ABI)
    it('reverts if a malicious contract tries to reenter', async () => {
      const reentrantProtocol = await (await ethers.getContractFactory('ReenteringProtocol')).deploy()

      router = (
        await deployUniversalRouter(
          permit2,
          mockLooksRareRewardsDistributor.address,
          mockLooksRareToken.address,
          reentrantProtocol.address
        )
      ).connect(alice) as UniversalRouter

      planner.addCommand(CommandType.SWEEP, [ETH_ADDRESS, alice.address, 0])
      let { commands, inputs } = planner

      const sweepCalldata = routerInterface.encodeFunctionData('execute(bytes,bytes[])', [commands, inputs])
      const reentrantCalldata = reentrantProtocol.interface.encodeFunctionData('callAndReenter', [
        router.address,
        sweepCalldata,
      ])

      planner = new RoutePlanner()
      planner.addCommand(CommandType.NFTX, [0, reentrantCalldata])
      ;({ commands, inputs } = planner)

      const notAllowedReenterSelector = '0xb418cb98'
      await expect(router['execute(bytes,bytes[])'](commands, inputs)).to.be.revertedWith(
        `ExecutionFailed(0, "` + notAllowedReenterSelector + `")`
      )
    })

  "gasUsed": 206020,
  "gasUsed": 341508,
  "gasUsed": 202485,
  "gasUsed": 32927,
  "gasUsed": 109868,
  "gasUsed": 183748,
  "gasUsed": 248781,
  "gasUsed": 268806,
  "gasUsed": 393672,
  "gasUsed": 494924,
  "gasUsed": 39506,
  "gasUsed": 68748,
  "gasUsed": 38480,
  "gasUsed": 34071,
  "gasUsed": 46959,
  "gasUsed": 54315,
  "gasUsed": 57580,
  "gasUsed": 202485,
  "gasUsed": 334432,
  "gasUsed": 192635,
  "gasUsed": 199493,
  "gasUsed": 192047,
  "gasUsed": 308663,
  "gasUsed": 316620,
  "gasUsed": 318402,
  "gasUsed": 312387,
  "gasUsed": 182726,
  "gasUsed": 182501,
  "gasUsed": 200159,
  "gasUsed": 190489,
  "gasUsed": 218512,
  "gasUsed": 130785,
  "gasUsed": 109957,
  "gasUsed": 248378,
  "gasUsed": 248126,
  "gasUsed": 180856,
  "gasUsed": 180856,
  "gasUsed": 109342,
  "gasUsed": 252865,
  "gasUsed": 182824,
  "gasUsed": 126583,
  "gasUsed": 131584,
  "gasUsed": 147289,
  "gasUsed": 110264,
  "gasUsed": 142535,
  "gasUsed": 118353,
  "gasUsed": 279736,
  "gasUsed": 194720,
  "gasUsed": 119627,
  "gasUsed": 424182,
  "gasUsed": 316880,
  "gasUsed": 135027,
  "gasUsed": 136373,
  "gasUsed": 248111,
  "gasUsed": 144539,
exports[`UniversalRouter Gas Tests gas: bytecode size 1`] = `17322`;
  "gasUsed": 304175,
  "gasUsed": 202485,
exports[`Uniswap UX Tests gas: Comparisons Casual Swapper - 3 swaps Permit2 Max Approval Swap 1`] = `1179047`;
exports[`Uniswap UX Tests gas: Comparisons Casual Swapper - 3 swaps Permit2 Sign Per Swap 1`] = `1216404`;
exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper - 10 swaps Permit2 Max Approval Swap 1`] = `3285205`;
exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper - 10 swaps Permit2 Sign Per Swap 1`] = `3452010`;
exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper across 3 swap router versions - 15 swaps across 3 versions Permit2 Max Approval Swap 1`] = `4390057`;
exports[`Uniswap UX Tests gas: Comparisons Frequent Swapper across 3 swap router versions - 15 swaps across 3 versions Permit2 Sign Per Swap 1`] = `4611667`;
exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Complex Swap Permit2 Max Approval Swap 1`] = `540773`;
exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Complex Swap Permit2 Sign Per Swap 1`] = `541091`;
exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Simple Swap Permit2 Max Approval Swap 1`] = `314619`;
exports[`Uniswap UX Tests gas: Comparisons One Time Swapper - Simple Swap Permit2 Sign Per Swap 1`] = `314555`;
  "gasUsed": 214502,
  "gasUsed": 215697,
  mockLooksRareToken?: string,
  mockReentrantProtocol?: string
    nftxZap: mockReentrantProtocol ?? '0x0fc584529a2AEfA997697FAfAcbA5831faC0c22d',