> ## Documentation Index
> Fetch the complete documentation index at: https://docs.b3os.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Swap Tokens (Uniswap V4)

Swap ERC20 tokens on Uniswap V4 at the best available price on a single chain. Auto-routes through a direct pool or a hub token (up to 2 hops), enforces an on-chain slippage floor, uses Permit2 for approvals, and supports native ETH. Returns the transaction hash, output amount, and executed route. Ideal for: same-chain token swaps on Uniswap V4, native-ETH swaps, buying and selling ERC20s.

![Swap Tokens (Uniswap V4) logo](https://cdn.b3.fun/b3os-icons/uniswap.svg)
Catalog action EVM Onchain wallet Gas swap

Swap ERC20 tokens on Uniswap V4 at the best available price on a single chain. Auto-routes through a direct pool or a hub token (up to 2 hops), enforces an on-chain slippage floor, uses Permit2 for approvals, and supports native ETH. Returns the transaction hash, output amount, and executed route. Ideal for: same-chain token swaps on Uniswap V4, native-ETH swaps, buying and selling ERC20s.

**Review wallet and value movement**

This action can require a wallet connector, gas, token movement, or an external side effect. Test with simulation or a controlled amount before using it in a live workflow.

## At a Glance

| Field | Value |
| --- | --- |
| Action ID | `v4-swap` |
| Category | EVM Onchain |
| Connector | `wallet` |
| Requires gas | Yes |
| Funds movement | `swap` |
| Tags | `blockchain`, `evm`, `dex`, `swap`, `sell`, `buy`, `token`, `erc20`, `trade`, `uniswap`, `v4`, `defi` |

## Payload Schema

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `tokenIn` | `string` | Yes | Input token address to sell. Use 0x0000000000000000000000000000000000000000 for native ETH. |
| `tokenOut` | `string` | Yes | Output token address to receive. Use 0x0000000000000000000000000000000000000000 for native ETH. |
| `amountIn` | `string` | Yes | Exact input amount to sell, in the token's smallest unit \(wei\). |
| `chainId` | `number` | Yes | Chain to swap on. V4 swaps are single-chain only. |
| `recipient` | `string` | No | Output tokens are always delivered to the swapping wallet — V4 TAKE_ALL routes to the transaction sender and there is no recipient word on-chain. If provided, this MUST equal the swapping wallet address; a different address is rejected. Leave empty to use the swapping wallet. |
| `slippageBps` | `number` | No | Slippage tolerance in basis points \(100 = 1%\). Default is 300 \(3%\). Max 8000 \(80%\). |
| `deadlineMinutes` | `number` | No | Transaction deadline in minutes from now. Default: 20. |
| `maxHops` | `number` | No | Maximum number of pool hops the auto-router may use. Default: 2. Capped at 2 for v1. |
| `maxPriceImpactBps` | `number` | No | Aborts the swap if fill-vs-spot price impact exceeds this many basis points \(1000 = 10%\). Default is 1000 \(10%\). Higher tolerates more impact. |

## Result Schema

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `transactionHash` | `string` | Yes | The Universal Router swap transaction hash. |
| `amountIn` | `string` | Yes | Input amount that was swapped, in the token's smallest unit \(wei\). |
| `amountInFormatted` | `string \| null` | No | Full-precision, human-readable input amount \(e.g. "1.5"\). Null when tokenIn's decimals could not be resolved. |
| `amountOut` | `string` | Yes | Actual output amount received, in the token's smallest unit. Parsed from the transaction receipt's ERC20 Transfer logs for ERC20 output; falls back to the routing quote for native-ETH output or when the receipt can't be reliably decoded. The guaranteed on-chain floor is amountOutMinimum. |
| `amountOutFormatted` | `string \| null` | No | Full-precision, human-readable output amount. Null when tokenOut's decimals could not be resolved. |
| `amountOutMinimum` | `string` | Yes | Minimum output amount enforced on-chain \(TAKE_ALL minAmount\), computed from the quote and slippageBps. |
| `route` | `array` | Yes | The executed route: 1 entry for a direct swap, 2 entries for a hub-token hop. |
| `tokenIn` | `string` | Yes | Input token address that was sold. |
| `tokenOut` | `string` | Yes | Output token address that was received. |
| `chainId` | `number` | Yes | Chain the swap executed on. |
| `tokenInDecimals` | `number \| null` | No | Decimal places of tokenIn, used to format amountInFormatted. Null if on-chain lookup failed. |
| `tokenOutDecimals` | `number \| null` | No | Decimal places of tokenOut, used to format amountOutFormatted. Null if on-chain lookup failed. |
| `tokenInSymbol` | `string \| null` | No | Symbol of the input token \(e.g. 'WETH'\). Null if on-chain lookup failed. |
| `tokenOutSymbol` | `string \| null` | No | Symbol of the output token \(e.g. 'USDC'\). Null if on-chain lookup failed. |

## Examples

**Workflow node**

```json
{
  "type": "v4-swap",
  "payload": {
    "tokenIn": "ETH",
    "tokenOut": "ETH",
    "amountIn": "1000000",
    "chainId": 1
  },
  "children": [],
  "connector": {
    "type": "wallet",
    "id": "conn_wallet"
  }
}
```
  **Test with API**

```bash
curl -X POST "https://api.b3os.org/v1/actions/v4-swap/test" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "inputs": {
    "tokenIn": "ETH",
    "tokenOut": "ETH",
    "amountIn": "1000000",
    "chainId": 1
  }
}'
```

**Use expressions for dynamic values**

Payload fields can use workflow expressions such as `{{$trigger.body.amount}}`, `{{$nodes.fetch.result.price}}`, and `{{$props.asset}}` when the value should come from a trigger, prior node, or reusable workflow prop.