Skip to main content

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.

Cross-chain swap endpoints are experimental and require explicit enablement by both the Portal and 0x teams before they can be used. Contact your Portal account manager to request access.
Portal’s Enclave MPC API provides cross-chain bridging and swapping through 0x. This guide covers getting quotes, executing swaps, and tracking transaction status across chains.

Overview

Using 0x cross-chain, you can:
  • Get quotes for cross-chain swaps across EVM chains with multiple bridge providers
  • Execute cross-chain swaps by signing and submitting the returned transaction
  • Track transaction status for cross-chain transfers
  • Browse transaction history for a wallet address
  • List available sources including bridge providers and DEX sources

Prerequisites

Before using 0x cross-chain operations, ensure you have:
  • A properly initialized Portal client (see Create a client)
  • An active wallet with the required token(s) on the origin chain (see Create a wallet)
  • 0x integration enabled in your Portal Dashboard with a cross-chain-enabled API key (see 0x Integration)

Getting Cross-Chain Quotes

Use the POST /api/v3/clients/me/integrations/0x/cross-chain/quotes endpoint to get quotes for a cross-chain swap.
curl --request POST \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/0x/cross-chain/quotes' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "originChain": "eip155:8453",
  "destinationChain": "eip155:42161",
  "sellToken": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
  "buyToken": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
  "sellAmount": "1000000",
  "sortQuotesBy": "price"
}'

Parameters

NameTypeRequiredDescription
originChainstringYesOrigin chain in CAIP-2 format (e.g. eip155:8453)
destinationChainstringYesDestination chain in CAIP-2 format (e.g. eip155:42161)
sellTokenstringYesToken to sell on the origin chain. Accepts a contract address (e.g. 0x833589...), a native token keyword (NATIVE, ETH, AVAX, POL, etc.), or a supported token symbol (USDC, USDT)
buyTokenstringYesToken to buy on the destination chain. Same formats as sellToken
sellAmountstringYesAmount of sellToken to sell, in base units (the smallest indivisible unit of the token, e.g. 1000000 for 1 USDC since USDC has 6 decimals, or wei for native ETH)
sortQuotesBystringYesSort quotes by speed or price
originAddressstringNoWallet address on origin chain. Defaults to the client’s EIP-155 address
destinationAddressstringNoWallet address to receive tokens. Defaults to originAddress
slippageBpsnumberNoMaximum slippage in basis points (100 = 1%). Defaults to 100
maxNumQuotesnumberNoMaximum number of quotes to return (1-10). Defaults to 3
excludedBridgesstringNoComma-separated bridge providers to exclude
includedBridgesstringNoComma-separated bridge providers to include
feeBpsstringNoIntegrator fee in basis points
feeRecipientstringNoAddress to receive integrator fees

Response

The response includes an array of quotes, each containing:
  • sellAmount / buyAmount / minBuyAmount - Token amounts in base units
  • steps - Sequential steps (swap, bridge, wrap/unwrap) required to complete the cross-chain swap
  • transaction - A Portal-formatted transaction object (from, to, data, gas, gasPrice, value) ready to sign and submit
  • approvalTransaction - A Portal-formatted approval transaction (included automatically when token allowance is needed on EVM origin chains). Sign and submit this before the main transaction
  • estimatedTimeSeconds - Estimated time for the swap to complete
  • fees - Breakdown of integrator fees, 0x fees, and bridge fees
  • issues - Problems that would cause the swap to fail (allowance, balance, simulation, invalid sources). See Inspecting issues below
When issues.allowance is present, the response automatically includes an approvalTransaction that approves the exact sellAmount for the swap. This uses the minimum required approval for security — no unlimited approvals.

Inspecting issues

Before submitting any transactions, inspect the quote’s issues property. It surfaces problems that would otherwise cause the swap to fail on-chain:
  • allowance - The wallet hasn’t approved enough of sellToken for the 0x contract. Sign the included approvalTransaction (covered in Step 1 below).
  • balance - The wallet doesn’t hold enough sellToken to cover sellAmount. Top up the wallet before retrying.
  • simulationIncomplete - 0x couldn’t fully simulate the swap, so execution may revert. Re-fetch the quote, or proceed with caution if the route is otherwise sound.
  • invalidSourcesPassed - One of the bridges or DEX sources you requested via includedBridges isn’t valid for this route. Adjust includedBridges / excludedBridges and re-fetch.
Resolve any issues (top up the wallet, exclude a problematic source, etc.), then fetch a new quote and proceed with the steps below.

Executing a Cross-Chain Swap

After selecting a quote, check if an approvalTransaction is present. If so, you must sign and submit it before the main transaction. This is a two-step signing flow:
  1. Sign approvalTransaction (if present) — approves the 0x contract to spend your ERC20 tokens
  2. Re-fetch a fresh quote — the original quote may have expired while the approval was confirming
  3. Sign transaction — executes the cross-chain swap
If approvalTransaction is present in the quote response, you must sign and submit it before the main transaction. Submitting the swap transaction without approval will fail with an “ERC20: transfer amount exceeds allowance” error.

Step 1: Approve Token Allowance (if required)

If the quote includes approvalTransaction, sign and submit it first. This approves the 0x contract to spend the exact amount of your sell token needed for the swap.
curl --request POST \
  --url https://mpc-client.portalhq.io/v1/sign \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "share": "[share]",
  "method": "eth_sendTransaction",
  "params": [approvalTransaction],
  "rpcUrl": "https://api.portalhq.io/rpc/v1/eip155/8453",
  "chainId": "eip155:8453"
}'
Pass the entire approvalTransaction object from the quote response as params. Wait for the approval transaction to confirm before proceeding to the next step.
Native token swaps (e.g. ETH, AVAX) do not require approval since they are not ERC20 tokens. The approvalTransaction field will only be present when swapping ERC20 tokens that require allowance.

Step 2: Re-fetch a Fresh Quote

After the approval confirms, fetch a new quote. The original quote contains calldata with embedded timestamps that may have expired during the approval confirmation.
# Re-fetch quote with the same parameters as Step 1
curl --request POST \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/0x/cross-chain/quotes' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "originChain": "eip155:8453",
  "destinationChain": "eip155:42161",
  "sellToken": "USDC",
  "buyToken": "USDC",
  "sellAmount": "1000000",
  "sortQuotesBy": "price"
}'
The new quote should no longer include approvalTransaction (since the allowance is now set) and the transaction calldata will have fresh timestamps.

Step 3: Sign and Submit the Cross-Chain Transaction

Use the transaction from the fresh quote:
curl --request POST \
  --url https://mpc-client.portalhq.io/v1/sign \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "share": "[share]",
  "method": "eth_sendTransaction",
  "params": [transaction],
  "rpcUrl": "https://api.portalhq.io/rpc/v1/eip155/8453",
  "chainId": "eip155:8453"
}'
Pass the entire transaction object from the quote response as params.
The rpcUrl and chainId should correspond to the origin chain, since the transaction is submitted on the origin chain. The bridge provider handles delivering tokens to the destination chain.

Step 4: Resolve the Transaction Hash (Account Abstraction clients only)

If your client uses Account Abstraction, the eth_sendTransaction response contains a user operation hash rather than a transaction hash. The cross-chain status endpoint requires the actual on-chain transaction hash, so resolve the userOp hash first:
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/chains/eip155:8453/transactions/[userOpHash]' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
Use evmUserOperation.receipt.hash from the response as the originTxHash in Step 5. EOA clients can skip this step and use the hash returned from signing directly. See the transaction lookup endpoint for the full response shape.

Step 5: Track Transaction Status

Use the GET /api/v3/clients/me/integrations/0x/cross-chain/status endpoint to track the cross-chain transfer:
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/0x/cross-chain/status?originChain=eip155:8453&originTxHash=0xYourTransactionHash' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'

Status Values

StatusDescription
origin_tx_pendingOrigin chain transaction is pending
origin_tx_succeededOrigin chain transaction succeeded
origin_tx_confirmedOrigin chain transaction is confirmed
origin_tx_revertedOrigin chain transaction reverted
bridge_pendingBridge transfer is in progress
bridge_filledBridge transfer completed successfully
bridge_failedBridge transfer failed (check failure field for details)
If the status is bridge_failed, check the failure field in the response. In some cases (e.g. Stargate V2), a failure.recovery.manualTransaction may be provided that you can submit to recover funds on the destination chain.

Listing Available Sources

Use the GET /api/v3/clients/me/integrations/0x/cross-chain/sources endpoint to list available bridge providers and DEX sources:
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/0x/cross-chain/sources' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
The response includes:
  • bridges - Available bridge providers with supported origin/destination chain pairs
  • swapSources - Available DEX sources with supported chain IDs

Viewing Transaction History

Use the GET /api/v3/clients/me/integrations/0x/cross-chain/tx-history endpoint to view cross-chain transaction history for a wallet:
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/0x/cross-chain/tx-history?user=0xYourWalletAddress&limit=20' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'

Example Flow

Here’s a complete example of a cross-chain swap from Base USDC to Arbitrum USDC:
# 1. Get cross-chain quotes
QUOTE_RESPONSE=$(curl --request POST \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/0x/cross-chain/quotes' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "originChain": "eip155:8453",
  "destinationChain": "eip155:42161",
  "sellToken": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
  "buyToken": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
  "sellAmount": "1000000",
  "sortQuotesBy": "price"
}')

# 2. Inspect quote.issues, then select a quote and pass its `transaction`
#    object straight through as `params` below.

# 3. Sign and submit the transaction on the origin chain
curl --request POST \
  --url https://mpc-client.portalhq.io/v1/sign \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "share": "[share]",
  "method": "eth_sendTransaction",
  "params": [transaction],
  "rpcUrl": "https://api.portalhq.io/rpc/v1/eip155/8453",
  "chainId": "eip155:8453"
}'

# 4. Track the cross-chain transfer status (AA clients: first resolve the
#    userOp hash to a tx hash via GET /clients/me/chains/{chain}/transactions/{userOpHash})
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/0x/cross-chain/status?originChain=eip155:8453&originTxHash=0xYourTransactionHash' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'

Failure Handling

Cross-chain operations are non-atomic. If a bridge transfer fails:
  • Automatic refunds: For Across, Relay, and Squid Coral, the user will be refunded in the bridging token (which may differ from the original sell token) on the origin chain.
  • Manual recovery: For Stargate V2, funds may be delivered to the destination chain but not to the wallet. The status API will return a failure.recovery.manualTransaction that can be submitted to re-trigger delivery.
Always monitor transaction status after submission and implement appropriate error handling for your users.

Supported Networks

0x cross-chain supports bridging between the following EVM networks:
  • Ethereum (eip155:1)
  • Base (eip155:8453)
  • Arbitrum (eip155:42161)
  • Optimism (eip155:10)
  • Polygon (eip155:137)
  • BSC (eip155:56)
  • Avalanche (eip155:43114)
  • Linea (eip155:59144)
  • Blast (eip155:81457)
  • Scroll (eip155:534352)
Use the sources endpoint to get the full list of supported bridge pairs.

Next Steps