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

Portal's Web SDK provides high-level 0x swaps through
`portal.trading.zeroX.tradeAsset(...)` and lower-level access through
`portal.trading.zeroX`.

## Overview

Using the 0x integration, you can:

* **Trade assets end-to-end** with one high-level call
* **Track lifecycle progress** from quote fetch to confirmation
* **Override signer and confirmation behavior** per call when needed
* Fetch **indicative prices** for token swaps
* Fetch **swap quotes** between supported tokens
* Retrieve **available liquidity sources**
* **Execute swaps manually** by signing and submitting transactions from a quote

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

## High-Level Methods

### `tradeAsset`

Fetches a 0x quote, signs and broadcasts the quote transaction, waits for on-chain confirmation, and returns hashes.

### Signature

```typescript theme={null}
tradeAsset(
  params: ZeroXTradeAssetParams,
  options?: ZeroXTradeAssetOptions & ZeroExOptions,
): Promise<ZeroXTradeAssetResult>
```

**Essential parameters**

| Name                                             | Required | Description                                                                                   |
| ------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------- |
| `chainId`                                        | Yes      | CAIP-2 chain (e.g. `'eip155:1'`). See [Supported Networks](#supported-networks).              |
| `sellToken`                                      | Yes      | Token to sell (symbol or address).                                                            |
| `buyToken`                                       | Yes      | Token to buy (symbol or address).                                                             |
| `sellAmount`                                     | Yes      | Amount in base units (smallest units).                                                        |
| `fromAddress`                                    | Yes      | Sender address used by high-level 0x execution (**use this field, not `txOrigin`**).          |
| `slippageBps`                                    | No       | Max slippage in basis points (e.g. `100` = 1%).                                               |
| `swapFeeRecipient`, `swapFeeBps`, `swapFeeToken` | No       | Integrator fee fields.                                                                        |
| `tradeSurplusRecipient`                          | No       | Surplus recipient.                                                                            |
| `gasPrice`                                       | No       | Optional gas price.                                                                           |
| `excludedSources`                                | No       | Comma-separated sources to exclude.                                                           |
| `sellEntireBalance`                              | No       | `'true'` / `'false'`.                                                                         |
| `onProgress`                                     | No       | Stages such as `fetching_quote`, `signing`, `submitted`, `confirming`, `confirmed`, `failed`. |
| `zeroXApiKey`                                    | No       | Override the Dashboard key for this call.                                                     |

`ZeroXTradeAssetOptions`:

| Name                                             | Required | Description                                                                                                                                                                    |
| ------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `signAndSendTransaction`                         | No       | Per-call signer override.                                                                                                                                                      |
| `waitForConfirmation`                            | No       | Per-call confirmation override. **MUST return `true` or resolve for success.** Returning `false`, throwing an error, or timing out will **abort the swap** and throw an error. |
| `evmRequestFn`                                   | No       | **Web SDK:** When `waitForConfirmation` is omitted, receipt polling can use this JSON-RPC function (e.g. `eth_getTransactionReceipt`) on EVM chains.                           |
| `evmPollerOptions`                               | No       | Tune the built-in EVM receipt poller when using `evmRequestFn` (`pollIntervalMs`, `timeoutMs`).                                                                                |
| *(Inherited from `ZeroExOptions`)* `zeroXApiKey` | No       | Per-call API key (overrides Dashboard key).                                                                                                                                    |

**Return value**

| Field    | Description                   |
| -------- | ----------------------------- |
| `hashes` | Broadcast transaction hashes. |

<Note>
  0x `tradeAsset` execution precedence:

  * **Signer:** per-call `options.signAndSendTransaction` → instance default signer → throw
  * **Confirmation:** per-call `options.waitForConfirmation` → instance default waiter, **or** on Web, `evmRequestFn` + receipt polling when `waitForConfirmation` is omitted

  Confirmation is strict: if the waiter returns `false`, times out, throws an error, or the network is unsupported, the swap fails immediately and throws.

  On **portal-react-native**, `tradeAsset` does not offer `evmRequestFn`; you supply `waitForConfirmation` (or rely on the Portal default where wired).
</Note>

<Warning>
  `tradeAsset` requires **at least one** confirmation mechanism. If neither `waitForConfirmation` nor `evmRequestFn` is available (from instance defaults or per-call options), the method throws immediately:

  `[ZeroX] tradeAsset requires waitForConfirmation (instance default or per-call option), or evmRequestFn fallback.`

  When you construct `Portal` with an `rpcConfig`, `evmRequestFn` is wired automatically — no extra setup needed. This requirement only surfaces when using `ZeroX` standalone or without Portal's default wiring.

  Receipt-polling timeouts are **strict**: if confirmation times out, the swap throws and does not return a result.
</Warning>

**Example (`onProgress` + default on-chain wait)**

```typescript theme={null}
import Portal from '@portal-hq/web'
import type { ZeroXTradeAssetParams } from '@portal-hq/web'

const portal = new Portal({
  apiKey: 'YOUR_PORTAL_CLIENT_API_KEY',
  rpcConfig: {
    'eip155:1': 'https://YOUR_RPC_URL',
  },
})

async function swap() {
  const eip155Address = await portal.getEip155Address()
  if (!eip155Address) throw new Error('No EVM address')

  const params: ZeroXTradeAssetParams = {
    chainId: 'eip155:1',
    sellToken: 'ETH',
    buyToken: 'USDC',
    sellAmount: '100000000000000',
    fromAddress: eip155Address,
    onProgress: (status, data) => {
      console.log('[0x]', status, data?.txHash ?? '', data?.errorMessage ?? '')
    },
  }

  try {
    const result = await portal.trading.zeroX.tradeAsset(params)
    console.log('Hashes:', result.hashes)
    return result
  } catch (e) {
    console.error('tradeAsset failed', e)
    throw e
  }
}
```

Use `try/catch` around `tradeAsset`; `onProgress` may emit `failed` before the thrown error.

***

## Example (custom API key + execution options)

```typescript theme={null}
const eip155Address = await portal.getEip155Address()
if (!eip155Address) throw new Error('No EVM address')

const result = await portal.trading.zeroX.tradeAsset(
  {
    chainId: 'eip155:1',
    sellToken: 'ETH',
    buyToken: 'USDC',
    sellAmount: '100000000000000',
    fromAddress: eip155Address,
    zeroXApiKey: 'YOUR_0X_API_KEY',
    onProgress: (status, data) => {
      console.log('[0x]', status, data?.txHash ?? '', data?.errorMessage ?? '')
    },
  },
  {
    waitForConfirmation: async (txHash, network) => {
      return portal.waitForConfirmation(txHash, network)
    },
  },
)

console.log(result.hashes)
```

***

## Low-level methods

The following methods return quotes, prices, or raw transaction data for you to sign with `portal.request` when you need full control over each step.

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

```typescript theme={null}
await portal.trading.zeroX.getQuote(request)
```

```typescript theme={null}
await portal.trading.zeroX.getQuote(request, {
  zeroXApiKey: 'YOUR_0X_API_KEY',
})
```

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

```typescript theme={null}
async function getZeroXPrice(portal: Portal) {
  const request: ZeroExPriceRequest = {
    chainId: 'eip155:8453', // BASE network
    sellToken: 'ETH',
    buyToken: 'USDC',
    sellAmount: '10000000000000', // 0.00001 ETH
  }

  const response = await portal.trading.zeroX.getPrice(request)
  const price = response.data.rawResponse
}
```

### Getting a Swap Quote

Use `portal.trading.zeroX.getQuote` to fetch a swap quote from 0x.

```typescript theme={null}
async function getZeroXQuote(portal: Portal) {
  const takerAddress = await portal.getEip155Address()

  const request: ZeroExQuoteRequest = {
    chainId: 'eip155:8453', // BASE network
    sellToken: 'ETH',
    buyToken: 'USDC',
    sellAmount: '10000000000000', // 0.00001 ETH
  }

  const response = await portal.trading.zeroX.getQuote(request)
  const quote = response.data.rawResponse

  console.log(quote)
}
```

### Getting Liquidity Sources

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

For full request and response details, refer to the Client API documentation.

```typescript theme={null}
async function getZeroXSources(portal: Portal) {
  const response = await portal.trading.zeroX.getSources('eip155:1')

  const sources = response.data.rawResponse
}
```

### Low-level: 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.

```typescript theme={null}
async function executeSwap(
  portal: Portal,
  fromAddress: string,
  quoteResponse: ZeroExQuoteResponse,
  chainId: string
) {
  const ethTx: ETHTransactionParam = {
    from: fromAddress,
    to: quoteResponse.data?.rawResponse.transaction.to,
    value: quoteResponse.data?.rawResponse.transaction.value ?? '0x0',
    data: quoteResponse.data?.rawResponse.transaction.data,
  }

  const response = await portal.request({ chainId, method: 'eth_sendTransaction', params: [ethTx] })
}
```

## 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)
* Review the [Client API 0x endpoints](../../../apis/client/manual-reference#0x-integration)
