Skip to main content
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)
  • 0x integration enabled in your Portal Dashboard (see 0x Integration) 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.
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:
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.
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.
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.
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:
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.
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.
// 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:
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:
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.
NetworkEIP-155 Chain ID
Ethereumeip155:1
Optimismeip155:10
BSCeip155:56
Unichaineip155:130
Polygoneip155:137
Worldchaineip155:480
Mantleeip155:5000
Baseeip155:8453
Monad Testneteip155:10143
Modeeip155:34443
Arbitrumeip155:42161
Avalancheeip155:43114
Inkeip155:57073
Lineaeip155:59144
Berachaineip155:80094
Blasteip155:81457
Scrolleip155:534352

Next Steps