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

# Multi-Token Trades

> Trade several tokens at once - one order, one atomic settlement.

TetraFi handles three trade shapes, each settling atomically in a single order:

| Shape       | Example                    | Intent structure          |
| ----------- | -------------------------- | ------------------------- |
| One-to-one  | WETH → USDC                | 1 input, 1 output         |
| Many-to-one | (WETH + WBTC) → USDT       | multiple inputs, 1 output |
| One-to-many | WETH → (USDC + DAI + USDT) | 1 input, multiple outputs |

Many-to-one and one-to-many shapes shine when you're rebalancing a portfolio, consolidating stablecoin balances, or fanning one asset out into several - without running a separate swap (and paying separate overhead) for each leg.

## What Changes vs a Single-Token Trade

The API surface barely moves. The differences:

**Request:** list several entries in `intent.inputs[]` or `intent.outputs[]` instead of one each.

**Response:** the order payload widens to cover every leg. When one LP fills everything, you get a single-counterparty order; when several LPs each take a slice, the payload becomes a split fill with one entry per counterparty.

**Signing:** unchanged - preflight hands you the complete typed envelope for whatever shape came back, and you sign it verbatim. One signature covers every leg.

## 1. Quote a Multi-Token Intent

List each leg as its own entry. Amounts pair with their own entry, so decimals stay unambiguous.

### Many-to-one: sell USDC + DAI → buy USDT

```python theme={null} theme={null}
import httpx

API = "https://api.tetrafi.io/api/v1"
ME = "0x2e7E7cc62919eAf4c502dAC34753cFc5A29e9693"
headers = {"X-API-Key": "tfk_live_..."}

# Many-to-one: sell USDC + DAI -> buy USDT
resp = httpx.post(
    f"{API}/rfq/quotes",
    json={
        "user": ME,
        "intent": {
            "intentType": "swap",
            "inputs": [
                {"user": ME,
                 "asset": {"chainId": 1, "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},  # USDC
                 "amount": "100000000"},                    # 100 USDC (6 decimals)
                {"user": ME,
                 "asset": {"chainId": 1, "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F"},  # DAI
                 "amount": "100000000000000000000"},        # 100 DAI (18 decimals)
            ],
            "outputs": [
                {"receiver": ME,
                 "asset": {"chainId": 1, "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7"}},  # USDT
            ],
            "swapType": "ExactInput",
        },
        "supportedTypes": ["escrow-v0"],
    },
    headers=headers,
)
quotes = resp.json()["quotes"]
print(f"{len(quotes)} quotes for the 2-in-1-out intent")
```

### One-to-many: sell WETH → buy USDC + DAI + USDT

Flip the shape: a single input, several outputs. Use `ExactOutput` when you want to pin how much of each output token arrives:

```python theme={null} theme={null}
resp = httpx.post(
    f"{API}/rfq/quotes",
    json={
        "user": ME,
        "intent": {
            "intentType": "swap",
            "inputs": [
                {"user": ME,
                 "asset": {"chainId": 1, "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"}},  # WETH
            ],
            "outputs": [
                {"receiver": ME,
                 "asset": {"chainId": 1, "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},  # USDC
                 "amount": "600000000"},   # 600 USDC
                {"receiver": ME,
                 "asset": {"chainId": 1, "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F"},  # DAI
                 "amount": "600000000000000000000"},   # 600 DAI
                {"receiver": ME,
                 "asset": {"chainId": 1, "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7"},  # USDT
                 "amount": "600000000"},   # 600 USDT
            ],
            "swapType": "ExactOutput",
        },
        "supportedTypes": ["escrow-v0"],
    },
    headers=headers,
)
quotes = resp.json()["quotes"]
```

## 2. Read the Multi-Leg Response

The response looks like any other quote list, with `preview` widened to every leg:

When a single LP covers the whole intent, the preview pairs your inputs against its combined delivery:

```json theme={null} theme={null}
{
  "quoteId": "q_01J3F...",
  "solverId": "lp-atlas",
  "order": { "type": "escrow-v0", "payload": { "...": "one envelope covering both inputs" } },
  "preview": {
    "inputs": [
      { "asset": "eip155:1/erc20:0xA0b8...eB48", "amount": "100000000",             "symbol": "USDC" },
      { "asset": "eip155:1/erc20:0x6B17...1d0F", "amount": "100000000000000000000", "symbol": "DAI" }
    ],
    "outputs": [
      { "asset": "eip155:1/erc20:0xdAC1...1ec7", "amount": "198898842", "symbol": "USDT" }
    ]
  },
  "validUntil": 1784560100
}
```

When several LPs split the fill, the quote is a split-fill order - each counterparty commits to its slice, but you still see one combined preview and sign once:

```json theme={null} theme={null}
{
  "quoteId": "q_01J3G...",
  "solverId": "split:lp-atlas+lp-borealis",
  "order": { "type": "escrow-v0", "payload": { "...": "split fill - one slice per LP, one taker signature" } },
  "preview": {
    "inputs": [
      { "asset": "eip155:1/erc20:0xA0b8...eB48", "amount": "100000000",             "symbol": "USDC" },
      { "asset": "eip155:1/erc20:0x6B17...1d0F", "amount": "100000000000000000000", "symbol": "DAI" }
    ],
    "outputs": [
      { "asset": "eip155:1/erc20:0xdAC1...1ec7", "amount": "198898842", "symbol": "USDT" }
    ]
  },
  "validUntil": 1784560100
}
```

The structural takeaway: single-LP orders carry one counterparty commitment; split fills carry one per LP - but from your side the contract is identical: the escrow enforces the combined minimum delivery, atomically, or refunds every leg.

## 3. Preflight, Sign, Settle

Shape makes no difference to your code. Preflight the quote you picked, sign the typed data it returns, submit - the same three calls as a one-to-one trade:

```python theme={null} theme={null}
from eth_account import Account
from eth_account.messages import encode_typed_data

PRIVATE_KEY = "0x<your_private_key_hex>"
account = Account.from_key(PRIVATE_KEY)

# --- 1. Pick from the multi-token quotes ---
selected = quotes[0]

# --- 2. Preflight ---
pf = httpx.post(f"{API}/rfq/orders/preflight", headers=headers,
                json={"quoteResponse": selected}).json()

# --- 3. Sign the (multi-leg) escrow-v0 payload and submit ---
sign_action = next(a for a in pf["nextActions"] if a["purpose"] == "orderSignature")
signable = encode_typed_data(full_message=sign_action["typedData"])
signature = Account.sign_message(signable, private_key=PRIVATE_KEY).signature.hex()

order = httpx.post(f"{API}/rfq/orders",
                   headers={**headers, "Idempotency-Key": selected["quoteId"]},
                   json={"quoteResponse": selected, "signature": signature}).json()
print(f"Multi-token order submitted: {order['id']}")
```

<Info>
  The order payload's shape - single counterparty or split fill - is chosen by the platform from how LPs answered your intent. You never select it: sign whatever preflight returns. The [Order Submission guide](/rfq-api/guides/gasless-execution) breaks down what the envelope always binds.
</Info>
