> ## 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 Android SDK with 0x integration.

Portal's Android 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 via the `zeroXApiKey` parameter.

```kotlin theme={null}
lifecycleScope.launch {
    val sourcesResult = portal.trading.zeroX.getSources(
        chainId = "eip155:1",
        zeroXApiKey = "YOUR_0X_API_KEY"
    )
    
    sourcesResult.fold(
        onSuccess = { response ->
            val sources = response.data?.rawResponse?.sources ?: emptyList()
            println("Available sources: $sources")
        },
        onFailure = { error ->
            println("Error: $error")
        }
    )
}
```

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

```kotlin theme={null}
lifecycleScope.launch {
    val sourcesResult = portal.trading.zeroX.getSources(
        chainId = "eip155:1"
    )
    
    sourcesResult.fold(
        onSuccess = { response ->
            val sources = response.data?.rawResponse?.sources ?: emptyList()
            println("Available sources: $sources")
        },
        onFailure = { error ->
            println("Error: $error")
        }
    )
}
```

***

## 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.

```kotlin theme={null}
lifecycleScope.launch {
    val priceRequest = ZeroXPriceRequest(
        chainId = "eip155:1",
        buyToken = "USDC",
        sellToken = "ETH",
        sellAmount = "100000000000000" // 0.0001 ETH
    )
    
    val priceResult = portal.trading.zeroX.getPrice(
        request = priceRequest
    )
    
    priceResult.fold(
        onSuccess = { response ->
            val data = response.data?.rawResponse
            println("Price: ${data?.price ?: "N/A"}")
            println("Buy Amount: ${data?.buyAmount}")
            println("Liquidity Available: ${data?.liquidityAvailable ?: false}")
        },
        onFailure = { error ->
            println("Error: $error")
        }
    )
}
```

***

## Getting a Swap Quote

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

```kotlin theme={null}
lifecycleScope.launch {
    val quoteRequest = ZeroXQuoteRequest(
        chainId = "eip155:1",
        buyToken = "USDC",
        sellToken = "ETH",
        sellAmount = "100000000000000" // 0.0001 ETH
    )
    
    val quoteResult = portal.trading.zeroX.getQuote(
        request = quoteRequest
    )
    
    quoteResult.fold(
        onSuccess = { response ->
            val quote = response.data?.rawResponse
            println("Quote: ${quote?.price ?: "N/A"}")
            println("Transaction: ${quote?.transaction}")
        },
        onFailure = { error ->
            println("Error: $error")
        }
    )
}
```

***

## Getting Liquidity Sources

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

```kotlin theme={null}
lifecycleScope.launch {
    val sourcesResult = portal.trading.zeroX.getSources(
        chainId = "eip155:1"
    )
    
    sourcesResult.fold(
        onSuccess = { response ->
            val sources = response.data?.rawResponse?.sources ?: emptyList()
            println("Available sources: $sources")
        },
        onFailure = { error ->
            println("Error: $error")
        }
    )
}
```

***

## 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:

```kotlin theme={null}
lifecycleScope.launch {
    val quoteResult = portal.trading.zeroX.getQuote(
        request = quoteRequest
    )
    
    quoteResult.fold(
        onSuccess = { response ->
            val issues = response.data?.rawResponse?.issues
            
            issues?.allowance?.let { allowance ->
                println("Allowance issue: actual=${allowance.actual}, spender=${allowance.spender}")
            }
            
            issues?.balance?.let { balance ->
                println("Balance issue: actual=${balance.actual}, expected=${balance.expected}")
            }
            
            issues?.simulationIncomplete?.let { incomplete ->
                if (incomplete) {
                    println("Warning: Simulation incomplete")
                }
            }
            
            issues?.invalidSourcesPassed?.let { invalidSources ->
                if (invalidSources.isNotEmpty()) {
                    println("Invalid sources: $invalidSources")
                }
            }
        },
        onFailure = { error ->
            println("Error: $error")
        }
    )
}
```

***

## 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>

```kotlin theme={null}
lifecycleScope.launch {
    // Get the quote
    val quoteRequest = ZeroXQuoteRequest(
        chainId = "eip155:1",
        buyToken = "USDC",
        sellToken = "ETH",
        sellAmount = "100000000000000" // 0.0001 ETH
    )
    
    val quoteResult = portal.trading.zeroX.getQuote(
        request = quoteRequest
    )
    
    quoteResult.fold(
        onSuccess = { response ->
            val quoteData = response.data
            if (quoteData == null) {
                println("Error: No data in response")
                return@fold
            }
            
            val transaction = quoteData.rawResponse?.transaction
            if (transaction == null) {
                println("Error: No transaction in quote response")
                return@fold
            }
            
            // Convert ZeroXTransaction to EthTransactionParam
            val ethTransaction = EthTransactionParam(
                from = transaction.from,
                to = transaction.to,
                gas = transaction.gas,
                gasPrice = transaction.gasPrice,
                maxFeePerGas = null,
                maxPriorityFeePerGas = null,
                value = transaction.value,
                data = transaction.data,
                nonce = null
            )
            
            // Submit the transaction
            val sendTransactionResponse = portal.request(
                chainId = "eip155:1",
                method = PortalRequestMethod.eth_sendTransaction,
                params = listOf(ethTransaction)
            )
            
            val transactionHash = sendTransactionResponse.result as? String
            if (transactionHash != null) {
                println("Transaction submitted: $transactionHash")
            } else {
                println("Error: Invalid response type for request")
            }
        },
        onFailure = { error ->
            println("Error: $error")
        }
    )
}
```

***

## Error Handling

Handle errors gracefully when interacting with the 0x API:

```kotlin theme={null}
lifecycleScope.launch {
    val sourcesResult = portal.trading.zeroX.getSources(
        chainId = "eip155:1"
    )
    
    sourcesResult.fold(
        onSuccess = { response ->
            val sources = response.data?.rawResponse?.sources ?: emptyList()
            println("Success: $sources")
        },
        onFailure = { error ->
            println("Error: $error")
            // Handle specific error types
            when (error) {
                is PortalHttpException -> {
                    println("HTTP Error: ${error.message}")
                }
                is PortalHttpUnauthorizedException -> {
                    println("Unauthorized: Check your API key")
                }
                else -> {
                    println("Unknown error: ${error.message}")
                }
            }
        }
    )
}
```

***

## Complete Swap Flow Example

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

```kotlin theme={null}
lifecycleScope.launch {
    val chainId = "eip155:1"
    
    try {
        // Step 1: Get sources
        val sourcesResult = portal.trading.zeroX.getSources(
            chainId = chainId
        )
        
        sourcesResult.fold(
            onSuccess = { sourcesResponse ->
                val sources = sourcesResponse.data?.rawResponse?.sources ?: emptyList()
                println("Sources: $sources")
                
                // Step 2: Get quote
                val quoteRequest = ZeroXQuoteRequest(
                    chainId = chainId,
                    buyToken = "USDC",
                    sellToken = "ETH",
                    sellAmount = "100000000000000" // 0.0001 ETH
                )
                
                val quoteResult = portal.trading.zeroX.getQuote(
                    request = quoteRequest
                )
                
                quoteResult.fold(
                    onSuccess = { quoteResponse ->
                        val quoteData = quoteResponse.data
                        if (quoteData == null) {
                            println("Error: No data in response")
                            return@fold
                        }
                        
                        val transaction = quoteData.rawResponse?.transaction
                        if (transaction == null) {
                            println("Error: No transaction in quote response")
                            return@fold
                        }
                        
                        // Step 3: Submit transaction
                        val ethTransaction = EthTransactionParam(
                            from = transaction.from,
                            to = transaction.to,
                            gas = transaction.gas,
                            gasPrice = transaction.gasPrice,
                            maxFeePerGas = null,
                            maxPriorityFeePerGas = null,
                            value = transaction.value,
                            data = transaction.data,
                            nonce = null
                        )
                        
                        val sendTransactionResponse = portal.request(
                            chainId = chainId,
                            method = PortalRequestMethod.eth_sendTransaction,
                            params = listOf(ethTransaction)
                        )
                        
                        val transactionHash = sendTransactionResponse.result as? String
                        if (transactionHash != null) {
                            println("Transaction submitted: $transactionHash")
                        } else {
                            println("Error: Invalid response type for request")
                        }
                    },
                    onFailure = { error ->
                        println("Error getting quote: $error")
                    }
                )
            },
            onFailure = { error ->
                println("Error getting sources: $error")
            }
        )
    } catch (error: Throwable) {
        println("Error: $error")
    }
}
```

***

## 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)
