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

# Token routing

> Route deposits to different output tokens based on their source chain, token, or symbol.

Configure output token rules as part of [account registration](/deposits/headless/setup/account-registration). By default, all deposits are bridged to the single target token set at registration.

```ts theme={null}
import { keccak256, toHex } from "viem";

const DEPOSIT_SERVICE_URL =
  "https://v1.orchestrator.rhinestone.dev/deposit-processor";
const API_KEY = "YOUR_RHINESTONE_API_KEY";

const headers = {
  "Content-Type": "application/json",
  "x-api-key": API_KEY,
};

// Reuse the stable per-user salt from managed account registration.
const salt = keccak256(toHex("user-123"));
```

## Configure token routing

Token routing rules let you select the output token based on what the user deposited.

When registering an account, the `target` object accepts two optional fields:

| Field              | Type          | Description                                                                                          |
| ------------------ | ------------- | ---------------------------------------------------------------------------------------------------- |
| `outputTokenRules` | `Array<Rule>` | Routing rules evaluated by match specificity                                                         |
| `rejectUnmapped`   | `boolean`     | If `true`, deposits that don't match any rule are rejected instead of falling back to `target.token` |

Each rule has:

| Field          | Type               | Description                                                      |
| -------------- | ------------------ | ---------------------------------------------------------------- |
| `match.chain`  | `string` (CAIP-2)  | Match deposits from this source chain (e.g. `"eip155:1"`)        |
| `match.token`  | `string` (address) | Match deposits of this source token address                      |
| `match.symbol` | `string`           | Match deposits by token symbol (case-insensitive, e.g. `"USDC"`) |
| `outputToken`  | `string` (address) | The final token to deliver on the target chain                   |

A rule's `match` must specify at least one of `chain`, `token`, or `symbol`. You can combine them for more specific matches.

### Rule priority

When multiple rules match a deposit, the most specific rule wins. Declaration order only matters when two rules share the same specificity.

| Match type         | Example                                                              |
| ------------------ | -------------------------------------------------------------------- |
| `chain` + `token`  | Specific token from a specific chain                                 |
| `chain` + `symbol` | Any token with symbol X from chain Y                                 |
| `token` (only)     | Specific token from any chain                                        |
| `symbol` (only)    | Any token with symbol X from any chain                               |
| `chain` (only)     | Any token from a specific chain                                      |
| No match           | Falls back to `target.token` (or rejected if `rejectUnmapped: true`) |

### Example: USDC and ETH passthrough

Route USDC deposits to USDC.e and ETH deposits to WETH on Optimism, while defaulting other tokens to a fallback:

```ts theme={null}
await fetch(`${DEPOSIT_SERVICE_URL}/register-managed`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    account: {
      salt,
      target: {
        chain: "eip155:10", // Optimism
        token: "0xYOUR_DEFAULT_FALLBACK_TOKEN",
        recipient: "0xYOUR_RECIPIENT_ADDRESS",
        outputTokenRules: [
          {
            match: { symbol: "USDC" },
            outputToken: "0x7f5c764cbc14f9669b88837ca1490cca17c31607", // USDC.e on Optimism
          },
          {
            match: { symbol: "ETH" },
            outputToken: "0x4200000000000000000000000000000000000006", // WETH on Optimism
          },
        ],
      },
    },
  }),
});
```

With this configuration:

* User deposits USDC (from any chain) → receives USDC.e on Optimism
* User deposits ETH (from any chain) → receives WETH on Optimism
* User deposits any other token → receives `target.token` (default fallback)

### Example: chain-specific overrides

Combine `chain` and `symbol` for chain-specific routing. The chain-specific rule takes priority because `chain + symbol` outranks `symbol` alone.

```ts theme={null}
outputTokenRules: [
  {
    match: { chain: "eip155:1", symbol: "USDC" },
    outputToken: "0xUSCD_BRIDGED_ADDRESS",
  },
  {
    match: { symbol: "USDC" },
    outputToken: "0xUSDC_NATIVE_ADDRESS",
  },
];
```

### Example: reject unknown tokens

Only accept specific tokens and reject everything else:

```ts theme={null}
await fetch(`${DEPOSIT_SERVICE_URL}/register-managed`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    account: {
      salt,
      target: {
        chain: "eip155:10",
        token: "0xNOT_USED_AS_FALLBACK",
        recipient: "0xYOUR_RECIPIENT_ADDRESS",
        outputTokenRules: [
          { match: { symbol: "USDC" }, outputToken: "0xUSDC_ADDRESS" },
          { match: { symbol: "ETH" }, outputToken: "0xWETH_ADDRESS" },
        ],
        rejectUnmapped: true,
      },
    },
  }),
});
```

Deposits that don't match USDC or ETH are ignored (not bridged).
