Skip to content

Commit

Permalink
merge dev
Browse files Browse the repository at this point in the history
  • Loading branch information
dianakocsis committed Nov 15, 2024
2 parents 965f265 + 1337089 commit 758b1e3
Show file tree
Hide file tree
Showing 24 changed files with 106 additions and 100 deletions.
32 changes: 2 additions & 30 deletions contracts/base/Dispatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {Commands} from '../libraries/Commands.sol';
import {Lock} from './Lock.sol';
import {ERC20} from 'solmate/src/tokens/ERC20.sol';
import {IAllowanceTransfer} from 'permit2/src/interfaces/IAllowanceTransfer.sol';
import {IERC721Permit} from '@uniswap/v3-periphery/contracts/interfaces/IERC721Permit.sol';
import {ActionConstants} from '@uniswap/v4-periphery/src/libraries/ActionConstants.sol';
import {CalldataDecoder} from '@uniswap/v4-periphery/src/libraries/CalldataDecoder.sol';
import {PoolKey} from '@uniswap/v4-core/src/types/PoolKey.sol';
Expand Down Expand Up @@ -251,37 +250,10 @@ abstract contract Dispatcher is Payments, V2SwapRouter, V3SwapRouter, V4SwapRout
_executeActions(inputs);
// This contract MUST be approved to spend the token since its going to be doing the call on the position manager
} else if (command == Commands.V3_POSITION_MANAGER_PERMIT) {
bytes4 selector;
assembly {
selector := calldataload(inputs.offset)
}
if (selector != IERC721Permit.permit.selector) {
revert InvalidAction(selector);
}

_checkV3PermitCall(inputs);
(success, output) = address(V3_POSITION_MANAGER).call(inputs);
} else if (command == Commands.V3_POSITION_MANAGER_CALL) {
bytes4 selector;
assembly {
selector := calldataload(inputs.offset)
}
if (!isValidAction(selector)) {
revert InvalidAction(selector);
}

uint256 tokenId;
assembly {
// tokenId is always the first parameter in the valid actions
tokenId := calldataload(add(inputs.offset, 0x04))
}
// If any other address that is not the owner wants to call this function, it also needs to be approved (in addition to this contract)
// This can be done in 2 ways:
// 1. This contract is permitted for the specific token and the caller is approved for ALL of the owner's tokens
// 2. This contract is permitted for ALL of the owner's tokens and the caller is permitted for the specific token
if (!isAuthorizedForToken(msgSender(), tokenId)) {
revert NotAuthorizedForToken(tokenId);
}

_checkV3PositionManagerCall(inputs, msgSender());
(success, output) = address(V3_POSITION_MANAGER).call(inputs);
} else if (command == Commands.V4_INITIALIZE_POOL) {
PoolKey calldata poolKey;
Expand Down
13 changes: 0 additions & 13 deletions contracts/interfaces/external/IWETH9.sol

This file was deleted.

2 changes: 1 addition & 1 deletion contracts/modules/PaymentsImmutables.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.24;

import {IWETH9} from '../interfaces/external/IWETH9.sol';
import {IWETH9} from '@uniswap/v4-periphery/src/interfaces/external/IWETH9.sol';
import {IPermit2} from 'permit2/src/interfaces/IPermit2.sol';

struct PaymentsParameters {
Expand Down
42 changes: 40 additions & 2 deletions contracts/modules/V3ToV4Migrator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.24;
import {MigratorImmutables} from '../modules/MigratorImmutables.sol';
import {INonfungiblePositionManager} from '@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol';
import {Actions} from '@uniswap/v4-periphery/src/libraries/Actions.sol';
import {IERC721Permit} from '@uniswap/v3-periphery/contracts/interfaces/IERC721Permit.sol';
import {CalldataDecoder} from '@uniswap/v4-periphery/src/libraries/CalldataDecoder.sol';

/// @title V3 to V4 Migrator
Expand All @@ -16,19 +17,56 @@ abstract contract V3ToV4Migrator is MigratorImmutables {
error NotAuthorizedForToken(uint256 tokenId);

/// @dev validate if an action is decreaseLiquidity, collect, or burn
function isValidAction(bytes4 selector) internal pure returns (bool) {
function _isValidAction(bytes4 selector) private pure returns (bool) {
return selector == INonfungiblePositionManager.decreaseLiquidity.selector
|| selector == INonfungiblePositionManager.collect.selector
|| selector == INonfungiblePositionManager.burn.selector;
}

/// @dev the caller is authorized for the token if its the owner, spender, or operator
function isAuthorizedForToken(address caller, uint256 tokenId) internal view returns (bool) {
function _isAuthorizedForToken(address caller, uint256 tokenId) private view returns (bool) {
address owner = V3_POSITION_MANAGER.ownerOf(tokenId);
return caller == owner || V3_POSITION_MANAGER.getApproved(tokenId) == caller
|| V3_POSITION_MANAGER.isApprovedForAll(owner, caller);
}

/// @dev check that a call is to the ERC721 permit function
function _checkV3PermitCall(bytes calldata inputs) internal pure {
bytes4 selector;
assembly {
selector := calldataload(inputs.offset)
}

if (selector != IERC721Permit.permit.selector) {
revert InvalidAction(selector);
}
}

/// @dev check that the v3 position manager call is a safe call
function _checkV3PositionManagerCall(bytes calldata inputs, address caller) internal view {
bytes4 selector;
assembly {
selector := calldataload(inputs.offset)
}

if (!_isValidAction(selector)) {
revert InvalidAction(selector);
}

uint256 tokenId;
assembly {
// tokenId is always the first parameter in the valid actions
tokenId := calldataload(add(inputs.offset, 0x04))
}
// If any other address that is not the owner wants to call this function, it also needs to be approved (in addition to this contract)
// This can be done in 2 ways:
// 1. This contract is permitted for the specific token and the caller is approved for ALL of the owner's tokens
// 2. This contract is permitted for ALL of the owner's tokens and the caller is permitted for the specific token
if (!_isAuthorizedForToken(caller, tokenId)) {
revert NotAuthorizedForToken(tokenId);
}
}

/// @dev check that the v4 position manager call is a safe call
/// of the position-altering Actions, we only allow Actions.MINT
/// this is because, if a user could be tricked into approving the UniversalRouter for
Expand Down
2 changes: 1 addition & 1 deletion lib/v4-periphery
Submodule v4-periphery updated 128 files
2 changes: 1 addition & 1 deletion test/integration-tests/CheckOwnership.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Check Ownership', () => {
params: [ALICE_ADDRESS],
})
alice = await ethers.getSigner(ALICE_ADDRESS)
router = (await deployUniversalRouter()).connect(alice) as UniversalRouter
router = (await deployUniversalRouter(alice.address)).connect(alice) as UniversalRouter
usdcContract = new ethers.Contract(USDC.address, TOKEN_ABI, alice)
aliceUSDCBalance = await usdcContract.balanceOf(ALICE_ADDRESS)
planner = new RoutePlanner()
Expand Down
4 changes: 2 additions & 2 deletions test/integration-tests/UniswapMixed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ describe('Uniswap V2, V3, and V4 Tests:', () => {
usdcContract = new ethers.Contract(USDC.address, TOKEN_ABI, bob)
permit2 = PERMIT2.connect(bob) as IPermit2

v4PoolManager = (await deployV4PoolManager()).connect(bob) as PoolManager
router = (await deployUniversalRouter(v4PoolManager.address)).connect(bob) as UniversalRouter
v4PoolManager = (await deployV4PoolManager(bob.address)).connect(bob) as PoolManager
router = (await deployUniversalRouter(undefined, v4PoolManager.address)).connect(bob) as UniversalRouter

v4PositionManager = (await ethers.getContractAt('PositionManager', await router.V4_POSITION_MANAGER())).connect(
bob
Expand Down
2 changes: 1 addition & 1 deletion test/integration-tests/UniswapV2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('Uniswap V2 Tests:', () => {
wethContract = new ethers.Contract(WETH.address, TOKEN_ABI, bob)
usdcContract = new ethers.Contract(USDC.address, TOKEN_ABI, bob)
permit2 = PERMIT2.connect(bob) as IPermit2
router = (await deployUniversalRouter()) as UniversalRouter
router = (await deployUniversalRouter(bob.address)) as UniversalRouter
planner = new RoutePlanner()

// alice gives bob some tokens
Expand Down
2 changes: 1 addition & 1 deletion test/integration-tests/UniswapV3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('Uniswap V3 Tests:', () => {
wethContract = new ethers.Contract(WETH.address, TOKEN_ABI, bob)
usdcContract = new ethers.Contract(USDC.address, TOKEN_ABI, bob)
permit2 = PERMIT2.connect(bob) as IPermit2
router = (await deployUniversalRouter()) as UniversalRouter
router = (await deployUniversalRouter(bob.address)) as UniversalRouter
planner = new RoutePlanner()

// alice gives bob some tokens
Expand Down
10 changes: 2 additions & 8 deletions test/integration-tests/UniswapV4.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ describe('Uniswap V4 Tests:', () => {
wethContract = new ethers.Contract(WETH.address, TOKEN_ABI, bob)
usdcContract = new ethers.Contract(USDC.address, TOKEN_ABI, bob)
permit2 = PERMIT2.connect(bob) as IPermit2
v4PoolManager = (await deployV4PoolManager()).connect(bob) as PoolManager
router = (await deployUniversalRouter(v4PoolManager.address)).connect(bob) as UniversalRouter
v4PoolManager = (await deployV4PoolManager(bob.address)).connect(bob) as PoolManager
router = (await deployUniversalRouter(undefined, v4PoolManager.address)).connect(bob) as UniversalRouter
v4PositionManager = (await ethers.getContractAt('PositionManager', await router.V4_POSITION_MANAGER())).connect(
bob
) as PositionManager
Expand Down Expand Up @@ -134,7 +134,6 @@ describe('Uniswap V4 Tests:', () => {
zeroForOne: true,
amountIn: amountInUSDC,
amountOutMinimum: minAmountOutNative,
sqrtPriceLimitX96: 0,
hookData: '0x',
},
])
Expand Down Expand Up @@ -336,7 +335,6 @@ describe('Uniswap V4 Tests:', () => {
zeroForOne: true,
amountOut: amountOutNative,
amountInMaximum: maxAmountInUSDC,
sqrtPriceLimitX96: 0,
hookData: '0x',
},
])
Expand Down Expand Up @@ -422,7 +420,6 @@ describe('Uniswap V4 Tests:', () => {
zeroForOne: true,
amountIn: amountInNative,
amountOutMinimum: minAmountOutUSDC,
sqrtPriceLimitX96: 0,
hookData: '0x',
},
])
Expand Down Expand Up @@ -512,7 +509,6 @@ describe('Uniswap V4 Tests:', () => {
zeroForOne: true,
amountOut: amountOutUSDC,
amountInMaximum: maxAmountInNative,
sqrtPriceLimitX96: 0,
hookData: '0x',
},
])
Expand Down Expand Up @@ -613,7 +609,6 @@ describe('Uniswap V4 Tests:', () => {
zeroForOne: false,
amountIn: amountInUSDC,
amountOutMinimum: minAmountOutNative,
sqrtPriceLimitX96: 0,
hookData: '0x',
},
])
Expand Down Expand Up @@ -700,7 +695,6 @@ describe('Uniswap V4 Tests:', () => {
zeroForOne: false,
amountOut: amountOutNative,
amountInMaximum: maxAmountInUSDC,
sqrtPriceLimitX96: 0,
hookData: '0x',
},
])
Expand Down
8 changes: 5 additions & 3 deletions test/integration-tests/UniversalRouter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ 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/src/tokens/ERC20.sol/ERC20.json'
import { abi as WETH_ABI } from '../../artifacts/contracts/interfaces/external/IWETH9.sol/IWETH9.json'
import { abi as WETH_ABI } from '../../artifacts/@uniswap/v4-periphery/src/interfaces/external/IWETH9.sol/IWETH9.json'

import deployUniversalRouter from './shared/deployUniversalRouter'
import {
Expand Down Expand Up @@ -45,7 +45,7 @@ describe('UniversalRouter', () => {
wethContract = new ethers.Contract(WETH.address, WETH_ABI, alice) as IWETH9
pair_DAI_WETH = await makePair(alice, DAI, WETH)
permit2 = PERMIT2.connect(alice) as IPermit2
router = (await deployUniversalRouter()).connect(alice) as UniversalRouter
router = (await deployUniversalRouter(alice.address)).connect(alice) as UniversalRouter
})

describe('#execute', () => {
Expand Down Expand Up @@ -120,7 +120,9 @@ describe('UniversalRouter', () => {
const sweepCalldata = routerInterface.encodeFunctionData('execute(bytes,bytes[])', [commands, inputs])

const reentrantWETH = await (await ethers.getContractFactory('ReenteringWETH')).deploy()
router = (await deployUniversalRouter(undefined, reentrantWETH.address)).connect(alice) as UniversalRouter
router = (await deployUniversalRouter(alice.address, undefined, reentrantWETH.address)).connect(
alice
) as UniversalRouter
await reentrantWETH.setParameters(router.address, sweepCalldata)

planner = new RoutePlanner()
Expand Down
2 changes: 1 addition & 1 deletion test/integration-tests/V3ToV4Migration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe('V3 to V4 Migration Tests:', () => {
wethContract = new ethers.Contract(WETH.address, TOKEN_ABI, bob)
usdcContract = new ethers.Contract(USDC.address, TOKEN_ABI, bob)
v3NFTPositionManager = V3_NFT_POSITION_MANAGER.connect(bob) as INonfungiblePositionManager
router = (await deployUniversalRouter()) as UniversalRouter
router = (await deployUniversalRouter(bob.address)) as UniversalRouter
v4PositionManagerAddress = await router.V4_POSITION_MANAGER()
v4PositionManager = (await ethers.getContractAt('PositionManager', v4PositionManagerAddress)) as PositionManager

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Check Ownership Gas', () => {
params: [ALICE_ADDRESS],
})
alice = await ethers.getSigner(ALICE_ADDRESS)
router = (await deployUniversalRouter()).connect(alice) as UniversalRouter
router = (await deployUniversalRouter(alice.address)).connect(alice) as UniversalRouter
planner = new RoutePlanner()
})

Expand Down
4 changes: 2 additions & 2 deletions test/integration-tests/gas-tests/Payments.gas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import deployUniversalRouter from '../shared/deployUniversalRouter'
import { RoutePlanner, CommandType } from '../shared/planner'
import snapshotGasCost from '@uniswap/snapshot-gas-cost'
const { ethers } = hre
import WETH_ABI from '../../../artifacts/contracts/interfaces/external/IWETH9.sol/IWETH9.json'
import WETH_ABI from '../../../artifacts/@uniswap/v4-periphery/src/interfaces/external/IWETH9.sol/IWETH9.json'
import { BigNumber } from 'ethers'
import { ADDRESS_THIS } from '@uniswap/router-sdk'

Expand All @@ -32,7 +32,7 @@ describe('Payments Gas Tests', () => {
bob = (await ethers.getSigners())[1]
daiContract = new ethers.Contract(DAI.address, TOKEN_ABI, alice)
wethContract = new ethers.Contract(WETH.address, new ethers.utils.Interface(WETH_ABI.abi), alice)
router = (await deployUniversalRouter()).connect(alice) as UniversalRouter
router = (await deployUniversalRouter(alice.address)).connect(alice) as UniversalRouter
planner = new RoutePlanner()
})

Expand Down
2 changes: 1 addition & 1 deletion test/integration-tests/gas-tests/Uniswap.gas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('Uniswap Gas Tests', () => {
daiContract = new ethers.Contract(DAI.address, TOKEN_ABI, bob)
wethContract = new ethers.Contract(WETH.address, TOKEN_ABI, bob)
permit2 = PERMIT2.connect(bob) as IPermit2
router = (await deployUniversalRouter()).connect(bob) as UniversalRouter
router = (await deployUniversalRouter(bob.address)).connect(bob) as UniversalRouter
pair_DAI_WETH = await makePair(bob, DAI, WETH)
pair_DAI_USDC = await makePair(bob, DAI, USDC)
pair_USDC_WETH = await makePair(bob, USDC, WETH)
Expand Down
4 changes: 2 additions & 2 deletions test/integration-tests/gas-tests/UniversalRouter.gas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { UniversalRouter, IWETH9, ERC20 } from '../../../typechain'
import { expect } from '../shared/expect'
import { ALICE_ADDRESS } from '../shared/constants'
import { abi as TOKEN_ABI } from '../../../artifacts/solmate/src/tokens/ERC20.sol/ERC20.json'
import { abi as WETH_ABI } from '../../../artifacts/contracts/interfaces/external/IWETH9.sol/IWETH9.json'
import { abi as WETH_ABI } from '../../../artifacts/@uniswap/v4-periphery/src/interfaces/external/IWETH9.sol/IWETH9.json'
import { resetFork, WETH, DAI } from '../shared/mainnetForkHelpers'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import hre from 'hardhat'
Expand All @@ -27,7 +27,7 @@ describe('UniversalRouter Gas Tests', () => {
})
daiContract = new ethers.Contract(DAI.address, TOKEN_ABI, alice) as ERC20
wethContract = new ethers.Contract(WETH.address, WETH_ABI, alice) as IWETH9
router = (await deployUniversalRouter()).connect(alice) as UniversalRouter
router = (await deployUniversalRouter(alice.address)).connect(alice) as UniversalRouter
planner = new RoutePlanner()
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ describe('Uniswap UX Tests gas:', () => {
usdcContract = ERC20__factory.connect(USDC.address, alice)

permit2 = PERMIT2.connect(alice) as IPermit2
router = (await deployUniversalRouter()).connect(bob) as UniversalRouter
router = (await deployUniversalRouter(bob.address)).connect(bob) as UniversalRouter

planner = new RoutePlanner()

Expand Down Expand Up @@ -466,7 +466,7 @@ describe('Uniswap UX Tests gas:', () => {
}

// Launch SwapRouter03
const router2 = (await deployUniversalRouter()).connect(bob) as UniversalRouter
const router2 = (await deployUniversalRouter(bob.address)).connect(bob) as UniversalRouter
const router2ApprovalTx = (await approveSwapRouter02(bob, USDC, router2.address))!
totalGas = totalGas.add(router2ApprovalTx.gasUsed)

Expand All @@ -477,7 +477,7 @@ describe('Uniswap UX Tests gas:', () => {
}

// Launch SwapRouter04
const router3 = (await deployUniversalRouter()).connect(bob) as UniversalRouter
const router3 = (await deployUniversalRouter(bob.address)).connect(bob) as UniversalRouter
const router3ApprovalTx = (await approveSwapRouter02(bob, USDC, router3.address))!
totalGas = totalGas.add(router3ApprovalTx.gasUsed)

Expand Down Expand Up @@ -506,7 +506,7 @@ describe('Uniswap UX Tests gas:', () => {
}

// Launch Universal Router v2
const router2 = (await deployUniversalRouter()).connect(bob) as UniversalRouter
const router2 = (await deployUniversalRouter(bob.address)).connect(bob) as UniversalRouter

// Do 5 simple swaps
for (let i = 0; i < 5; i++) {
Expand All @@ -520,7 +520,7 @@ describe('Uniswap UX Tests gas:', () => {
}

// Launch Universal Router v3
const router3 = (await deployUniversalRouter()).connect(bob) as UniversalRouter
const router3 = (await deployUniversalRouter(bob.address)).connect(bob) as UniversalRouter

// Do 5 simple swaps
for (let i = 0; i < 5; i++) {
Expand Down Expand Up @@ -552,7 +552,7 @@ describe('Uniswap UX Tests gas:', () => {
}

// Launch Universal Router v2
const router2 = (await deployUniversalRouter()).connect(bob) as UniversalRouter
const router2 = (await deployUniversalRouter(bob.address)).connect(bob) as UniversalRouter
MAX_PERMIT.spender = router2.address
let calldata2 = await getPermitSignature(MAX_PERMIT, bob, permit2)
planner.addCommand(CommandType.PERMIT2_PERMIT, [MAX_PERMIT, calldata2])
Expand All @@ -565,7 +565,7 @@ describe('Uniswap UX Tests gas:', () => {
}

// Launch Universal Router v3
const router3 = (await deployUniversalRouter()).connect(bob) as UniversalRouter
const router3 = (await deployUniversalRouter(bob.address)).connect(bob) as UniversalRouter
MAX_PERMIT.spender = router3.address
let calldata3 = await getPermitSignature(MAX_PERMIT, bob, permit2)
planner.addCommand(CommandType.PERMIT2_PERMIT, [MAX_PERMIT, calldata3])
Expand Down
Loading

0 comments on commit 758b1e3

Please sign in to comment.