Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.li.fi/llms.txt

Use this file to discover all available pages before exploring further.

In Widget Light, the host application owns all wallet connections. The widget running inside the iframe never touches browser extensions or private keys directly. Instead, ecosystem handlers bridge RPC requests from the iframe to your wallet provider.

How Wallet Bridging Works

When the widget inside the iframe needs to perform a wallet operation (send a transaction, sign a message, switch chains), it sends an RPC_REQUEST message via postMessage. The host-side handler processes the request using your wallet provider and sends the result back as an RPC_RESPONSE.
Widget (iframe)                         Host (your app)
     |                                       |
     |-- RPC_REQUEST (eth_sendTransaction) ->|
     |                                       |-- wagmi sends tx
     |                                       |<- tx hash
     |<- RPC_RESPONSE (tx hash) ------------|
Wallet state changes (account switches, chain changes, connect/disconnect) are also pushed from the host to the iframe automatically via EVENT messages.

IframeEcosystemHandler Interface

Every ecosystem handler implements the IframeEcosystemHandler interface:
interface IframeEcosystemHandler {
  /** Chain type identifier: 'EVM' | 'SVM' | 'UTXO' | 'MVM' | 'TVM' */
  chainType: WidgetLightChainType

  /** Returns initial wallet state sent with the INIT handshake */
  getInitState(): EcosystemInitState | null

  /** Handles an RPC request forwarded from the iframe */
  handleRequest(id: string, method: string, params?: unknown): Promise<unknown>

  /** Subscribes to wallet state changes; returns an unsubscribe function */
  subscribe(emit: (event: string, data: unknown) => void): () => void
}

Ecosystem Handlers

EVM — useEthereumIframeHandler()

import { useEthereumIframeHandler } from '@lifi/widget-light/ethereum'
The EVM handler reads wallet state from your wagmi context automatically. No parameters are required.
const ethHandler = useEthereumIframeHandler()
DetailValue
Chain typeEVM
Reads fromwagmi context (useConnection, useWalletClient, usePublicClient, useSwitchChain)
Peer dependencieswagmi, viem, @wagmi/core
ParametersNone
Supported RPC methods:
MethodDescription
eth_accountsReturns connected accounts
eth_requestAccountsRequests account access
eth_chainIdReturns current chain ID (hex)
net_versionReturns current network version
eth_sendTransactionSends a transaction (supports EIP-1559 and legacy gas)
personal_signSigns an arbitrary message
eth_signSigns data
eth_signTypedData_v4Signs EIP-712 typed data
wallet_switchEthereumChainSwitches to a different chain
wallet_addEthereumChainAdds a new chain to the wallet
wallet_sendCallsSends batched calls (EIP-5792)
wallet_getCallsStatusGets status of batched calls (EIP-5792)
wallet_showCallsStatusShows batched calls status UI (EIP-5792)
wallet_getCapabilitiesQueries wallet capabilities (EIP-5792)
Any unrecognized methods are forwarded to the public client (e.g. eth_getBalance, eth_call). Wallet events emitted: accountsChanged, chainChanged, connect

Solana — useSolanaIframeHandler(params)

import { useSolanaIframeHandler } from '@lifi/widget-light/solana'
The Solana handler is library-agnostic. You pass wallet state explicitly, so it works with any Solana wallet library that provides a wallet-standard Wallet instance.
const solHandler = useSolanaIframeHandler({
  address: solanaAddress,     // string | null
  connected: solanaConnected, // boolean
  wallet: solanaWallet,       // Wallet from @wallet-standard/base | null
})
DetailValue
Chain typeSVM
Peer dependencies@wallet-standard/base
Parameters:
ParameterTypeDescription
addressstring | nullConnected wallet address
connectedbooleanWhether a wallet is connected
walletWallet | nullWallet-standard Wallet instance
Supported RPC methods:
MethodDescription
getAccountReturns current account address
signTransactionSigns a serialized transaction (base64)
signMessageSigns an arbitrary message (base64)
signAndSendTransactionSigns and sends a transaction (base64)
Wallet events emitted: accountsChanged, connect, disconnect

Bitcoin — useBitcoinIframeHandler()

import { useBitcoinIframeHandler } from '@lifi/widget-light/bitcoin'
The Bitcoin handler reads wallet state from the @bigmi/react context automatically. No parameters are required.
const btcHandler = useBitcoinIframeHandler()
DetailValue
Chain typeUTXO
Reads from@bigmi/react context (useAccount, useConfig)
Peer dependencies@bigmi/client, @bigmi/react
ParametersNone
Supported RPC methods:
MethodDescription
getAccountReturns current account address and public key
Other methodsForwarded to the wallet client via client.request()
Wallet events emitted: accountsChanged, connect, disconnect

Sui — useSuiIframeHandler()

import { useSuiIframeHandler } from '@lifi/widget-light/sui'
The Sui handler reads wallet state from @mysten/dapp-kit-react hooks automatically. No parameters are required.
const suiHandler = useSuiIframeHandler()
DetailValue
Chain typeMVM
Reads from@mysten/dapp-kit-react hooks (useCurrentWallet, useDAppKit, useWalletConnection)
Peer dependencies@mysten/dapp-kit-react
ParametersNone
Supported RPC methods:
MethodDescription
getAccountReturns current account address
signTransactionSigns a transaction block (base64)
signPersonalMessageSigns an arbitrary message (base64)
signAndExecuteTransactionSigns and executes a transaction block
Wallet events emitted: accountsChanged, connect, disconnect

Tron — useTronIframeHandler(params)

import { useTronIframeHandler } from '@lifi/widget-light/tron'
The Tron handler is library-agnostic. You pass wallet state explicitly, so it works with any Tron wallet library that provides a compatible adapter.
const tronHandler = useTronIframeHandler({
  address: tronAddress,     // string | null
  connected: tronConnected, // boolean
  adapter: tronAdapter,     // TronAdapter | null
})
DetailValue
Chain typeTVM
Peer dependenciesNone (adapter state is passed explicitly)
Parameters:
ParameterTypeDescription
addressstring | nullConnected wallet address
connectedbooleanWhether a wallet is connected
adapterTronAdapter | nullWallet adapter with signTransaction and signMessage methods
Supported RPC methods:
MethodDescription
getAccountReturns current account address
signTransactionSigns a TronWeb transaction object (JSON)
signMessageSigns an arbitrary message string
Wallet events emitted: accountsChanged, connect, disconnect

Subpath Imports

Each ecosystem handler is exposed via a subpath import to enable tree-shaking. If you only use EVM, the Solana, Bitcoin, Sui, and Tron handlers (and their peer dependencies) are never included in your bundle:
// Only includes EVM handler code
import { useEthereumIframeHandler } from '@lifi/widget-light/ethereum'

// Only includes Solana handler code
import { useSolanaIframeHandler } from '@lifi/widget-light/solana'

// Only includes Bitcoin handler code
import { useBitcoinIframeHandler } from '@lifi/widget-light/bitcoin'

// Only includes Sui handler code
import { useSuiIframeHandler } from '@lifi/widget-light/sui'

// Only includes Tron handler code
import { useTronIframeHandler } from '@lifi/widget-light/tron'

Combining Multiple Handlers

Pass all your handlers as an array. The widget routes each RPC request to the handler matching the request’s chainType:
import { LiFiWidgetLight } from '@lifi/widget-light'
import { useEthereumIframeHandler } from '@lifi/widget-light/ethereum'
import { useSolanaIframeHandler } from '@lifi/widget-light/solana'
import { useMemo } from 'react'

function App() {
  const ethHandler = useEthereumIframeHandler()
  const solHandler = useSolanaIframeHandler({
    address: solanaAddress,
    connected: solanaConnected,
    wallet: solanaWallet,
  })

  const handlers = useMemo(
    () => [ethHandler, solHandler],
    [ethHandler, solHandler]
  )

  return (
    <LiFiWidgetLight
      config={{ integrator: 'my-app' }}
      handlers={handlers}
    />
  )
}

External Wallet Management

If your app has its own wallet connection UI (a connect button, a modal, etc.), use the onConnect prop to intercept wallet connection requests from the widget. When onConnect is provided, the widget sends a CONNECT_WALLET_REQUEST to the host instead of opening its built-in wallet menu.
import { LiFiWidgetLight } from '@lifi/widget-light'
import type { ConnectWalletArgs } from '@lifi/widget-light'
import { useCallback } from 'react'

function App() {
  const handleConnect = useCallback((args?: ConnectWalletArgs) => {
    // args.chainId - the chain the widget wants to connect to (optional)
    // args.chainType - the chain type ('EVM', 'SVM', 'UTXO', 'MVM', 'TVM') (optional)
    openYourWalletModal(args)
  }, [])

  return (
    <LiFiWidgetLight
      config={{ integrator: 'my-app' }}
      handlers={handlers}
      onConnect={handleConnect}
    />
  )
}
The ConnectWalletArgs type contains:
FieldTypeDescription
chainIdnumber | undefinedThe chain ID the widget wants to connect to
chainTypeWidgetChainType | undefinedThe chain type ('EVM', 'SVM', 'UTXO', 'MVM', 'TVM')
When onConnect is provided, the host automatically sets walletConfig.useExternalWalletManagement: true in the config sent to the iframe. You do not need to set this manually.