> ## 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.

# Widget Light Wallet Management

> Ecosystem handlers and wallet integration for @lifi/widget-light

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:

```tsx theme={"system"}
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()`

```tsx theme={"system"}
import { useEthereumIframeHandler } from '@lifi/widget-light/ethereum'
```

The EVM handler reads wallet state from your wagmi context automatically. No parameters are required.

```tsx theme={"system"}
const ethHandler = useEthereumIframeHandler()
```

| Detail                | Value                                                                                   |
| --------------------- | --------------------------------------------------------------------------------------- |
| **Chain type**        | `EVM`                                                                                   |
| **Reads from**        | wagmi context (`useConnection`, `useWalletClient`, `usePublicClient`, `useSwitchChain`) |
| **Peer dependencies** | `wagmi`, `viem`, `@wagmi/core`                                                          |
| **Parameters**        | None                                                                                    |

**Supported RPC methods:**

| Method                       | Description                                            |
| ---------------------------- | ------------------------------------------------------ |
| `eth_accounts`               | Returns connected accounts                             |
| `eth_requestAccounts`        | Requests account access                                |
| `eth_chainId`                | Returns current chain ID (hex)                         |
| `net_version`                | Returns current network version                        |
| `eth_sendTransaction`        | Sends a transaction (supports EIP-1559 and legacy gas) |
| `personal_sign`              | Signs an arbitrary message                             |
| `eth_sign`                   | Signs data                                             |
| `eth_signTypedData_v4`       | Signs EIP-712 typed data                               |
| `wallet_switchEthereumChain` | Switches to a different chain                          |
| `wallet_addEthereumChain`    | Adds a new chain to the wallet                         |
| `wallet_sendCalls`           | Sends batched calls (EIP-5792)                         |
| `wallet_getCallsStatus`      | Gets status of batched calls (EIP-5792)                |
| `wallet_showCallsStatus`     | Shows batched calls status UI (EIP-5792)               |
| `wallet_getCapabilities`     | Queries 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)`

```tsx theme={"system"}
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.

```tsx theme={"system"}
const solHandler = useSolanaIframeHandler({
  address: solanaAddress,     // string | null
  connected: solanaConnected, // boolean
  wallet: solanaWallet,       // Wallet from @wallet-standard/base | null
})
```

| Detail                | Value                   |
| --------------------- | ----------------------- |
| **Chain type**        | `SVM`                   |
| **Peer dependencies** | `@wallet-standard/base` |

**Parameters:**

| Parameter   | Type             | Description                       |
| ----------- | ---------------- | --------------------------------- |
| `address`   | `string \| null` | Connected wallet address          |
| `connected` | `boolean`        | Whether a wallet is connected     |
| `wallet`    | `Wallet \| null` | Wallet-standard `Wallet` instance |

**Supported RPC methods:**

| Method                   | Description                             |
| ------------------------ | --------------------------------------- |
| `getAccount`             | Returns current account address         |
| `signTransaction`        | Signs a serialized transaction (base64) |
| `signMessage`            | Signs an arbitrary message (base64)     |
| `signAndSendTransaction` | Signs and sends a transaction (base64)  |

**Wallet events emitted:** `accountsChanged`, `connect`, `disconnect`

### Bitcoin -- `useBitcoinIframeHandler()`

```tsx theme={"system"}
import { useBitcoinIframeHandler } from '@lifi/widget-light/bitcoin'
```

The Bitcoin handler reads wallet state from the `@bigmi/react` context automatically. No parameters are required.

```tsx theme={"system"}
const btcHandler = useBitcoinIframeHandler()
```

| Detail                | Value                                              |
| --------------------- | -------------------------------------------------- |
| **Chain type**        | `UTXO`                                             |
| **Reads from**        | `@bigmi/react` context (`useAccount`, `useConfig`) |
| **Peer dependencies** | `@bigmi/client`, `@bigmi/react`                    |
| **Parameters**        | None                                               |

**Supported RPC methods:**

| Method        | Description                                           |
| ------------- | ----------------------------------------------------- |
| `getAccount`  | Returns current account address and public key        |
| Other methods | Forwarded to the wallet client via `client.request()` |

**Wallet events emitted:** `accountsChanged`, `connect`, `disconnect`

### Sui -- `useSuiIframeHandler()`

```tsx theme={"system"}
import { useSuiIframeHandler } from '@lifi/widget-light/sui'
```

The Sui handler reads wallet state from `@mysten/dapp-kit-react` hooks automatically. No parameters are required.

```tsx theme={"system"}
const suiHandler = useSuiIframeHandler()
```

| Detail                | Value                                                                                    |
| --------------------- | ---------------------------------------------------------------------------------------- |
| **Chain type**        | `MVM`                                                                                    |
| **Reads from**        | `@mysten/dapp-kit-react` hooks (`useCurrentWallet`, `useDAppKit`, `useWalletConnection`) |
| **Peer dependencies** | `@mysten/dapp-kit-react`                                                                 |
| **Parameters**        | None                                                                                     |

**Supported RPC methods:**

| Method                      | Description                            |
| --------------------------- | -------------------------------------- |
| `getAccount`                | Returns current account address        |
| `signTransaction`           | Signs a transaction block (base64)     |
| `signPersonalMessage`       | Signs an arbitrary message (base64)    |
| `signAndExecuteTransaction` | Signs and executes a transaction block |

**Wallet events emitted:** `accountsChanged`, `connect`, `disconnect`

### Tron -- `useTronIframeHandler(params)`

```tsx theme={"system"}
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.

```tsx theme={"system"}
const tronHandler = useTronIframeHandler({
  address: tronAddress,     // string | null
  connected: tronConnected, // boolean
  adapter: tronAdapter,     // TronAdapter | null
})
```

| Detail                | Value                                     |
| --------------------- | ----------------------------------------- |
| **Chain type**        | `TVM`                                     |
| **Peer dependencies** | None (adapter state is passed explicitly) |

**Parameters:**

| Parameter   | Type                  | Description                                                     |
| ----------- | --------------------- | --------------------------------------------------------------- |
| `address`   | `string \| null`      | Connected wallet address                                        |
| `connected` | `boolean`             | Whether a wallet is connected                                   |
| `adapter`   | `TronAdapter \| null` | Wallet adapter with `signTransaction` and `signMessage` methods |

**Supported RPC methods:**

| Method            | Description                               |
| ----------------- | ----------------------------------------- |
| `getAccount`      | Returns current account address           |
| `signTransaction` | Signs a TronWeb transaction object (JSON) |
| `signMessage`     | Signs 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:

```tsx theme={"system"}
// 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`:

```tsx theme={"system"}
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.

```tsx theme={"system"}
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:

| Field       | Type                           | Description                                                   |
| ----------- | ------------------------------ | ------------------------------------------------------------- |
| `chainId`   | `number \| undefined`          | The chain ID the widget wants to connect to                   |
| `chainType` | `WidgetChainType \| undefined` | The chain type (`'EVM'`, `'SVM'`, `'UTXO'`, `'MVM'`, `'TVM'`) |

<Note>
  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.
</Note>
