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.

Portal’s React Native SDK provides comprehensive cross-chain bridging and swapping capabilities through the portal.trading.lifi API. This guide covers getting quotes, finding routes, executing swaps and bridges, and tracking transaction status.

Overview

The Li.Fi functionality allows you to:
  • Get quotes for bridging or swapping tokens across chains
  • Find routes to discover the best paths for your cross-chain transfers
  • Execute swaps and bridges by signing and submitting transactions
  • Track transaction status for cross-chain transfers
Supported Chains: Li.Fi integration currently supports EVM-compatible chains (Ethereum, Base, Arbitrum, Polygon, etc.) and Solana. Other non-EVM chains may not be supported for Li.Fi operations.

Prerequisites

Before using Li.Fi operations, ensure you have:
  • A properly initialized Portal client
  • An active wallet with the required token(s) on the source network (see Create a wallet)
  • Li.Fi integration enabled in your Portal Dashboard (see Li.Fi Integration)

High-Level Methods

tradeAsset

Runs the end-to-end Li.Fi flow in one call:
  1. Discover routes (getRoutes)
  2. Select a route (routeIndex, default 0)
  3. Build each step (getRouteStep)
  4. Sign and broadcast each step transaction
  5. Wait for on-chain confirmation for that step
  6. Poll Li.Fi status until terminal for that step
  7. Continue to the next step
Steps are executed sequentially (in order), not in parallel. Confirmation behavior: tradeAsset uses strict confirmation semantics. Each step MUST be confirmed on-chain before proceeding to the next step. If waitForConfirmation returns false, times out, or throws, the entire flow fails and an error is thrown. There is no optimistic fallback.

Signature

tradeAsset(
  params: LifiTradeAssetParams,
  options?: LifiTradeAssetOptions,
): Promise<LifiTradeAssetResult>
Essential parameters
NameRequiredDescription
fromChainYesSource chain, CAIP-2 (e.g. 'eip155:8453').
toChainYesDestination chain, CAIP-2.
fromTokenYesSource token symbol or address.
toTokenYesDestination token symbol or address.
amountYesAmount in smallest units (e.g. wei).
fromAddressYesSender address.
toAddressNoRecipient; defaults to fromAddress.
routeOptionsNoSlippage, ordering, bridges, etc. See Route options.
routeIndexNoRoute index from discovery; default 0.
onProgressNoFired for each major stage (fetching_routes, signing, submitted, confirming, lifi_pending, complete, failed, …).
statusPollNoOverrides the built-in Li.Fi status polling used after on-chain confirmation for each step (same shape as pollStatus).
Second argument LifiTradeAssetOptions:
NameRequiredDescription
signAndSendTransactionNoPer-call signer override for route-step transactions.
waitForConfirmationNoPer-call confirmation override. Called after each submitted step with (txHash, network). MUST return true or resolve for success. Returning false, throwing an error, or timing out will abort the entire flow and throw an error. When omitted, the built-in EVM receipt poller is used with the same strict behavior.
evmRequestFnNoPer-call EVM RPC function used by the built-in fallback EVM receipt poller when waitForConfirmation is not provided.
evmPollerOptionsNoPer-call tuning for the built-in EVM receipt poller (pollIntervalMs, timeoutMs) when waitForConfirmation is not provided.
Return value
FieldDescription
hashesTransaction hashes per executed step.
stepsStep objects from the API.
routeThe executed route.
Example (progress + per-call confirmation options)
import Portal from '@portal-hq/core'
import type { LifiTradeAssetParams, LifiTradeAssetOptions } from '@portal-hq/core'

const portal = new Portal({
  apiKey: 'YOUR_PORTAL_CLIENT_API_KEY',
  backup: {
    /* ... */
  },
  gatewayConfig: {
    'eip155:8453': 'https://YOUR_RPC_URL',
    'eip155:42161': 'https://YOUR_RPC_URL',
  },
})

async function runTrade() {
  const addresses = await portal.addresses
  const fromAddress = addresses?.eip155
  if (!fromAddress) throw new Error('No EVM address')

  const params: LifiTradeAssetParams = {
    fromChain: 'eip155:8453',
    toChain: 'eip155:42161',
    fromToken: 'ETH',
    toToken: 'USDC',
    amount: '1000000000000',
    fromAddress,
    statusPoll: {
      everyMs: 10_000,
      initialDelayMs: 10_000,
      timeoutMs: 600_000,
    },
    onProgress: (status, data) => {
      console.log('[Li.Fi]', status, data.txHash ?? '')
    },
  }

  const options: LifiTradeAssetOptions = {
    waitForConfirmation: async (txHash, network) => {
      // Example: reuse Portal confirmation helper, or plug in custom logic
      return portal.waitForConfirmation(txHash, network)
    },
    evmPollerOptions: { pollIntervalMs: 4_000, timeoutMs: 600_000 },
  }

  try {
    const result = await portal.trading.lifi.tradeAsset(params, options)
    console.log('Hashes:', result.hashes)
    console.log('Executed steps:', result.steps.length)
    console.log('Route id:', result.route.id)
    return result
  } catch (e) {
    console.error('tradeAsset failed', e)
    throw e
  }
}
Example (default confirmation behavior)
const result = await portal.trading.lifi.tradeAsset({
  fromChain: 'eip155:8453',
  toChain: 'eip155:42161',
  fromToken: 'ETH',
  toToken: 'USDC',
  amount: '1000000000000',
  fromAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
})
Wrap tradeAsset in try/catch; failures (no route, step error, receipt timeout, Li.Fi terminal FAILED, …) throw after onProgress may report 'failed'.

Progress lifecycle

onProgress can emit statuses such as:
  • fetching_routes
  • route_selected
  • preparing_step
  • signing
  • submitted
  • confirming
  • lifi_pending
  • step_done
  • complete
  • failed

pollStatus

Built-in Li.Fi status polling with retries and backoff. Use when you already have a tx hash (for example from a manual flow) and want the same polling behavior as inside tradeAsset, without implementing the loop yourself.
import Portal from '@portal-hq/core'

async function pollTransferStatus(portal: Portal, txHash: string) {
  const terminal = await portal.trading.lifi.pollStatus(
    {
      txHash,
      fromChain: 'eip155:8453',
      toChain: 'eip155:42161',
    },
    (statusUpdate) => {
      console.log('Status:', statusUpdate.status)
      return true
    },
    { everyMs: 10_000, timeoutMs: 600_000 },
  )

  console.log('Final status:', terminal.status)
}

pollStatus options

NameDefaultDescription
everyMs10000Time between requests (ms).
initialDelayMs0 here / 10000 in tradeAsset’s statusPollDelay before the first request.
timeoutMs600000Max total poll time.
maxConsecutiveErrors10Abort after this many consecutive hard errors.
backofffactor 1.5, maxIntervalMs 15000Backoff between polls.
Return false from the update callback to stop early; return true (or nothing) to continue.

Route Options

The routeOptions parameter on tradeAsset (and the options field on LifiRoutesRequest) accepts a LifiRoutesRequestOptions object:
NameTypeDescription
slippagenumberMaximum acceptable slippage as a decimal (e.g. 0.005 for 0.5%).
order'FASTEST' | 'CHEAPEST'Route ordering preference.
insurancebooleanWhether to include bridge insurance.
bridgesLifiToolsConfigurationAllow/deny specific bridge tools.
exchangesLifiToolsConfigurationAllow/deny specific exchange tools.
allowSwitchChainbooleanAllow routes that require switching chains mid-route.
allowDestinationCallbooleanAllow contract calls on the destination chain.
feenumberIntegrator fee percentage.
maxPriceImpactnumberMaximum price impact as a decimal.
referrerstringReferrer address for fee sharing.

Getting a Quote

import { LifiQuoteRequest } from '@portal-hq/trading'

async function getQuote(portal: Portal) {
  const addresses = await portal.addresses
  const fromAddress = addresses?.eip155

  if (!fromAddress) {
    throw new Error('No EVM address found')
  }

const request: LifiQuoteRequest = {
  fromChain: 'eip155:8453',
  toChain: 'eip155:42161',
  // Amount in wei (1 ETH = 1e18 wei)
  // 1_000_000_000_000 wei = 0.000001 ETH
  fromAmount: '1000000000000',
  fromToken: 'ETH',
  toToken: 'USDC',
  fromAddress,
}


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

  if (!quote) return

  console.log('To amount:', quote.estimate?.toAmount)

  if (quote.transactionRequest) {
    await executeTransaction(
      portal,
      quote.transactionRequest,
      request.fromChain
    )
  }
}

Finding Routes

import { LifiRoutesRequest } from '@portal-hq/trading'

async function getRoutes(portal: Portal) {
  const addresses = await portal.addresses
  const fromAddress = addresses?.eip155

  if (!fromAddress) {
    throw new Error('No EVM address found')
  }

const request: LifiRoutesRequest = {
  fromChainId: 'eip155:8453',
  toChainId: 'eip155:42161',
  fromTokenAddress: 'ETH',
  toTokenAddress: 'USDC',

  // Amount in wei (1 ETH = 1e18 wei)
  // 1_000_000_000_000 wei = 0.000001 ETH
  fromAmount: '1000000000000',

  fromAddress,
}

  const response = await portal.trading.lifi.getRoutes(request)
  const routes = response.data?.rawResponse?.routes ?? []

  const route =
    routes.find(r => r.tags?.includes('RECOMMENDED')) ?? routes[0]

  if (!route) return

  await processRouteSteps(portal, route.steps, request.fromChainId)
}

Getting Route Step Details

import { LifiStep, LifiStepTransactionRequest } from '@portal-hq/trading'

async function getRouteStep(
  portal: Portal,
  step: LifiStep
): Promise<LifiStep | null> {
  const response = await portal.trading.lifi.getRouteStep(
    step as LifiStepTransactionRequest
  )

  return response.data?.rawResponse ?? null
}

Executing Transactions

import { ETHTransactionParam } from '@portal-hq/provider'
import { LifiTransactionRequest } from '@portal-hq/trading'

async function executeTransaction(
  portal: Portal,
  transactionRequest: LifiTransactionRequest,
  chainId: string
) {
  const ethTx: ETHTransactionParam = {
    from: transactionRequest.from,
    to: transactionRequest.to,
    value: transactionRequest.value ?? '0x0',
    data: transactionRequest.data,
  }

  const response = await portal.request(
    'eth_sendTransaction',
    [ethTx],
    chainId
  )

  console.log('Tx hash:', response.result)
}

Note LifiTransactionRequest may include gasLimit and gasPrice. You can omit these fields to let Portal estimate gas automatically, or include them if you prefer to use Li.Fi’s suggested values.

Processing Multi-Step Routes

async function processRouteSteps(
  portal: Portal,
  steps: LifiStep[],
  chainId: string
) {
  for (const step of steps) {
    const stepWithTx = await getRouteStep(portal, step)
    if (!stepWithTx?.transactionRequest) {
      throw new Error('Missing transactionRequest')
    }

    await executeTransaction(
      portal,
      stepWithTx.transactionRequest,
      chainId
    )
  }
}

Tracking Transaction Status

import { LifiStatusRequest } from '@portal-hq/trading'

async function getStatus(
  portal: Portal,
  txHash: string,
  fromChain: string
) {
  const request: LifiStatusRequest = {
    txHash,
    fromChain,
  }

  const response = await portal.trading.lifi.getStatus(request)
  const status = response.data?.rawResponse

  console.log('Status:', status?.status)
}

Polling Until Completion

async function pollUntilDone(
  portal: Portal,
  txHash: string,
  fromChain: string
) {
  while (true) {
    const response = await portal.trading.lifi.getStatus({
      txHash,
      fromChain,
    })

    const status = response.data?.rawResponse?.status
    if (status === 'DONE') return true
    if (status === 'FAILED') return false

    await new Promise(r => setTimeout(r, 2000))
  }
}

Supported Networks

Portal’s Li.Fi integration supports the following mainnet networks:
  • Monad (eip155:143)
  • Ethereum (eip155:1)
  • Optimism (eip155:10)
  • BSC (eip155:56)
  • Gnosis (eip155:100)
  • Unichain (eip155:130)
  • Polygon (eip155:137)
  • Sonic (eip155:146)
  • Mantle (eip155:5000)
  • Base (eip155:8453)
  • Arbitrum (eip155:42161)
  • Celo (eip155:42220)
  • Avalanche (eip155:43114)
  • Linea (eip155:59144)
  • Berachain (eip155:80094)
  • Katana (eip155:747474)
  • Solana (solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp)
  • Bitcoin (bip122:000000000019d6689c085ae165831e93-p2wpkh)
For the complete list of networks Li.Fi supports across its ecosystem, refer to the Li.Fi documentation. If you need a chain that isn’t listed above, contact Portal support.
Testnets are not supported.

Next Steps