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

# Swap Tokens with 0x

> Learn how to swap tokens using Portal's iOS SDK with 0x integration.

Portal's iOS SDK provides token swapping functionality through the `portal.trading.zeroX` API. This integration allows you to retrieve swap quotes, inspect available liquidity sources, and execute token swaps using 0x.

## Overview

Using the 0x integration, you can:

* Fetch **indicative prices** for token swaps
* Fetch **swap quotes** between supported tokens
* Retrieve **available liquidity sources**
* **Execute swaps** by signing and submitting transactions

All swap execution is performed by submitting the transaction data returned by 0x using `portal.request`.

## Prerequisites

Before using the 0x API, make sure you have:

* A properly initialized Portal client
* An active wallet with sufficient balance on the source network (see [Create a wallet](./create-a-wallet))
* 0x integration enabled in your Portal Dashboard (see [0x Integration](../../../integrations/Trading/zerox)) OR have a 0x API Key available

***

## Using a Custom 0x API Key (Optional)

By default, Portal uses the 0x API Key that can be added through the Portal Dashboard to communicate with the 0x integration.

If you have a 0x API key that you want to test with locally, you can optionally include it in the request body via the options parameter.

```swift theme={null}
let sources = try await portal.trading.zeroX.getSources(
    chainId: "eip155:1"
)
```

If you've configured your 0x API key in the Portal Dashboard, you can ommit passing the `zeroXApiKey` parameter:

```swift theme={null}
let sources = try await portal.trading.zeroX.getSources(
    chainId: "eip155:1"
)
```

***

## Getting a Price (Indicative)

Use `portal.trading.zeroX.getPrice` to retrieve an **indicative price** for a token swap without generating executable transaction data.

This method is useful for displaying prices, estimating swap outcomes, or building preview experiences without committing to a quote.

```swift theme={null}
let priceRequest = ZeroXPriceRequest(
    chainId: "eip155:1",
    buyToken: "USDC",
    sellToken: "ETH",
    sellAmount: "100000000000000" // 0.0001 ETH
)

let price = try await portal.trading.zeroX.getPrice(
    request: priceRequest
)

print("Price: \(price.data.price.price ?? "N/A")")
print("Buy Amount: \(price.data.price.buyAmount)")
print("Liquidity Available: \(price.data.price.liquidityAvailable ?? false)")
```

***

## Getting a Swap Quote

Use `portal.trading.zeroX.getQuote` to fetch a swap quote from 0x with executable transaction data.

```swift theme={null}
let quoteRequest = ZeroXQuoteRequest(
    chainId: "eip155:1",
    buyToken: "USDC",
    sellToken: "ETH",
    sellAmount: "100000000000000" // 0.0001 ETH
)

let quote = try await portal.trading.zeroX.getQuote(
    request: quoteRequest
)

print("Quote: \(quote.data.quote.price ?? "N/A")")
print("Transaction: \(quote.data.quote.transaction)")
```

***

## Getting Liquidity Sources

You can query available liquidity sources supported by 0x using `portal.trading.zeroX.getSources`.

```swift theme={null}
let sources = try await portal.trading.zeroX.getSources(
    chainId: "eip155:1"
)
print("Available sources: \(sources.data.sources)")
```

***

## Checking Quote Issues

When getting a quote, you may encounter issues related to allowances, balances, or simulation. Always check for these before executing a swap:

```swift theme={null}
let quote = try await portal.trading.zeroX.getQuote(
    request: quoteRequest
)

if let issues = quote.data.quote.issues {
    if let allowance = issues.allowance {
        print("Allowance issue: actual=\(allowance.actual), spender=\(allowance.spender)")
    }
    if let balance = issues.balance {
        print("Balance issue: actual=\(balance.actual), expected=\(balance.expected)")
    }
    if let simulationIncomplete = issues.simulationIncomplete, simulationIncomplete {
        print("Warning: Simulation incomplete")
    }
    if let invalidSources = issues.invalidSourcesPassed, !invalidSources.isEmpty {
        print("Invalid sources: \(invalidSources)")
    }
}
```

***

## Executing the Swap

Once you receive a quote containing transaction data, execute the swap by sending the transaction through `portal.request`.

<Note>
  The transaction data returned by 0x may include gas parameters such as `gas` or `gasPrice`. These fields are optional — you can omit them and let Portal estimate gas automatically, or include them if you prefer to use 0x's suggested values.
</Note>

```swift theme={null}
// Get the quote
let quoteRequest = ZeroXQuoteRequest(
    chainId: "eip155:1",
    buyToken: "USDC",
    sellToken: "ETH",
    sellAmount: "100000000000000" // 0.0001 ETH
)

let quote = try await portal.trading.zeroX.getQuote(
    request: quoteRequest
)

// Extract transaction details
let transaction = quote.data.quote.transaction
let transactionDict: [String: Any] = [
    "data": transaction.data,
    "from": transaction.from,
    "gas": transaction.gas,
    "gasPrice": transaction.gasPrice,
    "to": transaction.to,
    "value": transaction.value
]

// Submit the transaction
let result = try await portal.request(
    chainId: "eip155:1",
    method: .eth_sendTransaction,
    params: [transactionDict],
    options: nil
)

print("Transaction submitted: \(result)")
```

***

## Error Handling

Handle errors gracefully when interacting with the 0x API:

```swift theme={null}
do {
    let sources = try await portal.trading.zeroX.getSources(
        chainId: "eip155:1"
    )
    print("Success: \(sources)")
} catch {
    print("Error: \(error)")
    // Handle specific error types
    if let urlError = error as? URLError {
        print("URL Error: \(urlError.localizedDescription)")
    } else if error is DecodingError {
        print("Decoding Error: Invalid response format")
    }
}
```

***

## Complete Swap Flow Example

Here's a complete example of executing a token swap:

```swift theme={null}
let chainId = "eip155:1"

// Step 1: Get sources
let sources = try await portal.trading.zeroX.getSources(
    chainId: chainId
)
print("Sources: \(sources.data.sources)")

// Step 2: Get quote
let quoteRequest = ZeroXQuoteRequest(
    chainId: chainId,
    buyToken: "USDC",
    sellToken: "ETH",
    sellAmount: "100000000000000" // 0.0001 ETH
)

let quote = try await portal.trading.zeroX.getQuote(
    request: quoteRequest
)

// Step 3: Submit transaction
let transaction = quote.data.quote.transaction
let transactionDict: [String: Any] = [
    "data": transaction.data,
    "from": transaction.from,
    "gas": transaction.gas,
    "gasPrice": transaction.gasPrice,
    "to": transaction.to,
    "value": transaction.value
]

let result = try await portal.request(
    chainId: chainId,
    method: .eth_sendTransaction,
    params: [transactionDict],
    options: nil
)

print("Transaction submitted: \(result)")
```

***

## Supported Networks

The `portal.trading.zeroX` API supports a predefined set of EIP-155 networks. Requests using unsupported chains will fail.

| Network       | EIP-155 Chain ID |
| ------------- | ---------------- |
| Ethereum      | `eip155:1`       |
| Optimism      | `eip155:10`      |
| BSC           | `eip155:56`      |
| Unichain      | `eip155:130`     |
| Polygon       | `eip155:137`     |
| Worldchain    | `eip155:480`     |
| Mantle        | `eip155:5000`    |
| Base          | `eip155:8453`    |
| Monad Testnet | `eip155:10143`   |
| Mode          | `eip155:34443`   |
| Arbitrum      | `eip155:42161`   |
| Avalanche     | `eip155:43114`   |
| Ink           | `eip155:57073`   |
| Linea         | `eip155:59144`   |
| Berachain     | `eip155:80094`   |
| Blast         | `eip155:81457`   |
| Scroll        | `eip155:534352`  |

***

## Next Steps

* Learn how to [sign Ethereum transactions](./sign-a-transaction)
* Explore how to [send tokens](./send-tokens)
* Check out [Portal API methods](./portal-api-methods)
