Tenzro Testnet is live —request testnet TNZO
← Back to Tutorials

Bridge Aggregation with LI.FI

BridgeIntermediate25 min

Use LI.FI as a bridge aggregator on the Tenzro Network to find the best route across 30+ bridges and 66+ chains. LI.FI compares Stargate, Across, Hop, Celer, Connext, and many more to find the cheapest or fastest path for your cross-chain transfer. This tutorial covers chain discovery, route comparison, fee optimization, transfer execution, status tracking, and gas price queries.

What You'll Build

  • Query 66+ supported chains via LI.FI
  • Get a quick quote (single best route) or all available routes
  • Compare fees across 30+ bridges for the same transfer
  • Execute the optimal bridge transfer
  • Track transfer status until completion
  • Query gas prices across multiple chains
  • Handle multi-hop routes for exotic chain pairs

LI.FI vs Direct Adapters

Tenzro includes direct adapters for LayerZero, Chainlink CCIP, and deBridge. LI.FI adds aggregation on top — it queries 30+ bridges simultaneously and returns the best routes. Use LI.FI when you want automatic bridge selection, and direct adapters when you need fine-grained control over a specific bridge protocol.

Prerequisites

[dependencies]
tenzro-sdk = "0.1"
tokio = { version = "1", features = ["full"] }

Step 1: Get Supported Chains

// LI.FI supports 66+ chains including:
// Ethereum, Arbitrum, Optimism, Base, Polygon, BSC, Avalanche,
// Fantom, Gnosis, zkSync, Linea, Scroll, Mantle, Blast,
// Solana, Cosmos chains, and more

// Get all supported chains
let chains = client.bridge().list_supported_chains("lifi").await?;
println!("LI.FI supports {} chains:", chains.len());
for chain in &chains[..10] {
    println!("  {} (chain_id: {})", chain.name, chain.chain_id);
}
LI.FI supports 66 chains:
  Ethereum (chain_id: 1)
  Arbitrum (chain_id: 42161)
  Optimism (chain_id: 10)
  Base (chain_id: 8453)
  Polygon (chain_id: 137)
  BSC (chain_id: 56)
  Avalanche (chain_id: 43114)
  zkSync Era (chain_id: 324)
  Linea (chain_id: 59144)
  Scroll (chain_id: 534352)

Step 2: Get a Quick Quote

A quote returns the single best route. Use this when you just want the optimal path without comparing alternatives:

// Get a quick quote (single best route)
let quote = client.bridge().get_quote(
    "ethereum",         // source chain
    "arbitrum",         // destination chain
    "USDC",             // token
    "1000000000",       // 1000 USDC
    &wallet.address,    // sender
    &wallet.address,    // recipient
    Some("lifi"),       // use LI.FI
).await?;

println!("Best Route (Quote):");
println!("  Bridge:   {}", quote.bridge_name);
println!("  Fee:      {} USD", quote.fee_usd);
println!("  Output:   {} USDC", quote.estimated_output);
println!("  Time:     ~{}s", quote.estimated_time_seconds);
println!("  Gas:      {} USD", quote.gas_cost_usd);
Best Route (Quote):
  Bridge:   Stargate V2
  Fee:      0.38 USD
  Output:   999.62 USDC
  Time:     ~60s
  Gas:      0.85 USD

Step 3: Compare All Routes

Get all available routes for a detailed comparison. LI.FI queries every supported bridge for the chain pair:

// Get all available routes (for comparison)
let routes = client.bridge().get_all_routes(
    "ethereum",
    "arbitrum",
    "USDC",
    "1000000000",
    &wallet.address,
    &wallet.address,
    Some("lifi"),
).await?;

println!("Available Routes ({} found):", routes.len());
for (i, route) in routes.iter().enumerate() {
    println!("  Route {}: {} via {}", i + 1, route.bridge_name, route.tool_name);
    println!("    Fee:    {} USD", route.fee_usd);
    println!("    Output: {} USDC", route.estimated_output);
    println!("    Time:   ~{}s", route.estimated_time_seconds);
    println!("    Steps:  {}", route.steps.len());
}
Available Routes (5 found):
  Route 1: Stargate V2 via stargate
    Fee:    0.38 USD
    Output: 999.62 USDC
    Time:   ~60s
    Steps:  1
  Route 2: Across via across
    Fee:    0.45 USD
    Output: 999.55 USDC
    Time:   ~120s
    Steps:  1
  Route 3: Hop via hop
    Fee:    0.52 USD
    Output: 999.48 USDC
    Time:   ~300s
    Steps:  1
  Route 4: Celer cBridge via cbridge
    Fee:    0.61 USD
    Output: 999.39 USDC
    Time:   ~180s
    Steps:  1
  Route 5: Connext via connext
    Fee:    0.73 USD
    Output: 999.27 USDC
    Time:   ~240s
    Steps:  2

Step 4: Compare Fees Across Bridges

// Compare fees across all bridges for the same transfer
let fee_comparison = routes.iter()
    .map(|r| (r.bridge_name.clone(), r.fee_usd, r.estimated_time_seconds))
    .collect::<Vec<_>>();

// Sort by fee
let mut by_fee = fee_comparison.clone();
by_fee.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
println!("\nBy Fee (cheapest first):");
for (name, fee, _time) in &by_fee {
    println!("  {}: {} USD", name, fee);
}

// Sort by time
let mut by_time = fee_comparison.clone();
by_time.sort_by_key(|r| r.2);
println!("\nBy Time (fastest first):");
for (name, _fee, time) in &by_time {
    println!("  {}: ~{}s", name, time);
}
By Fee (cheapest first):
  Stargate V2: 0.38 USD
  Across: 0.45 USD
  Hop: 0.52 USD
  Celer cBridge: 0.61 USD
  Connext: 0.73 USD

By Time (fastest first):
  Stargate V2: ~60s
  Across: ~120s
  Celer cBridge: ~180s
  Connext: ~240s
  Hop: ~300s

Step 5: Execute Bridge Transfer

// Execute the bridge transfer using the best route
let result = client.bridge().bridge_tokens(
    "ethereum",
    "arbitrum",
    "USDC",
    "1000000000",
    &wallet.address,
    Some("lifi"),  // LI.FI selects the best bridge internally
).await?;

println!("Transfer initiated:");
println!("  Tx Hash:   {}", result.transaction_hash);
println!("  Bridge:    {}", result.bridge_used);
println!("  Order ID:  {}", result.order_id);
Transfer initiated:
  Tx Hash:   0x3c8f...b2a7
  Bridge:    stargate (via LI.FI)
  Order ID:  lifi-3c8f-b2a7

Step 6: Track Status

// Track bridge transfer status
loop {
    let status = client.bridge().get_status(&result.order_id).await?;

    println!("Status: {} (substatus: {})",
        status.state, status.substatus.unwrap_or_default());

    match status.state.as_str() {
        "DONE" | "Completed" | "Fulfilled" => {
            println!("Transfer complete!");
            println!("  Source tx:      {}", status.source_tx.unwrap_or_default());
            println!("  Destination tx: {}", status.destination_tx.unwrap_or_default());
            println!("  Received:       {} USDC", status.received_amount.unwrap_or_default());
            break;
        }
        "FAILED" => {
            eprintln!("Transfer failed: {}", status.error.unwrap_or_default());
            break;
        }
        _ => {
            // PENDING, NOT_FOUND, INVALID
            tokio::time::sleep(std::time::Duration::from_secs(15)).await;
        }
    }
}
Status: PENDING (substatus: BRIDGE_NOT_STARTED)
Status: PENDING (substatus: BRIDGE_STARTED)
Status: DONE (substatus: COMPLETED)
Transfer complete!
  Source tx:      0x3c8f...b2a7
  Destination tx: 0x9d4e...7f1c
  Received:       999.62 USDC

Step 7: Gas Price Queries

Query gas prices across multiple chains to factor into bridge cost calculations:

// Query gas prices across chains
let gas_prices = client.bridge().get_gas_prices(
    &["ethereum", "arbitrum", "base", "optimism", "polygon"],
    Some("lifi"),
).await?;

println!("Gas Prices:");
for gp in &gas_prices {
    println!("  {}: {} gwei ({} USD for transfer)",
        gp.chain, gp.gas_price_gwei, gp.transfer_cost_usd);
}
Gas Prices:
  ethereum: 12.5 gwei ($3.42 for transfer)
  arbitrum: 0.1 gwei ($0.05 for transfer)
  base: 0.012 gwei ($0.003 for transfer)
  optimism: 0.004 gwei ($0.001 for transfer)
  polygon: 30.0 gwei ($0.02 for transfer)

Multi-Hop Routes

When no direct bridge exists between two chains, LI.FI finds multi-step paths automatically:

// Multi-hop route: when no direct bridge exists
// LI.FI automatically finds multi-step paths
let complex_route = client.bridge().get_all_routes(
    "polygon",          // source
    "scroll",           // destination (less common)
    "USDC",
    "500000000",
    &wallet.address,
    &wallet.address,
    Some("lifi"),
).await?;

for route in &complex_route {
    println!("Route: {} ({} steps)", route.bridge_name, route.steps.len());
    for (i, step) in route.steps.iter().enumerate() {
        println!("  Step {}: {} -> {} via {}",
            i + 1, step.from_chain, step.to_chain, step.tool);
    }
}

// Example output for a 2-step route:
// Route: stargate+scroll-bridge (2 steps)
//   Step 1: polygon -> ethereum via stargate
//   Step 2: ethereum -> scroll via scroll-bridge

TypeScript Example

import { TenzroClient } from "@tenzro/sdk";

const client = new TenzroClient({ network: "testnet" });
const wallet = await client.wallet.createWallet();

// Get all routes via LI.FI
const routes = await client.bridge.getAllRoutes({
  sourceChain: "ethereum",
  destinationChain: "base",
  token: "USDC",
  amount: "500000000",
  sender: wallet.address,
  recipient: wallet.address,
  adapter: "lifi",
});

console.log(`Found ${routes.length} routes:`);
for (const route of routes) {
  console.log(`  ${route.bridgeName}: ${route.feeUsd} USD, ~${route.estimatedTimeSeconds}s`);
}

// Execute the cheapest route
const result = await client.bridge.bridgeTokens({
  sourceChain: "ethereum",
  destinationChain: "base",
  token: "USDC",
  amount: "500000000",
  recipient: wallet.address,
  adapter: "lifi",
});

console.log(`Transfer: ${result.transactionHash}`);

// Track status
let status;
do {
  status = await client.bridge.getStatus(result.orderId);
  console.log(`Status: ${status.state}`);
  if (status.state !== "DONE" && status.state !== "FAILED") {
    await new Promise(r => setTimeout(r, 15000));
  }
} while (status.state !== "DONE" && status.state !== "FAILED");

What You Learned

Next Steps