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

# Multi-Token Trades

> Swap multiple tokens in a single atomic transaction.

Bebop supports three trade structures. Each structure settles atomically in one transaction:

<Note>
  Multi-token RFQ trades are available on EVM chains. Solana RFQ supports one-to-one trades only.
</Note>

| Mode        | Example                      | `type` in response |
| ----------- | ---------------------------- | ------------------ |
| One-to-one  | WETH → USDC                  | `121`              |
| Many-to-one | (WETH + WBTC) → USDC         | `M21`              |
| One-to-many | WETH → (USDT + USDC + PYUSD) | `12M`              |

Use multi-token trades to rebalance a portfolio, consolidate stablecoins, or distribute one asset into multiple tokens.

## How It Differs from Single-Token Trades

The API interface is nearly identical. The differences are:

**Request:** Pass comma-separated token addresses and amounts instead of single values.

**Response:** The `onchainOrderType` is `MultiOrder` or `AggregateOrder` instead of `SingleOrder`. The API returns `MultiOrder` when a single maker fills the trade, or `AggregateOrder` when multiple makers are involved.

## 1. Request a Multi-Token Quote

Separate multiple token addresses and amounts with commas. The order of amounts must match the order of token addresses.

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

```python theme={null}
import httpx

NETWORK = "ethereum"

# Many-to-one: sell USDC + DAI -> buy USDT
resp = httpx.get(
    f"https://api.bebop.xyz/pmm/{NETWORK}/v3/quote",
    params={
        "sell_tokens": ",".join(
            [
                "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",  # USDC
                "0x6B175474E89094C44Da98b954EedeAC495271d0F",  # DAI
            ]
        ),
        "buy_tokens": "0xdAC17F958D2ee523a2206206994597C13D831ec7",  # USDT
        "sell_amounts": ",".join(
            [
                "100000000",  # 100 USDC (6 decimals)
                "100000000000000000000",  # 100 DAI (18 decimals)
            ]
        ),
        "taker_address": "0x2e7E7cc62919eAf4c502dAC34753cFc5A29e9693",
    },
)
resp.raise_for_status()
quote = resp.json()
print(
    f'Quote type: {quote.get("type")}, order type: {quote.get("onchainOrderType")}'
)
print(quote)
```

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

For one-to-many, specify a single `sell_tokens` / `sell_amounts` and comma-separated `buy_tokens`. Use `buy_amounts` instead of `sell_amounts` to control how much of each output token you want:

```python theme={null}
resp = httpx.get(
    f"https://api.bebop.xyz/pmm/{NETWORK}/v3/quote",
    params={
        "sell_tokens": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",  # WETH
        "buy_tokens": ",".join([
            "0xdAC17F958D2ee523a2206206994597C13D831ec7",  # USDT
            "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",  # USDC
            "0x6c3ea9036406852006290770BEdFcAbA0e23A0e8",  # PYUSD
        ]),
        "buy_amounts": ",".join([
            "500000000",  # 500 USDT
            "500000000",  # 500 USDC
            "500000000",  # 500 PYUSD
        ]),
        "taker_address": "0xYourWalletAddress",
    },
)
quote = resp.json()
```

## 2. Understand the Response

The response uses multiple entries in `sellTokens` or `buyTokens`. It also includes a complete settlement transaction:

```json theme={null}
{
  "type": "M21",
  "onchainOrderType": "AggregateOrder",
  "sellTokens": {
    "0xA0b8...": {"amount": "100000000", "symbol": "USDC"},
    "0x6B17...": {"amount": "100000000000000000000", "symbol": "DAI"}
  },
  "buyTokens": {
    "0xdAC1...": {"amount": "198898842", "symbol": "USDT"}
  },
  "tx": {
    "to": "0xbbbbbB...AD5F",
    "value": "0x0",
    "data": "0x4dcebcba...",
    "from": "0x5Bad...bBcB6"
  }
}
```

The API selects `MultiOrder` or `AggregateOrder` from the maker composition. You do not need to process this distinction.

## 3. Sign and Broadcast

Sign and broadcast the returned `tx` object before the quote expires.

```python theme={null}
import httpx
from eth_account import Account
from web3 import Web3

PRIVATE_KEY = "0x<your_private_key_hex>"
RPC_URL = "https://eth.llamarpc.com"
NETWORK = "ethereum"

# --- 1. Request a multi-token quote ---

w3 = Web3(Web3.HTTPProvider(RPC_URL))
account = Account.from_key(PRIVATE_KEY)

resp = httpx.get(
    f"https://api.bebop.xyz/pmm/{NETWORK}/v3/quote",
    params={
        "sell_tokens": ",".join(
            [
                "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",  # USDC
                "0x6B175474E89094C44Da98b954EedeAC495271d0F",  # DAI
            ]
        ),
        "buy_tokens": "0xdAC17F958D2ee523a2206206994597C13D831ec7",  # USDT
        "sell_amounts": ",".join(
            [
                "100000000",  # 100 USDC
                "100000000000000000000",  # 100 DAI
            ]
        ),
        "taker_address": account.address,
    },
)
quote = resp.json()

# --- 2. Approve each sell token for quote["approvalTarget"], if necessary ---
# See the Token Approvals guide for the complete allowance flow.

# --- 3. Sign and broadcast ---

tx = quote["tx"]
if tx["from"].lower() != account.address.lower():
    raise ValueError("The quote taker does not match the signing account")
tx["nonce"] = w3.eth.get_transaction_count(account.address)
tx["chainId"] = quote["chainId"]

signed_tx = w3.eth.account.sign_transaction(tx, account.key)
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
print(f"Multi-token trade submitted: {tx_hash.hex()}")
```

<Info>
  The API selects the order type automatically. Broadcast the returned transaction without changing its settlement calldata.
</Info>
