Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internal audit part 1 #10

Merged
merged 8 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
145951
145907
Original file line number Diff line number Diff line change
@@ -1 +1 @@
122846
122802
Original file line number Diff line number Diff line change
@@ -1 +1 @@
146913
146869
Original file line number Diff line number Diff line change
@@ -1 +1 @@
178322
178278
Original file line number Diff line number Diff line change
@@ -1 +1 @@
148707
148663
Original file line number Diff line number Diff line change
@@ -1 +1 @@
182133
182089
Original file line number Diff line number Diff line change
@@ -1 +1 @@
153050
153006
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151246
151202
Original file line number Diff line number Diff line change
@@ -1 +1 @@
172551
172507
Original file line number Diff line number Diff line change
@@ -1 +1 @@
174555
174511
Original file line number Diff line number Diff line change
@@ -1 +1 @@
181917
181873
Original file line number Diff line number Diff line change
@@ -1 +1 @@
247787
247743
Original file line number Diff line number Diff line change
@@ -1 +1 @@
183422
183378
Original file line number Diff line number Diff line change
@@ -1 +1 @@
185719
185675
Original file line number Diff line number Diff line change
@@ -1 +1 @@
250586
250542
Original file line number Diff line number Diff line change
@@ -1 +1 @@
187265
187221
Original file line number Diff line number Diff line change
@@ -1 +1 @@
100169
100147
Original file line number Diff line number Diff line change
@@ -1 +1 @@
100797
100775
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151950
151906
Original file line number Diff line number Diff line change
@@ -1 +1 @@
152828
152784
Original file line number Diff line number Diff line change
@@ -1 +1 @@
193254
193236
Original file line number Diff line number Diff line change
@@ -1 +1 @@
192710
192692
2 changes: 1 addition & 1 deletion .forge-snapshots/UniversalRouterBytecodeSize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
23514
23397
2 changes: 1 addition & 1 deletion .forge-snapshots/UniversalRouterTest#test_sweep_token.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
55464
55442
Original file line number Diff line number Diff line change
@@ -1 +1 @@
607648
607626
Original file line number Diff line number Diff line change
@@ -1 +1 @@
291686
291669
Original file line number Diff line number Diff line change
@@ -1 +1 @@
594516
594494
Original file line number Diff line number Diff line change
@@ -1 +1 @@
570271
570249
Original file line number Diff line number Diff line change
@@ -1 +1 @@
631905
631883
20 changes: 10 additions & 10 deletions src/UniversalRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@ import {StableSwapRouter} from "./modules/pancakeswap/StableSwapRouter.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";

contract UniversalRouter is RouterImmutables, IUniversalRouter, Dispatcher, Pausable {
modifier checkDeadline(uint256 deadline) {
if (block.timestamp > deadline) revert TransactionDeadlinePassed();
_;
}

constructor(RouterParameters memory params)
RouterImmutables(params)
StableSwapRouter(params.stableFactory, params.stableInfo)
V4SwapRouter(params.v4Vault, params.v4ClPoolManager, params.v4BinPoolManager)
{}

modifier checkDeadline(uint256 deadline) {
if (block.timestamp > deadline) revert TransactionDeadlinePassed();
_;
}

/// @notice To receive ETH from WETH
receive() external payable {
if (msg.sender != address(WETH9) && msg.sender != address(vault)) revert InvalidEthSender();
}

/// @inheritdoc IUniversalRouter
function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline)
external
Expand Down Expand Up @@ -76,9 +81,4 @@ contract UniversalRouter is RouterImmutables, IUniversalRouter, Dispatcher, Paus
function unpause() external onlyOwner whenPaused {
_unpause();
}

/// @notice To receive ETH from WETH
receive() external payable {
if (msg.sender != address(WETH9) && msg.sender != address(vault)) revert InvalidEthSender();
}
}
13 changes: 0 additions & 13 deletions src/base/Callbacks.sol

This file was deleted.

57 changes: 30 additions & 27 deletions src/base/Dispatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {StableSwapRouter} from "../modules/pancakeswap/StableSwapRouter.sol";
import {Payments} from "../modules/Payments.sol";
import {RouterImmutables} from "../base/RouterImmutables.sol";
import {V3ToV4Migrator} from "../modules/V3ToV4Migrator.sol";
import {Callbacks} from "../base/Callbacks.sol";
import {BytesLib} from "../libraries/BytesLib.sol";
import {Commands} from "../libraries/Commands.sol";
import {Lock} from "./Lock.sol";
Expand All @@ -27,7 +26,6 @@ abstract contract Dispatcher is
StableSwapRouter,
V4SwapRouter,
V3ToV4Migrator,
Callbacks,
Lock
{
using BytesLib for bytes;
Expand All @@ -37,6 +35,17 @@ abstract contract Dispatcher is
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
/// @param inputs An array of byte strings containing abi encoded inputs for each command
function execute(bytes calldata commands, bytes[] calldata inputs) external payable virtual;

/// @notice Public view function to be used instead of msg.sender, as the contract performs self-reentrancy and at
/// times msg.sender == address(this). Instead msgSender() returns the initiator of the lock
function msgSender() public view override(BaseActionsRouter) returns (address) {
return _getLocker();
}

/// @notice Decodes and executes the given command with the given inputs
/// @param commandType The command type to execute
/// @param inputs The inputs to execute the command with
Expand All @@ -48,10 +57,12 @@ abstract contract Dispatcher is

success = true;

if (command < Commands.FOURTH_IF_BOUNDARY) {
if (command < Commands.SECOND_IF_BOUNDARY) {
// 0x00 <= command < 0x21
if (command < Commands.EXECUTE_SUB_PLAN) {
// 0x00 <= command < 0x10
if (command < Commands.V4_SWAP) {
// 0x00 <= command < 0x08
if (command < Commands.FIRST_IF_BOUNDARY) {
if (command < Commands.V2_SWAP_EXACT_IN) {
if (command == Commands.V3_SWAP_EXACT_IN) {
// equivalent: abi.decode(inputs, (address, uint256, uint256, bytes, bool))
address recipient;
Expand Down Expand Up @@ -141,8 +152,8 @@ abstract contract Dispatcher is
// placeholder area for command 0x07
revert InvalidCommandType(command);
}
// 0x08 <= command < 0x10
} else {
// 0x08 <= command < 0x10
if (command == Commands.V2_SWAP_EXACT_IN) {
// equivalent: abi.decode(inputs, (address, uint256, uint256, bytes, bool))
address recipient;
Expand Down Expand Up @@ -226,8 +237,8 @@ abstract contract Dispatcher is
revert InvalidCommandType(command);
}
}
// 0x10 <= command < 0x18
} else {
// 0x10 <= command < 0x21
if (command == Commands.V4_SWAP) {
// pass the calldata provided to V4SwapRouter._executeActions (defined in BaseActionsRouter)
_executeActions(inputs);
Expand All @@ -244,16 +255,19 @@ abstract contract Dispatcher is
(success, output) = address(V3_POSITION_MANAGER).call(inputs);
} else if (command == Commands.V3_POSITION_MANAGER_CALL) {
bytes4 selector;
uint256 tokenId;
assembly {
selector := calldataload(inputs.offset)
// tokenId is always the first parameter in the valid actions
tokenId := calldataload(add(inputs.offset, 0x04))
}

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
Expand All @@ -265,19 +279,19 @@ abstract contract Dispatcher is
(success, output) = address(V3_POSITION_MANAGER).call(inputs);
} else if (command == Commands.V4_CL_POSITION_CALL) {
// should only call modifyLiquidities() with Actions.CL_MINT_POSITION
// do not permit or approve this contract over a v4 position or someone could use this command to decrease/burn your position
// do not permit or approve this contract over a v4 position or someone could use this command to decrease, burn, or transfer your position
(success, output) = address(V4_CL_POSITION_MANAGER).call{value: address(this).balance}(inputs);
} else if (command == Commands.V4_BIN_POSITION_CALL) {
// should only call modifyLiquidities() with Actions.BIN_ADD_LIQUIDITY
// do not permit or approve this contract over a v4 position or someone could use this command to decrease/burn your position
// do not permit or approve this contract over a v4 position or someone could use this command to decrease, burn, or transfer your position
(success, output) = address(V4_BIN_POSITION_MANAGER).call{value: address(this).balance}(inputs);
} else {
// placeholder area for command
// placeholder area for commands 0x15-0x20
revert InvalidCommandType(command);
}
}
// 0x20 <= command
} else {
// 0x21 <= command
if (command == Commands.EXECUTE_SUB_PLAN) {
bytes calldata _commands = inputs.toBytes(0);
bytes[] calldata _inputs = inputs.toBytesArray(1);
Expand Down Expand Up @@ -320,7 +334,7 @@ abstract contract Dispatcher is
uint256 amountIn = stableSwapExactOutputAmountIn(amountOut, amountInMax, path, flag);
stableSwapExactOutput(map(recipient), amountIn, amountOut, path, flag, payer);
} else {
// placeholder area for commands 0x23-0x3f
// placeholder area for commands 0x24-0x3f
revert InvalidCommandType(command);
}
}
Expand All @@ -338,15 +352,4 @@ abstract contract Dispatcher is
return recipient;
}
}

/// @notice Public view function to be used instead of msg.sender, as the contract performs self-reentrancy and at
/// times msg.sender == address(this). Instead msgSender() returns the initiator of the lock
function msgSender() public view override(BaseActionsRouter) returns (address) {
return _getLocker();
}

/// @notice Executes encoded commands along with provided inputs.
/// @param commands A set of concatenated commands, each 1 byte in length
/// @param inputs An array of byte strings containing abi encoded inputs for each command
function execute(bytes calldata commands, bytes[] calldata inputs) external payable virtual;
}
4 changes: 4 additions & 0 deletions src/base/Lock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ pragma solidity ^0.8.24;

import {Locker} from "../libraries/Locker.sol";

/// @title Lock
/// @notice A contract that provides a reentrancy lock for external calls
contract Lock {
/// @notice Thrown when attempting to reenter a locked function from an external caller
error ContractLocked();

/// @notice Modifier enforcing a reentrancy lock that allows self-reentrancy
/// @dev If the contract is not locked, use msg.sender as the locker
modifier isNotLocked() {
// Apply a reentrancy lock for all external callers
if (msg.sender != address(this)) {
Expand Down
Loading
Loading