Swap Router
Unified swap interface for V2 and V3 pools
Swap Router
SwapRouter02 provides a unified interface for executing swaps across both V2 and V3 pools. It handles routing, slippage protection, and multi-hop swaps.
SwapRouter02
Unified router supporting V2 constant-product and V3 concentrated liquidity swaps.
import "@luxfi/standard/src/uni/swapRouter/SwapRouter02.sol";
contract SwapRouter02 is
V2SwapRouter,
V3SwapRouter,
ApproveAndCall,
MulticallExtended,
SelfPermit
{
constructor(
address _factoryV2,
address factoryV3,
address _positionManager,
address _WETH9
);
}V2 Swap Functions
swapExactTokensForTokens
Swap exact input for minimum output.
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to
) external payable returns (uint256 amountOut);swapTokensForExactTokens
Swap maximum input for exact output.
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to
) external payable returns (uint256 amountIn);Usage
// Approve router
IERC20(WLUX).approve(address(router), amountIn);
// Swap WLUX -> LUXD (single hop)
uint256 amountOut = router.swapExactTokensForTokens(
1e18, // amountIn: 1 WLUX
950e18, // amountOutMin: 950 LUXD (5% slippage)
[WLUX, LUXD], // path
msg.sender // recipient
);
// Multi-hop: WLUX -> LETH -> LUXD
uint256 amountOut = router.swapExactTokensForTokens(
1e18,
0,
[WLUX, LETH, LUXD],
msg.sender
);V3 Swap Functions
exactInputSingle
Single-hop swap with exact input.
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params)
external payable returns (uint256 amountOut);exactInput
Multi-hop swap with exact input.
struct ExactInputParams {
bytes path; // Encoded path: token0, fee, token1, fee, token2...
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
}
function exactInput(ExactInputParams calldata params)
external payable returns (uint256 amountOut);exactOutputSingle
Single-hop swap with exact output.
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
function exactOutputSingle(ExactOutputSingleParams calldata params)
external payable returns (uint256 amountIn);exactOutput
Multi-hop swap with exact output.
struct ExactOutputParams {
bytes path; // Encoded path (reversed): tokenOut, fee, ..., tokenIn
address recipient;
uint256 amountOut;
uint256 amountInMaximum;
}
function exactOutput(ExactOutputParams calldata params)
external payable returns (uint256 amountIn);Usage
// Single-hop V3 swap
uint256 amountOut = router.exactInputSingle(
ISwapRouter.ExactInputSingleParams({
tokenIn: WLUX,
tokenOut: LUXD,
fee: 3000, // 0.3%
recipient: msg.sender,
amountIn: 1e18,
amountOutMinimum: 950e18,
sqrtPriceLimitX96: 0 // No price limit
})
);
// Multi-hop V3 swap: WLUX -> LETH -> LUXD
bytes memory path = abi.encodePacked(
WLUX,
uint24(3000), // WLUX-LETH 0.3%
LETH,
uint24(500), // LETH-LUXD 0.05%
LUXD
);
uint256 amountOut = router.exactInput(
ISwapRouter.ExactInputParams({
path: path,
recipient: msg.sender,
amountIn: 1e18,
amountOutMinimum: 0
})
);Native LUX Swaps
Swap LUX for Tokens
// Swap native LUX for tokens (wraps automatically)
router.exactInputSingle{value: 1 ether}(
ISwapRouter.ExactInputSingleParams({
tokenIn: WLUX,
tokenOut: LUXD,
fee: 3000,
recipient: msg.sender,
amountIn: 1 ether,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
})
);Swap Tokens for LUX
// Swap tokens for native LUX (unwraps automatically)
router.exactInputSingle(
ISwapRouter.ExactInputSingleParams({
tokenIn: LUXD,
tokenOut: WLUX,
fee: 3000,
recipient: address(0), // Router unwraps
amountIn: 1000e18,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
})
);
router.unwrapWETH9(0, msg.sender); // Receive native LUXMulticall
Execute multiple operations in a single transaction:
bytes[] memory calls = new bytes[](2);
// First swap
calls[0] = abi.encodeWithSelector(
router.exactInputSingle.selector,
ExactInputSingleParams({...})
);
// Second swap
calls[1] = abi.encodeWithSelector(
router.exactInputSingle.selector,
ExactInputSingleParams({...})
);
// Execute all
router.multicall(calls);Permit Support
Gasless approvals with EIP-2612:
// Combine permit + swap in single tx
bytes[] memory calls = new bytes[](2);
calls[0] = abi.encodeWithSelector(
router.selfPermit.selector,
token, amount, deadline, v, r, s
);
calls[1] = abi.encodeWithSelector(
router.exactInputSingle.selector,
params
);
router.multicall(calls);Slippage Protection
Always set appropriate amountOutMinimum or amountInMaximum:
// Calculate with 0.5% slippage tolerance
uint256 amountOutMin = expectedOut * 995 / 1000;
// Use in swap
router.exactInputSingle(
ISwapRouter.ExactInputSingleParams({
// ...
amountOutMinimum: amountOutMin,
// ...
})
);