Documentation

LI.FI Plugin Tutorial

Step-by-step guide to test and simulate cross-chain swaps using the LI.FI plugin with BuildBear Sandboxes.

What is LI.FI

LI.FI is a bridge and DEX aggregation protocol that offers the most efficient cross-chain swaps by routing through the best liquidity pools and bridges.


Introduction

This guide provides step-by-step instructions for integrating the LI.FI plugin with BuildBear Sandboxes. The plugin enables developers to test and simulate cross-chain swaps using multiple bridges and DEXs for optimal routing. This integration facilitates efficient liquidity aggregation, seamless asset exchanges, and enhanced cross-chain development in a controlled sandbox environment.


Features

  • Cross-Chain Testing: Simulate multi-chain interactions without real assets.
  • Seamless Integration: Works effortlessly within BuildBear’s sandbox.
  • Support for LI.FI SDK: Simulate bridging and swapping transactions.
  • Comprehensive Testing Logs: Access transaction details and validation reports.
  • Sandboxed Liquidity Access: Controlled liquidity aggregation testing.

What You'll Learn

  • How to install and configure the LI.FI Plugin in your BuildBear Sandbox
  • How to retrieve quotes for swapping for DAI to USDC on Polygon
  • How to extract and populate transactions using quote results
  • How to execute a transaction to Swap DAI to USDC, using LiFi DEX Aggregator

Step 1: Installing the Plugin

Install the LI.FI Plugin

  1. Log in to your BuildBear account.
  2. Navigate to the Plugin Marketplace in both the source and destination sandboxes.
  3. Search for LI.FI Plugin and click Install.
plugin-installation

Configure the Sandboxes

  1. Create two new sandboxes or use existing ones.
  2. Open the LI.FI Plugin.
  3. Link the sandboxes to configure cross-chain interaction.

Step 2: Defining and Submitting Cross-Chain Intents

Prerequisites

  • Install dependencies listed in package.json
  • Add your private key to your .env file

Define API URL and Endpoints

// BuildBear API Configuration
const RPC_URL = "https://rpc.buildbear.io/{from-sandbox-id}";

Replace sandbox-id with actual sandbox id of source chain sandbox

const API_URL =
  "https://api.buildbear.io/{from-sandbox-id}/plugin/lifi/{to-sandbox-id}";

Replace {from-sandbox-id} and {to-sandbox-id} with your actual BuildBear sandbox IDs.


1️⃣ Retrieve Swapping Quotes

The /quote endpoint takes these parameters:

  • fromChain: Source chain ID
  • toChain: Destination chain ID
  • fromToken: ERC20 token on source chain
  • toToken: ERC20 token on destination chain
  • fromAmount: Amount of tokens to bridge/swap
  • fromAddress: Sender's address
// Get a quote for your desired transfer
const getQuote = async (
  fromChain: string | number,
  toChain: string | number,
  fromToken: string,
  toToken: string,
  fromAmount: string,
  fromAddress: string
) => {
  try {
    const result = await axios.get(`${API_URL}/quote`, {
      params: {
        fromChain,
        toChain,
        fromToken,
        toToken,
        fromAmount,
        fromAddress,
      },
    });
    console.log("=============LIFI QUOTE===============");
    console.log(result.data);
    console.log("====================================");
    return result.data;
  } catch (error: any) {
    console.error(
      "LI.FI API Error Details:",
      error.response?.data || error.message
    );
    throw error;
  }
};

The result of the API call will contain the information about the tokens to bridge/swap, networks involved, gas estimates, transaction request object, etc. In our case the result will include information about the token swap.

For example:

estimates:

estimate: {
    tool: 'sushiswap',
    approvalAddress: '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE',
    toAmountMin: '994994',
    toAmount: '999994',
    fromAmount: '1000000000000000000',
    feeCosts: [],
    gasCosts: [ [Object] ],
    executionDuration: 30,
    fromAmountUSD: '1.0000',
    toAmountUSD: '0.9999'
},

transactionRequest Object:

transactionRequest: {
    value: '0x0',
    to: '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE',
    data: '0x4666fc80a1e8a494d935dd33d76357c13a27826546f60f9933288faa50d660a46c338ea300000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000001308ca04d6e6243f65d73101b5a23bb6fb58723300000000000000000000000000000000000000000000000000000000000f2eb2000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000086c6966692d617069000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a3078303030303030303030303030303030303030303030303030303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000085cd07ea01423b1e937929b44e4ad8c40bbb5e7100000000000000000000000085cd07ea01423b1e937929b44e4ad8c40bbb5e710000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a0630000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000184dd9c5f960000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a0630000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000000000f423a00000000000000000000000000000000000000000000000000000000000f2eb20000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043028f3cf7ad23cd3cadbd9735aff958023239c6a06301ffff01f369277650ad6654f25412ea8bfbd5942733babc0085cd07ea01423b1e937929b44e4ad8c40bbb5e7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    chainId: 137,
    gasPrice: '0xcc829accd',
    gasLimit: '0x68c8a',
    from: '0x1308cA04d6E6243F65D73101B5a23BB6Fb587233'
}

2️⃣ Configure Helper Functions

We need a helper function to get the approval call data, as well as a helper function to send transaction using the transaction request object received as a result of LI.FI quote

 
// Encode ERC20 Approval Transaction
const encodeApprovalCallData = (spender: string, amount: string) => {
  const iface = new Interface([
    "function approve(address spender, uint256 amount)",
  ]);
  return iface.encodeFunctionData("approve", [spender, amount]);
};
 
// Send and confirm transactions
const sendTransaction = async (
  provider: ethers.JsonRpcProvider,
  signer: ethers.Wallet,
  transactionRequest: { to: string; data: string; gasLimit?: `0x${string}` },
  isApproval = false
) => {
  try {
    signer.connect(provider);
 
    const tx = await signer.sendTransaction(
      transactionRequest.gasLimit
        ? {
            to: transactionRequest.to,
            data: transactionRequest.data,
            gasLimit: parseInt(transactionRequest.gasLimit, 16).toString(),
          }
        : { to: transactionRequest.to, data: transactionRequest.data }
    );
    await tx.wait();
 
    console.log(
      `${
        isApproval ? "Approval" : "LiFi Aggregator/Bridging"
      } Transaction Sent! Hash: ${tx.hash}`
    );
    console.log("Waiting for confirmation...");
 
    const receipt = await provider.getTransactionReceipt(tx.hash);
    console.log("Transaction Confirmed!");
    return receipt;
  } catch (error) {
    console.error("Transaction Error:", error);
    throw error;
  }
};

3️⃣ Execute Swapping Transaction

We will need to define the parameters to receive quotes from BuildBear LI.FI endpoint, as mentioned in Step 2. Once we have the quote, we approve the spending amount to the smart contract address in transaction request that will execute the swap transaction. After the approval, we use the transaction request object to send the actual transaction to the same smart contract address to initiate a LI.FI transfer

 
// Main Execution Flow
const run = async () => {
  const provider = new ethers.JsonRpcProvider(RPC_URL);
  const signer = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
 
  // ----------- WETH Bridge Polygon to Ethereum -----------
  // # Note: Uncomment the below params to fetch and execute bridging tx
  // const fromChain = 137;
  // const fromToken = "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619";
  // const toChain = 1;
  // const toToken = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
  // const fromAmount = parseUnits("1", 18).toString();
  // const fromAddress = signer.address;
 
  // ----------- Lifi aggregator swap DAI to USDC on Polygon -----------
 
  const fromChain = "POL";
  const fromToken = "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063";
  const toChain = "POL";
  const toToken = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359";
  const fromAmount = parseUnits("1", 18).toString();
  const fromAddress = signer.address;
 
  const quote = await getQuote(
    fromChain,
    toChain,
    fromToken,
    toToken,
    fromAmount,
    fromAddress
  );
 
  const approvalTxRequest = {
    to: quote.action.fromToken.address,
    data: encodeApprovalCallData(
      quote.transactionRequest.to,
      maxUint256.toString()
    ),
  };
 
  // Execute Approval Transaction
  await sendTransaction(provider, signer, approvalTxRequest, true);
  // Execute the Transaction
  await sendTransaction(provider, signer, quote.transactionRequest, false);
};
 
run().then(() => console.log("✅ DONE!"));

Output Example

The output similar to the following can be observed if the plugin is setup correctly.

=============LIFI QUOTE===============
{
  type: 'lifi',
  id: '8d1171b7-ffb6-49a2-a716-51cda8dfc29b:0',
  tool: 'sushiswap',
  toolDetails: {
    key: 'sushiswap',
    name: 'SushiSwap Aggregator',
    logoURI: 'https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/sushi.png'
  },
  action: {
    fromToken: {
      address: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
      chainId: 137,
      symbol: 'DAI',
      decimals: 18,
      name: '(PoS) DAI Stablecoin',
      coinKey: 'DAI',
      logoURI: 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x6B175474E89094C44Da98b954EedeAC495271d0F/logo.png',
      priceUSD: '1'
    },
    fromAmount: '1000000000000000000',
    toToken: {
      address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
      chainId: 137,
      symbol: 'USDC',
      decimals: 6,
      name: 'USD Coin',
      coinKey: 'USDC',
      logoURI: 'https://static.debank.com/image/coin/logo_url/usdc/e87790bfe0b3f2ea855dc29069b38818.png',
      priceUSD: '0.9999000099990001'
    },
    fromChainId: 137,
    toChainId: 137,
    slippage: 0.005,
    fromAddress: '0x1308cA04d6E6243F65D73101B5a23BB6Fb587233',
    toAddress: '0x1308cA04d6E6243F65D73101B5a23BB6Fb587233'
  },
  estimate: {
    tool: 'sushiswap',
    approvalAddress: '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE',
    toAmountMin: '994994',
    toAmount: '999994',
    fromAmount: '1000000000000000000',
    feeCosts: [],
    gasCosts: [ [Object] ],
    executionDuration: 30,
    fromAmountUSD: '1.0000',
    toAmountUSD: '0.9999'
  },
  includedSteps: [
    {
      id: '0b124c28-3a1c-46f9-9aa7-deb4e04efea0',
      type: 'swap',
      action: [Object],
      estimate: [Object],
      tool: 'sushiswap',
      toolDetails: [Object]
    }
  ],
  integrator: 'lifi-api',
  transactionRequest: {
    value: '0x0',
    to: '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE',
    data: '0x4666fc80a1e8a494d935dd33d76357c13a27826546f60f9933288faa50d660a46c338ea300000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000001308ca04d6e6243f65d73101b5a23bb6fb58723300000000000000000000000000000000000000000000000000000000000f2eb2000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000086c6966692d617069000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a3078303030303030303030303030303030303030303030303030303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000085cd07ea01423b1e937929b44e4ad8c40bbb5e7100000000000000000000000085cd07ea01423b1e937929b44e4ad8c40bbb5e710000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a0630000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000184dd9c5f960000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a0630000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000000000f423a00000000000000000000000000000000000000000000000000000000000f2eb20000000000000000000000001231deb6f5749ef6ce6943a275a1d3e7486f4eae000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043028f3cf7ad23cd3cadbd9735aff958023239c6a06301ffff01f369277650ad6654f25412ea8bfbd5942733babc0085cd07ea01423b1e937929b44e4ad8c40bbb5e7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    chainId: 137,
    gasPrice: '0xcc829accd',
    gasLimit: '0x68c8a',
    from: '0x1308cA04d6E6243F65D73101B5a23BB6Fb587233'
  }
}
====================================
Approval Transaction Sent! Hash: 0x5a1650475682ec03498b5c8ac4b0c04f3941f5eb92f8310c12444733cc4dc98b
Waiting for confirmation...
Transaction Confirmed!
LiFi Aggregator/Bridging Transaction Sent! Hash: 0x7dc6cfb80b2e83970f925dbb118c27c1f1528cdbe2e96c082b8bbede4f935d70
Waiting for confirmation...
Transaction Confirmed!
 DONE!

View the transaction on the BuildBear Explorer or the BlockScout Explorer

Output Screenshot


(Optional) Debug with Sentio

Clicking on "View on Sentio" opens the debugger for:

Fund Flow

Fund Flow

Call Trace

Call Trace

Gas Profiler

Gas Profiler

Debugger View

Debugger

Events Tab

Events

State Tab

State


Conclusion

This guide walked you through integrating the LI.FI Plugin with BuildBear Sandboxes. You learned how to fetch a swap quote, use it to populate and send a swapping transaction. For the full tutorial and source code, check out the GitHub repository.