Skip to content

Commit

Permalink
v3 refactor and pull latest periphery
Browse files Browse the repository at this point in the history
  • Loading branch information
dianakocsis committed Oct 16, 2024
1 parent 1889511 commit 79e0403
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 43 deletions.
34 changes: 2 additions & 32 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';

Expand All @@ -24,8 +23,6 @@ abstract contract Dispatcher is Payments, V2SwapRouter, V3SwapRouter, V4SwapRout

error InvalidCommandType(uint256 commandType);
error BalanceTooLow();
error InvalidAction(bytes4 action);
error NotAuthorizedForToken(uint256 tokenId);

/// @notice Executes encoded commands along with provided inputs.
/// @param commands A set of concatenated commands, each 1 byte in length
Expand Down Expand Up @@ -237,37 +234,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_POSITION_CALL) {
// should only call modifyLiquidities() to mint
Expand Down
2 changes: 1 addition & 1 deletion contracts/modules/Payments.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.24;

import {Constants} from '../libraries/Constants.sol';
import {ActionConstants} from '@uniswap/v4-periphery/src/libraries/ActionConstants.sol';
import {BipsLibrary} from '@uniswap/v4-core/src/libraries/BipsLibrary.sol';
import {BipsLibrary} from '@uniswap/v4-periphery/src/libraries/BipsLibrary.sol';
import {PaymentsImmutables} from '../modules/PaymentsImmutables.sol';
import {SafeTransferLib} from 'solmate/src/utils/SafeTransferLib.sol';
import {ERC20} from 'solmate/src/tokens/ERC20.sol';
Expand Down
45 changes: 43 additions & 2 deletions contracts/modules/V3ToV4Migrator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,62 @@ pragma solidity ^0.8.24;

import {MigratorImmutables} from '../modules/MigratorImmutables.sol';
import {INonfungiblePositionManager} from '@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol';
import {IERC721Permit} from '@uniswap/v3-periphery/contracts/interfaces/IERC721Permit.sol';

/// @title V3 to V4 Migrator
/// @notice A contract that migrates liquidity from Uniswap V3 to V4
abstract contract V3ToV4Migrator is MigratorImmutables {
error InvalidAction(bytes4 action);
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);
}
}
}
2 changes: 1 addition & 1 deletion lib/v4-periphery
Submodule v4-periphery updated 41 files
+1 −1 .forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap
+1 −1 .forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap
+1 −1 .forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap
+1 −1 .forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap
+1 −1 .forge-snapshots/PositionManager_collect_native.snap
+1 −1 .forge-snapshots/PositionManager_collect_sameRange.snap
+1 −1 .forge-snapshots/PositionManager_collect_withClose.snap
+1 −1 .forge-snapshots/PositionManager_collect_withTakePair.snap
+1 −1 .forge-snapshots/PositionManager_decreaseLiquidity_native.snap
+1 −1 .forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap
+1 −1 .forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap
+1 −1 .forge-snapshots/PositionManager_decrease_burnEmpty.snap
+1 −1 .forge-snapshots/PositionManager_decrease_burnEmpty_native.snap
+1 −1 .forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap
+1 −1 .forge-snapshots/PositionManager_decrease_take_take.snap
+1 −1 .forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap
+1 −1 .forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap
+1 −1 .forge-snapshots/PositionManager_increaseLiquidity_native.snap
+1 −1 .forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap
+1 −1 .forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap
+1 −1 .forge-snapshots/PositionManager_mint_native.snap
+1 −1 .forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap
+1 −1 .forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap
+1 −1 .forge-snapshots/PositionManager_mint_onSameTickLower.snap
+1 −1 .forge-snapshots/PositionManager_mint_onSameTickUpper.snap
+1 −1 .forge-snapshots/PositionManager_mint_sameRange.snap
+1 −1 .forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap
+1 −1 .forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap
+1 −1 .forge-snapshots/PositionManager_mint_withClose.snap
+1 −1 .forge-snapshots/PositionManager_mint_withSettlePair.snap
+1 −1 .forge-snapshots/PositionManager_multicall_initialize_mint.snap
+1 −1 .forge-snapshots/PositionManager_permit_twice.snap
+1 −1 lib/v4-core
+1 −1 src/V4Router.sol
+3 −2 src/base/ImmutableState.sol
+10 −0 src/interfaces/IImmutableState.sol
+2 −1 src/interfaces/IPositionManager.sol
+2 −1 src/interfaces/IV4Router.sol
+17 −0 src/libraries/BipsLibrary.sol
+51 −0 test/libraries/BipsLibrary.t.sol
+1 −1 test/router/Payments.t.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`UniversalRouter Gas Tests gas: bytecode size 1`] = `19173`;
exports[`UniversalRouter Gas Tests gas: bytecode size 1`] = `19172`;
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@
exports[`V3 to V4 Migration Gas Tests V3 Commands burn gas: erc721permit + decreaseLiquidity + collect + burn 1`] = `
Object {
"calldataByteLength": 1092,
"gasUsed": 256278,
"gasUsed": 256271,
}
`;

exports[`V3 to V4 Migration Gas Tests V3 Commands collect gas: erc721permit + decreaseLiquidity + collect 1`] = `
Object {
"calldataByteLength": 964,
"gasUsed": 223926,
"gasUsed": 223920,
}
`;

exports[`V3 to V4 Migration Gas Tests V3 Commands decrease liquidity gas: erc721permit + decreaseLiquidity 1`] = `
Object {
"calldataByteLength": 740,
"gasUsed": 202194,
"gasUsed": 202191,
}
`;

Expand All @@ -38,21 +38,21 @@ Object {
exports[`V3 to V4 Migration Gas Tests V4 Commands increase gas: migrate and increase 1`] = `
Object {
"calldataByteLength": 2980,
"gasUsed": 452916,
"gasUsed": 452909,
}
`;

exports[`V3 to V4 Migration Gas Tests V4 Commands mint gas: migrate and mint 1`] = `
Object {
"calldataByteLength": 2500,
"gasUsed": 591168,
"gasUsed": 591159,
}
`;

exports[`V3 to V4 Migration Gas Tests V4 Commands mint gas: migrate weth position into eth position with forwarding 1`] = `
Object {
"calldataByteLength": 2788,
"gasUsed": 595307,
"gasUsed": 595300,
}
`;

Expand Down

0 comments on commit 79e0403

Please sign in to comment.