Skip to content
Closed
Original file line number Diff line number Diff line change
@@ -1 +1 @@
146358
146304
Original file line number Diff line number Diff line change
@@ -1 +1 @@
123415
123362
Original file line number Diff line number Diff line change
@@ -1 +1 @@
147320
147266
Original file line number Diff line number Diff line change
@@ -1 +1 @@
178729
178676
Original file line number Diff line number Diff line change
@@ -1 +1 @@
149114
149062
Original file line number Diff line number Diff line change
@@ -1 +1 @@
182570
182517
Original file line number Diff line number Diff line change
@@ -1 +1 @@
153487
153435
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151699
151645
Original file line number Diff line number Diff line change
@@ -1 +1 @@
172360
172308
Original file line number Diff line number Diff line change
@@ -1 +1 @@
174610
174558
Original file line number Diff line number Diff line change
@@ -1 +1 @@
181709
181657
Original file line number Diff line number Diff line change
@@ -1 +1 @@
247024
246971
Original file line number Diff line number Diff line change
@@ -1 +1 @@
183250
183197
Original file line number Diff line number Diff line change
@@ -1 +1 @@
186048
185996
Original file line number Diff line number Diff line change
@@ -1 +1 @@
250783
250730
Original file line number Diff line number Diff line change
@@ -1 +1 @@
187582
187529
Original file line number Diff line number Diff line change
@@ -1 +1 @@
100147
100125
Original file line number Diff line number Diff line change
@@ -1 +1 @@
117028
100754
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151799
151862
Original file line number Diff line number Diff line change
@@ -1 +1 @@
152677
152658
Original file line number Diff line number Diff line change
@@ -1 +1 @@
193217
193207
Original file line number Diff line number Diff line change
@@ -1 +1 @@
192673
192663
2 changes: 1 addition & 1 deletion .forge-snapshots/UniversalRouterBytecodeSize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
24025
24168
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 @@
55442
55428
Original file line number Diff line number Diff line change
@@ -1 +1 @@
559387
559351
Original file line number Diff line number Diff line change
@@ -1 +1 @@
291669
291590
Original file line number Diff line number Diff line change
@@ -1 +1 @@
594200
594181
Original file line number Diff line number Diff line change
@@ -1 +1 @@
570042
570007
Original file line number Diff line number Diff line change
@@ -1 +1 @@
583553
583533
39 changes: 27 additions & 12 deletions src/base/Dispatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ abstract contract Dispatcher is
bytes calldata path = inputs.toBytes(3);
address payer = payerIsUser ? msgSender() : address(this);
v3SwapExactInput(map(recipient), amountIn, amountOutMin, path, payer);
return (success, output);
} else if (command == Commands.V3_SWAP_EXACT_OUT) {
// equivalent: abi.decode(inputs, (address, uint256, uint256, bytes, bool))
address recipient;
Expand All @@ -97,6 +98,7 @@ abstract contract Dispatcher is
bytes calldata path = inputs.toBytes(3);
address payer = payerIsUser ? msgSender() : address(this);
v3SwapExactOutput(map(recipient), amountOut, amountInMax, path, payer);
return (success, output);
} else if (command == Commands.PERMIT2_TRANSFER_FROM) {
// equivalent: abi.decode(inputs, (address, address, uint160))
address token;
Expand All @@ -108,6 +110,7 @@ abstract contract Dispatcher is
amount := calldataload(add(inputs.offset, 0x40))
}
permit2TransferFrom(token, msgSender(), map(recipient), amount);
return (success, output);
} else if (command == Commands.PERMIT2_PERMIT_BATCH) {
IAllowanceTransfer.PermitBatch calldata permitBatch;
assembly {
Expand All @@ -117,6 +120,7 @@ abstract contract Dispatcher is
}
bytes calldata data = inputs.toBytes(1);
PERMIT2.permit(msgSender(), permitBatch, data);
return (success, output);
} else if (command == Commands.SWEEP) {
// equivalent: abi.decode(inputs, (address, address, uint256))
address token;
Expand All @@ -128,6 +132,7 @@ abstract contract Dispatcher is
amountMin := calldataload(add(inputs.offset, 0x40))
}
Payments.sweep(token, map(recipient), amountMin);
return (success, output);
} else if (command == Commands.TRANSFER) {
// equivalent: abi.decode(inputs, (address, address, uint256))
address token;
Expand All @@ -139,6 +144,7 @@ abstract contract Dispatcher is
value := calldataload(add(inputs.offset, 0x40))
}
Payments.pay(token, map(recipient), value);
return (success, output);
} else if (command == Commands.PAY_PORTION) {
// equivalent: abi.decode(inputs, (address, address, uint256))
address token;
Expand All @@ -150,10 +156,9 @@ abstract contract Dispatcher is
bips := calldataload(add(inputs.offset, 0x40))
}
Payments.payPortion(token, map(recipient), bips);
} else {
// placeholder area for command 0x07
revert InvalidCommandType(command);
return (success, output);
}
// placeholder area for command 0x07
} else {
// 0x08 <= command < 0x10
if (command == Commands.V2_SWAP_EXACT_IN) {
Expand All @@ -172,6 +177,7 @@ abstract contract Dispatcher is
address[] calldata path = inputs.toAddressArray(3);
address payer = payerIsUser ? msgSender() : address(this);
v2SwapExactInput(map(recipient), amountIn, amountOutMin, path, payer);
return (success, output);
} else if (command == Commands.V2_SWAP_EXACT_OUT) {
// equivalent: abi.decode(inputs, (address, uint256, uint256, bytes, bool))
address recipient;
Expand All @@ -188,6 +194,7 @@ abstract contract Dispatcher is
address[] calldata path = inputs.toAddressArray(3);
address payer = payerIsUser ? msgSender() : address(this);
v2SwapExactOutput(map(recipient), amountOut, amountInMax, path, payer);
return (success, output);
} else if (command == Commands.PERMIT2_PERMIT) {
// equivalent: abi.decode(inputs, (IAllowanceTransfer.PermitSingle, bytes))
IAllowanceTransfer.PermitSingle calldata permitSingle;
Expand All @@ -196,6 +203,7 @@ abstract contract Dispatcher is
}
bytes calldata data = inputs.toBytes(6); // PermitSingle takes first 6 slots (0..5)
PERMIT2.permit(msgSender(), permitSingle, data);
return (success, output);
} else if (command == Commands.WRAP_ETH) {
// equivalent: abi.decode(inputs, (address, uint256))
address recipient;
Expand All @@ -205,6 +213,7 @@ abstract contract Dispatcher is
amount := calldataload(add(inputs.offset, 0x20))
}
Payments.wrapETH(map(recipient), amount);
return (success, output);
} else if (command == Commands.UNWRAP_WETH) {
// equivalent: abi.decode(inputs, (address, uint256))
address recipient;
Expand All @@ -214,6 +223,7 @@ abstract contract Dispatcher is
amountMin := calldataload(add(inputs.offset, 0x20))
}
Payments.unwrapWETH9(map(recipient), amountMin);
return (success, output);
} else if (command == Commands.PERMIT2_TRANSFER_FROM_BATCH) {
IAllowanceTransfer.AllowanceTransferDetails[] calldata batchDetails;
(uint256 length, uint256 offset) = inputs.toLengthOffset(0);
Expand All @@ -222,6 +232,7 @@ abstract contract Dispatcher is
batchDetails.offset := offset
}
permit2TransferFrom(batchDetails, msgSender());
return (success, output);
} else if (command == Commands.BALANCE_CHECK_ERC20) {
// equivalent: abi.decode(inputs, (address, address, uint256))
address owner;
Expand All @@ -234,16 +245,16 @@ abstract contract Dispatcher is
}
success = (ERC20(token).balanceOf(owner) >= minBalance);
if (!success) output = abi.encodePacked(BalanceTooLow.selector);
} else {
// placeholder area for command 0x0f
revert InvalidCommandType(command);
return (success, output);
}
// placeholder area for command 0x0f
}
} else {
// 0x10 <= command < 0x21
if (command == Commands.V4_SWAP) {
// pass the calldata provided to V4SwapRouter._executeActions (defined in BaseActionsRouter)
_executeActions(inputs);
return (success, output);
// 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;
Expand All @@ -255,6 +266,7 @@ abstract contract Dispatcher is
}

(success, output) = address(V3_POSITION_MANAGER).call(inputs);
return (success, output);
} else if (command == Commands.V3_POSITION_MANAGER_CALL) {
bytes4 selector;
assembly {
Expand All @@ -279,24 +291,26 @@ abstract contract Dispatcher is
}

(success, output) = address(V3_POSITION_MANAGER).call(inputs);
return (success, output);
} 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, or transfer your position
(success, output) = address(V4_CL_POSITION_MANAGER).call{value: address(this).balance}(inputs);
return (success, output);
} 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, or transfer your position
(success, output) = address(V4_BIN_POSITION_MANAGER).call{value: address(this).balance}(inputs);
} else {
// placeholder area for commands 0x15-0x20
revert InvalidCommandType(command);
return (success, output);
}
// placeholder area for commands 0x15-0x20
}
} else {
// 0x21 <= command
if (command == Commands.EXECUTE_SUB_PLAN) {
(bytes calldata _commands, bytes[] calldata _inputs) = inputs.decodeCommandsAndInputs();
(success, output) = (address(this)).call(abi.encodeCall(Dispatcher.execute, (_commands, _inputs)));
return (success, output);
} else if (command == Commands.STABLE_SWAP_EXACT_IN) {
// equivalent: abi.decode(inputs, (address, uint256, uint256, bytes, bytes, bool))
address recipient;
Expand All @@ -314,6 +328,7 @@ abstract contract Dispatcher is
uint256[] calldata flag = inputs.toUintArray(4);
address payer = payerIsUser ? msgSender() : address(this);
stableSwapExactInput(map(recipient), amountIn, amountOutMin, path, flag, payer);
return (success, output);
} else if (command == Commands.STABLE_SWAP_EXACT_OUT) {
// equivalent: abi.decode(inputs, (address, uint256, uint256, bytes, bytes, bool))
address recipient;
Expand All @@ -334,11 +349,11 @@ abstract contract Dispatcher is
/// @dev structured this way as stack too deep by Yul
uint256 amountIn = stableSwapExactOutputAmountIn(amountOut, amountInMax, path, flag);
stableSwapExactOutput(map(recipient), amountIn, amountOut, path, flag, payer);
} else {
// placeholder area for commands 0x24-0x3f
revert InvalidCommandType(command);
return (success, output);
}
// placeholder area for commands 0x24-0x3f
}
revert InvalidCommandType(command);
}

/// @notice Calculates the recipient address for a command
Expand Down