Skip to main content
Portal’s Android 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

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 entire bridge or swap in one call. pollStatus exposes the same Li.Fi status poller tradeAsset uses internally, for manual flows where you already have a transaction hash. If you only need to move tokens, use tradeAsset. Reach for the low-level methods when you need to inspect routes before committing, run your own signing, or drive a custom UI. Both return Result<T> like every other method on this page — handle them with onSuccess / onFailure, not try/catch.

tradeAsset

Runs the end-to-end Li.Fi flow:
  1. Discover routes (getRoutes)
  2. Select a route (routeIndex, default 0)
  3. Build each step (getRouteStep)
  4. Sign and broadcast that step’s transaction
  5. Wait for on-chain confirmation of that step
  6. Poll Li.Fi status until the step reaches a terminal state
  7. Continue to the next step
Steps execute sequentially, never in parallel. Signing and confirmation for each step happen on that step’s own chain, which the SDK resolves from the step itself — so a multi-chain route signs on each chain in turn without you managing it. Confirmation is strict. Every step must confirm on-chain before the next begins. waitForConfirmation must return true; anything else aborts the whole trade and yields a failed Result. There is no optimistic fallback.

Signature

Essential parameters
fromAddress is nullable in the type system but the SDK does not fill it in for you — it is forwarded to Li.Fi exactly as given. Omitting it means routes are quoted without a sender, while the transaction is still signed by your Portal wallet, so the quote may not match what actually executes. Pass it explicitly, resolving it from the chain you are trading on with portal.getAddress(fromChain).
Configuring the signer and confirmation Unlike the React Native and Web SDKs, tradeAsset takes no second options argument. The signing and confirmation hooks are injected once, when the Lifi instance is constructed:
Portal wires both automatically — signAndSendTransaction via eth_sendTransaction, and waitForConfirmation via an internal receipt poller that retries up to 30 times — so portal.trading.lifi.tradeAsset(params) works with no setup. The two callbacks are:
waitForConfirmation must return true for a confirmed transaction. Both failure modes abort the trade, but they surface differently:
  • Returning false fails the Result with LifiTradeAssetException.TransactionConfirmationFailed(txHash).
  • Throwing propagates through tradeAsset’s catch-all and fails the Result with the original exception, not TransactionConfirmationFailed.
That distinction matters for the closure Portal wires in: its receipt poller returns false for a reverted or never-confirmed transaction, but it throws when the RPC calls themselves keep failing — a bad chain ID, an unreachable RPC, an auth error. An onFailure that only matches TransactionConfirmationFailed will silently miss that whole class of failure, so always keep an else branch that surfaces error as-is. Overriding the defaults. portal.trading is built lazily by Portal with its own closures already supplied, so the instance at portal.trading.lifi cannot be reconfigured after the fact. To use different behavior, build your own instance and call tradeAsset on that instead. Trading accepts the two callbacks and constructs its Lifi internally — it does not take a Lifi:
Construct Lifi directly when you also need to change the per-step polling, which Trading does not expose:
Because Trading does not pass stepPollOptions through, the per-step Li.Fi polling inside tradeAsset always uses the Lifi constructor default — a 10-second initial delay, 10-second interval, 10-minute timeout. That default differs from the standalone pollStatus default, which has no initial delay.
Lifi, LifiTradingApi, and their methods are open as of 9.1.0, so you can subclass them to stub Li.Fi in tests.
Return value

Example (progress reporting)

Example (minimal)

Errors

Failures arrive inside the returned Result as a LifiTradeAssetException: MissingSigner, MissingConfirmation, NoRoutesFound, RouteIndexOutOfBounds, RouteHasNoSteps, MissingTransactionRequest, and InvalidTransactionRequest are object singletons — match them with is. The rest are classes carrying detail.
TransactionConfirmationFailed is not proof the transaction failed on-chain. Portal’s receipt poller returns false in two different situations, and Android maps both onto this one case:
  • The receipt came back reverted (status: 0x0) — the transaction genuinely failed.
  • The retries ran out before any receipt appeared — the transaction may still be pending and could yet confirm.
Treat it as “not confirmed”, not “failed” — re-check the hash on-chain rather than reporting a definitive failure. Note that txHash is a constructor parameter, not an exposed property: it is interpolated into error.message, so capture the hash from the SUBMITTED progress event if you need it programmatically.iOS keeps these two outcomes apart as transactionConfirmationFailed and transactionConfirmationTimedOut, so cross-platform code cannot assume both SDKs report an unconfirmed transaction the same way.
Cancelling the enclosing coroutine throws CancellationException rather than returning a failed Result, and no FAILED progress event is emitted. This preserves structured concurrency, but it means a UI that only dismisses its progress state on FAILED or COMPLETE will hang on cancellation — handle CancellationException separately.

Progress lifecycle

onProgress receives a LifiTradeAssetProgressStatus and a LifiTradeAssetProgressData. Every field on the data class is nullable; which ones are populated depends on the stage: txHash is null until SUBMITTED. errorMessage is only ever set on FAILED.

pollStatus

Polls Li.Fi for the status of a transfer until it reaches a terminal state. Use it when you have submitted a transaction yourself and want the same polling behavior tradeAsset uses internally.
Both onUpdate and options are defaulted, so pollStatus(request) alone is valid. Returning false from onUpdate stops polling early and succeeds with the last status received — it is not an error. Returning true continues.

pollStatus options


Low-Level Methods

The rest of this guide covers the individual Li.Fi methods. Use them when you need control over route selection, signing, or status tracking that tradeAsset does not expose.

Getting a Quote

Use the getQuote method to get a quote for bridging or swapping tokens across chains.
The response includes a transactionRequest object with the transaction details you’ll need to sign and submit.

Finding Routes

Use the getRoutes method to discover available routes for your cross-chain transfer.
The response includes an array of routes with estimates, fees, and gas costs. Routes may be tagged as RECOMMENDED, CHEAPEST, or FASTEST.

Getting Route Step Details

Use the getRouteStep method to get detailed transaction information for a specific route step, including an unsigned transaction that you can then sign and submit to an RPC provider (the transactionRequest field).
The response includes a transactionRequest object with the unsigned transaction that you can sign and submit.

Executing Swaps and Bridges

After getting a quote or route step details, extract the transaction details from the transactionRequest object and sign the transaction. Extract the from, to, value, and data fields to sign and submit the transaction.

Approving ERC-20 Tokens

If your fromToken is an ERC-20, the Li.Fi router cannot move it on your behalf until you grant an on-chain allowance. Skip this step when the fromToken is the chain’s native asset (its address is 0x0000000000000000000000000000000000000000). Build the approval transaction with the portal.delegations.approve(request) method, then sign each transaction it returns with the same eth_sendTransaction flow used to sign the swap. Call this helper after obtaining a quote and before calling executeTransaction:
This step only applies when the fromToken is an ERC-20. Native-asset swaps (ETH, MATIC, etc.) skip it. For more on the delegations API, see the Manage Token Delegations guide.

Signing and Submitting Transactions

The transactionRequest from Li.Fi may include gasPrice and gasLimit fields. You can remove these if you want Portal to estimate the gas for you, or include them if you want to use Li.Fi’s estimates.

Processing Multiple Route Steps

For routes with multiple steps, process them sequentially:

Waiting for Transaction Confirmation

Tracking Transaction Status

Use the getStatus method to track the status of your cross-chain transfer.

Polling for Cross-Chain Completion

For cross-chain transfers, poll the status endpoint until the transfer completes:

Example Flow

Here’s a complete example of executing a cross-chain bridge:

Best Practices

  1. Compare quotes/routes before signing and submitting the transaction(s) to find the best option for your use case
  2. Process steps sequentially for multi-step routes, ensuring each step completes before starting the next
  3. Handle network errors gracefully and provide user feedback
  4. Monitor transaction status for cross-chain transfers, as they may take longer than single-chain transactions
  5. Validate user balances before initiating swaps or bridges

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