> For the complete documentation index, see [llms.txt](https://docs.warpx.exchange/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.warpx.exchange/for-developers/warpx-v3/periphery/swap-router.md).

# Swap Router

#### Exact Input (Single Hop) <a href="#user-content-exact-input-single-hop" id="user-content-exact-input-single-hop"></a>

```
struct ExactInputSingleParams {    address tokenIn;    address tokenOut;    uint24 fee;    address recipient;    uint256 deadline;    uint256 amountIn;    uint256 amountOutMinimum;    uint160 sqrtPriceLimitX96;}function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut)
```

Swaps an exact amount of input tokens for as many output tokens as possible in a single pool.

**Parameters:**

| Field               | Description                           |
| ------------------- | ------------------------------------- |
| `tokenIn`           | Token to swap from                    |
| `tokenOut`          | Token to swap to                      |
| `fee`               | Pool fee tier (100, 500, 3000, 10000) |
| `recipient`         | Address to receive output tokens      |
| `deadline`          | Transaction expiry timestamp          |
| `amountIn`          | Exact amount of input tokens          |
| `amountOutMinimum`  | Minimum output (slippage protection)  |
| `sqrtPriceLimitX96` | Price limit (0 = no limit)            |

**Example:**

```
// Swap exactly 1000 USDC for WETHISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({    tokenIn: USDC,    tokenOut: WETH,    fee: 3000,    recipient: msg.sender,    deadline: block.timestamp + 300,    amountIn: 1000e6,    amountOutMinimum: 0.4e18,  // Min 0.4 WETH    sqrtPriceLimitX96: 0});uint256 amountOut = swapRouter.exactInputSingle(params);
```

***

#### Exact Input (Multi-Hop) <a href="#user-content-exact-input-multi-hop" id="user-content-exact-input-multi-hop"></a>

```
struct ExactInputParams {    bytes path;    address recipient;    uint256 deadline;    uint256 amountIn;    uint256 amountOutMinimum;}function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut)
```

Swaps an exact amount of input tokens through multiple pools for maximum output.

**Path Encoding:**

* Format: `abi.encodePacked(tokenA, feeAB, tokenB, feeBC, tokenC)`
* Example: USDC → (3000) → WETH → (3000) → DAI

**Example:**

```
// Swap USDC → WETH → DAIbytes memory path = abi.encodePacked(USDC,uint24(3000),  // 0.3% USDC/WETH poolWETH,uint24(3000),  // 0.3% WETH/DAI pool DAI);ISwapRouter.ExactInputParams memory params = ISwapRouter.ExactInputParams({    path: path,    recipient: msg.sender,    deadline: block.timestamp + 300,    amountIn: 1000e6,    amountOutMinimum: 950e18});uint256 amountOut = swapRouter.exactInput(params);
```

***

#### Exact Output (Single Hop) <a href="#user-content-exact-output-single-hop" id="user-content-exact-output-single-hop"></a>

```
struct ExactOutputSingleParams {
    address tokenIn;    
    address tokenOut;    
    uint24 fee;    
    address recipient;    
    uint256 deadline;    
    uint256 amountOut;    
    uint256 amountInMaximum;    
    uint160 sqrtPriceLimitX96;
}

function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn)
```

Swaps as few input tokens as possible for an exact amount of output tokens.

**Example:**

```
// Receive exactly 1 WETH, spending at most 2500 USDCISwapRouter.ExactOutputSingleParams memory params = ISwapRouter.ExactOutputSingleParams({    tokenIn: USDC,    tokenOut: WETH,    fee: 3000,    recipient: msg.sender,    deadline: block.timestamp + 300,    amountOut: 1e18,       // Exactly 1 WETH    amountInMaximum: 2500e6,    sqrtPriceLimitX96: 0});uint256 amountIn = swapRouter.exactOutputSingle(params);// Refund excess: if (amountIn < 2500e6) refund the difference
```

***

#### Exact Output (Multi-Hop) <a href="#user-content-exact-output-multi-hop" id="user-content-exact-output-multi-hop"></a>

```
struct ExactOutputParams {
    bytes path;
    address recipient;
    uint256 deadline;
    uint256 amountOut;
    uint256 amountInMaximum;
}
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn)
```

Swaps through multiple pools to receive an exact output amount.

**Path Encoding (Reversed):**

* Format: `abi.encodePacked(tokenC, feeBC, tokenB, feeAB, tokenA)`
* For USDC → WETH → DAI, encode as: DAI → WETH → USDC

**Example:**

```
// Get exactly 1000 DAI via USDC → WETH → DAIbytes memory path = abi.encodePacked(    DAI,           // Output token (reversed!)    uint24(3000),    WETH,    uint24(3000),    USDC           // Input token (reversed!));ISwapRouter.ExactOutputParams memory params = ISwapRouter.ExactOutputParams({    path: path,    recipient: msg.sender,    deadline: block.timestamp + 300,    amountOut: 1000e18,    amountInMaximum: 1050e6});uint256 amountIn = swapRouter.exactOutput(params);
```

***

### Token Approvals <a href="#user-content-token-approvals" id="user-content-token-approvals"></a>

Before swapping, approve the router to spend your tokens:

```
IERC20(tokenIn).approve(address(swapRouter), amountIn);
```

***

### Handling Native ETH <a href="#user-content-handling-native-eth" id="user-content-handling-native-eth"></a>

For ETH swaps, use WETH as `tokenIn` or `tokenOut` and send ETH with the transaction:

```
// Swap ETH for USDC
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({tokenIn: WETH,tokenOut: USDC,fee: 3000,recipient: msg.sender,deadline: block.timestamp + 300,amountIn: 1e18,amountOutMinimum: 2000e6,sqrtPriceLimitX96: 0});swapRouter.exactInputSingle{value: 1e18}(params);
```

***

### Price Limits <a href="#user-content-price-limits" id="user-content-price-limits"></a>

Set `sqrtPriceLimitX96` to prevent execution beyond a certain price:

* **Zero for one** (token0 → token1): Price cannot go below this value
* **One for zero** (token1 → token0): Price cannot go above this value
* **Set to 0**: No price limit

***

### Best Practices <a href="#user-content-best-practices" id="user-content-best-practices"></a>

1. **Always set slippage protection**: Use `amountOutMinimum` / `amountInMaximum`
2. **Use deadlines**: Set reasonable expiry times (e.g., 5 minutes)
3. **Multi-hop carefully**: More hops = more gas + more slippage
4. **Check routes**: Use off-chain router to find optimal paths
5. **Handle refunds**: For exact output swaps, refund unused input tokens

***

### Interface <a href="#user-content-interface" id="user-content-interface"></a>

```
interface ISwapRouter {
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); 
    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}
```
