> ## Documentation Index
> Fetch the complete documentation index at: https://docs.socket.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Socket Widget

> A plug-and-play React widget for token swaps and cross-chain bridging.

Socket Widget is a swap and bridge widget for moving tokens across blockchains. The `@socket.tech/widget` package exposes a React component you can embed in your app.

* Live product: [bungee.exchange](https://bungee.exchange/)
* NPM package: [@socket.tech/widget](https://www.npmjs.com/package/@socket.tech/widget)

> **v1.0.0**: The widget is wallet-provider-agnostic. Your app provides a minimal wallet adapter via `config.wallet`, and the widget handles routing, reads, writes, balances, receipts, and signing internally.

## Before You Start

Socket Widget handles swap and bridge flows, while your app owns wallet connection.

* Provide wallet state and wallet connect UI.
* Mount `QueryClientProvider` above `<SocketWidget />`.
* Pass a minimal wallet adapter via `config.wallet`.
* Support EVM only, Solana only, Tron only, or any combination by providing the matching adapter methods. **You only need to pass the methods for the chains you support** — e.g. for EVM-only apps, provide `getEVMWalletClient` and `switchChain`; you do not need to pass `getSolanaSigner` or `getTronWeb`.

Minimal React Query setup:

```tsx theme={null}
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

root.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>
);
```

## Install

```bash theme={null}
pnpm install @socket.tech/widget react react-dom viem @tanstack/react-query
```

<Note>
  Peer dependencies are not installed automatically. You must already have wallet infrastructure in your app.
</Note>

Import the widget styles in your app entrypoint:

```tsx theme={null}
import "@socket.tech/widget/styles.css";
import "@socket.tech/widget/fonts.css";
```

## Quickstart

1. Install the package and peer dependencies.
2. Mount `QueryClientProvider`.
3. Import the widget CSS.
4. Add a minimal wallet adapter.
5. Render `<SocketWidget config={config} />`.

Choose the smallest path that matches your app:

* **EVM only:** provide `accounts`, `getEVMWalletClient`, and usually `switchChain`.
* **Solana only:** provide `accounts`, `getSolanaSigner`, and `rpcs.solana`.
* **Tron:** provide `accounts` and `getTronWeb`.
* **EVM + Solana:** combine both adapters in the same `wallet` object.
* **EVM + Tron:** add `getTronWeb` and TRON accounts for Tron-supported routes.

## EVM-Only Example

```tsx theme={null}
import { SocketWidget, type WidgetConfig } from "@socket.tech/widget";
import { getWalletClient } from "@wagmi/core";
import { useMemo } from "react";
import { useAccount, useConfig, useSwitchChain } from "wagmi";

export function Widget() {
  const { address, chain, isConnected } = useAccount();
  const { switchChainAsync } = useSwitchChain();
  const wagmiConfig = useConfig();

  const accounts = useMemo(
    () =>
      address && isConnected
        ? [{ address, chainType: "EVM" as const, chainId: chain?.id, isConnected: true }]
        : [],
    [address, chain?.id, isConnected],
  );

  const config: WidgetConfig = {
    affiliateId: "your-affiliate-id",
    wallet: {
      accounts,
      getEVMWalletClient: async (chainId) => getWalletClient(wagmiConfig, { chainId }),
      switchChain: async (chainId) => {
        await switchChainAsync({ chainId });
        return true;
      },
    },
    eventHandlers: {
      onOpenWalletConnect: () => {
        openYourWalletModal();
      },
    },
  };

  return <SocketWidget config={config} />;
}
```

## Solana-Only Example

```tsx theme={null}
import { SocketWidget, type WidgetConfig } from "@socket.tech/widget";
import { useMemo } from "react";
import { useWallet } from "@solana/wallet-adapter-react";
import { useWalletModal } from "@solana/wallet-adapter-react-ui";

export function Widget() {
  const wallet = useWallet();
  const { setVisible } = useWalletModal();

  const accounts = useMemo(
    () =>
      wallet.publicKey
        ? [{ address: wallet.publicKey.toBase58(), chainType: "SVM" as const, isConnected: wallet.connected }]
        : [],
    [wallet.connected, wallet.publicKey],
  );

  const config: WidgetConfig = {
    affiliateId: "your-affiliate-id",
    rpcs: {
      solana: "https://api.mainnet-beta.solana.com",
    },
    wallet: {
      accounts,
      getSolanaSigner: async () => {
        if (!wallet.connected) return null;
        return {
          signAndSendTransaction: wallet.sendTransaction ?? undefined,
          signTransaction: wallet.signTransaction ?? undefined,
        };
      },
    },
    eventHandlers: {
      onOpenWalletConnect: () => setVisible(true),
    },
  };

  return <SocketWidget config={config} />;
}
```

To support both EVM and Solana, combine this signer with the EVM adapter shown above in the same `wallet` object.

## Adding Tron (optional)

* Include TRON accounts in `wallet.accounts` (with `chainType: "TRON"`)
* Provide `getTronWeb` returning your app's TronWeb instance (must satisfy `TronWebLike`)
* Route `eventHandlers.onOpenWalletConnect("tron")` to open your Tron wallet UI

If you do not pass `getTronWeb`, the widget works normally; Tron routes won't be available.

***

## Configuration Reference

### WidgetConfig

#### Required

| Property      | Type            | Description                                                         |
| ------------- | --------------- | ------------------------------------------------------------------- |
| `wallet`      | `WalletAdapter` | Minimal wallet adapter. The only mandatory property.                |
| `affiliateId` | `string`        | Integrator tracking identifier. Required for every widget instance. |

#### Optional

| Property                    | Type            | Description                                                                                              |
| --------------------------- | --------------- | -------------------------------------------------------------------------------------------------------- |
| `baseUrl`                   | `string`        | API base URL. Defaults to `https://backend.socket.tech/v3`.                                              |
| `turnstileSiteKey`          | `string`        | Cloudflare Turnstile site key. When provided, the widget loads Turnstile and uses JWT auth for requests. |
| `theme`                     | `Theme`         | Theming configuration. See [Theme Configuration](#theme-configuration).                                  |
| `widgetTitle`               | `string`        | Title shown in the widget header. Default: `"Swap"`.                                                     |
| `rpcs.solana`               | `string`        | Solana RPC URL. Required for Solana support.                                                             |
| `initialValues`             | `object`        | Default chain, token, and amount values.                                                                 |
| `supportedTokens`           | `object`        | Restrict available tokens by chain.                                                                      |
| `supportedChains`           | `object`        | Restrict available source/destination chains.                                                            |
| `eventHandlers`             | `EventHandlers` | Event callbacks. See [Event Handlers](#event-handlers).                                                  |
| `feeParams.feeTakerAddress` | `string`        | Wallet address that receives the integrator fee.                                                         |
| `feeParams.feeBps`          | `number`        | Fee in basis points (e.g. `10` = 0.1%).                                                                  |
| `features`                  | `object`        | Feature flags. See [Feature Flags](#feature-flags).                                                      |

### Feature Flags

* `internalToasts` (`boolean`): Show or hide internal toasts (default: `true`)
* `internalTxHistory` (`boolean`): Show or hide transaction history (default: `true`)
* `internalInflight` (`boolean`): Show or hide the inflight screen as a non-blocking toast (default: `true`)
* `internalTokenSelector` (`boolean`): Render the built-in token selector, or delegate token selection to your app via `eventHandlers.onOpenTokenSelector` (default: `true`)
* `internalTokenSelectorBounds` (`"widget"` | `"viewport"`): Constrain the built-in token selector to the widget or viewport (default: `"widget"`)

### Base URL and Auth Requirements

The widget uses a single default backend root: `https://backend.socket.tech/v3`.

* If you do not pass `baseUrl`, the widget uses the Socket backend URL above.
* `affiliateId` is required in every config.
* `turnstileSiteKey` is optional. Pass it only if you want JWT-authenticated requests.
* You may still override `baseUrl` explicitly if you need to point the widget at a different compatible backend.

***

## Wallet Adapter

The `wallet` object is the only host integration point the widget needs. You provide connected accounts and the network-specific wallet hooks you support; the widget handles the rest internally.

| Property             | Type                                                 | Required            | Description                                                                           |
| -------------------- | ---------------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------- |
| `accounts`           | `AccountInfo[]`                                      | Yes                 | Connected wallet accounts                                                             |
| `getEVMWalletClient` | `(chainId: number) => Promise<WalletClient \| null>` | EVM only            | Returns a viem WalletClient for the requested chain                                   |
| `getSolanaSigner`    | `() => Promise<SolanaSigner \| null>`                | Solana only         | Returns a Solana signer for signing transactions                                      |
| `getTronWeb`         | `() => TronWebLike \| undefined`                     | Tron only           | Returns the wallet-connected TronWeb instance for Tron transactions and deposit flows |
| `switchChain`        | `(chainId: number, account?) => Promise<boolean>`    | Recommended for EVM | Switches the wallet's active EVM chain                                                |

### What the widget handles internally

When you provide `getEVMWalletClient`, the widget automatically implements:

* `sendTransaction` (including EIP-5792 batched calls)
* `signTypedData`
* `writeContract`
* `readContract` (via viem public clients)
* `getBalance` (native + ERC-20)
* `getTransactionReceipt`
* `getBytecode`
* `getEnsAddress`
* `getWalletCapabilities` (EIP-5792)
* `getCallsStatus` (EIP-5792)

When you provide `getSolanaSigner` and `config.rpcs.solana`, the widget additionally handles:

* Solana transaction building and sending (VersionedTransaction with lookup tables)
* SOL and SPL token balance fetching (including Token-2022)
* Solana transaction receipt polling

When you provide `getTronWeb`, the widget additionally handles:

* Tron transaction building, signing, and broadcasting (for deposit and direct-deposit flows)
* TRX and TRC-20 balance and transaction receipt via the host-supplied TronWeb instance

### accounts

An array of currently connected wallet accounts:

```typescript theme={null}
accounts: Array<{
  address: string;
  chainType: "EVM" | "SVM" | "TRON";
  chainId?: number;
  isConnected: boolean;
  connector?: { id?: string; name?: string; icon?: string };
}>
```

### getEVMWalletClient

Returns a [viem WalletClient](https://viem.sh/docs/clients/wallet) for the requested chain. The widget uses this to send transactions, sign typed data, write contracts, and query EIP-5792 capabilities.

```typescript theme={null}
getEVMWalletClient: (chainId: number) => Promise<WalletClient | null>
```

The return type is `any` in the adapter interface so hosts are free to use any viem version; the widget casts internally.

### getSolanaSigner

Returns a Solana signer object. The widget builds the transaction internally (instructions, lookup tables, blockhash) and passes it to the signer. If the signer provides `signAndSendTransaction`, the widget prefers it; otherwise it falls back to `signTransaction` + `sendRawTransaction` via its internal Connection.

```typescript theme={null}
getSolanaSigner: () => Promise<{
  signAndSendTransaction?: (...args: any[]) => Promise<any>;
  signTransaction?: (...args: any[]) => Promise<any>;
} | null>
```

### getTronWeb

Returns the wallet-connected TronWeb instance from your app. The widget uses it to build, sign, and broadcast Tron transactions for deposit and direct-deposit flows. The instance must implement the minimal `TronWebLike` interface (see type export). If you do not support Tron, omit this property.

```typescript theme={null}
getTronWeb: () => TronWebLike | undefined
```

### switchChain

Switches the wallet's active EVM chain. The optional `account` parameter targets a specific wallet when multiple are connected.

Treat this as a success-or-throw contract in practice:

* resolve when the chain switch succeeds
* reject or throw if the switch is cancelled or fails

```typescript theme={null}
switchChain: (
  chainId: number,
  account?: { address?: string; chainType: "EVM" | "SVM" | "TRON" }
) => Promise<boolean>
```

***

## Token Configuration Details

### Token Interface

```typescript theme={null}
interface Token {
  address: string;
  chainId: number;
  decimals: number;
  logoURI: string;
  name: string;
  symbol: string;
  isVerified?: boolean; // Must be true to avoid warnings
}
```

### Using supportedTokens

Important notes:

* When `supportedTokens` are provided, the widget will not automatically set a default token.
* To show a default source token, you must pass `initialValues.fromChain` and `initialValues.inputTokens`.
* Set `isVerified: true` for tokens in `supportedTokens` to avoid warnings.
* `inputTokens` addresses must match tokens from your `supportedTokens.from[chainId]` list.

### Fetching Token Data

When using `supportedTokens`, you can fetch token data from the Socket API endpoints:

* `/tokens/list`: Returns a curated list of trending tokens (verified) or the complete token list
* `/tokens/search`: Search for tokens by address, name, or symbol

Tokens fetched from these endpoints include the `isVerified` field. For detailed request and response formats, see the [token-list API documentation](https://docs.socket.tech/api-reference/supported-chains-&-token-list/get-token-list).

***

## Theme Configuration

Customize the widget appearance with the `theme` property:

```tsx theme={null}
const theme = {
  width: 420, // or "full" for full width
  borderRadius: "base", // "none" | "sm" | "base" | "md" | "lg"
  fonts: {
    primary: "Inter, sans-serif",
    secondary: "Roboto, sans-serif",
  },
  colors: {
    text: {
      primary: "#FFFFFF",
      secondary: "#A0A0A0",
      button: "#000000",
      theme: "#3B82F6",
      accent1: "#10B981",
      accent2: "#F59E0B",
      accent3: "#EF4444",
      accent4: "#8B5CF6",
    },
    bg: {
      layer1: "#1F2937",
      layer2: "#374151",
      layer3: "#4B5563",
      accent1: "#10B981",
      accent3: "#EF4444",
      accent4: "#8B5CF6",
      main: "#111827",
      theme: "#3B82F6",
    },
    border: {
      strong: "#6B7280",
      theme: "#3B82F6",
    },
    icon: {
      primary: "#FFFFFF",
      secondary: "#A0A0A0",
      theme: "#3B82F6",
    },
  },
};
```

Colors support both hex (`#FFFFFF`) and RGB (`rgb(255, 255, 255)`) formats.

***

## Event Handlers

Handle user interactions and widget events:

```tsx theme={null}
const eventHandlers = {
  onFromTokenChange: (token: Token) => {
    console.log("Source token changed:", token);
  },
  onToTokenChange: (token: Token) => {
    console.log("Destination token changed:", token);
  },
  onFromChainChange: (chain: Chain) => {
    console.log("Source chain changed:", chain);
  },
  onToChainChange: (chain: Chain) => {
    console.log("Destination chain changed:", chain);
  },
  onEvent: (eventType: "success" | "error" | "warning", eventData: EventData) => {
    console.log("Widget event:", eventType, eventData);
  },
  onOpenWalletConnect: (network: "solana" | "eip155" | "tron") => {
    openWalletModal(network);
  },
  onSwapInitiated: (data: { chainId: number; hash: string; type: OrderFlowType }) => {
    console.log("Swap initiated:", data);
  },
  onTransactionStatusChange: (data: { requestHash: string; statusCode: SwapStatus }) => {
    console.log("Transaction status:", data);
  },
  onOpenTokenSelector: (data: TokenSelectorOpenData) => {
    openExternalTokenSelector(data);
  },
  onTokenSelectorDataChange: (data: TokenSelectorOpenData) => {
    syncExternalTokenSelector(data);
  },
  logEvent: (log: { event: Event; error: unknown; context?: Record<string, unknown> }) => {
    console.log("Analytics event:", log);
  },
  toggleExternalHistorySection: () => {
    toggleHistorySidebar();
  },
  showToast: (title, message, type, duration) => {
    // Display a custom toast notification
  },
};
```

***

## Imperative API

The imperative API allows parent components to control widget state programmatically.

Use case example: when a user clicks a history item in a sidebar, the parent can navigate the widget to the inflight screen for that transaction.

```tsx theme={null}
import { useRef } from "react";
import { SocketWidget, type WidgetImperativeAPIType } from "@socket.tech/widget";

export default function App() {
  const bungeeRef = useRef<WidgetImperativeAPIType>(null);

  const handleSetInflightData = (data: OrderData) => {
    bungeeRef.current?.setInflightData(data);
  };

  return <SocketWidget config={config} ref={bungeeRef} />;
}
```

Available methods:

* `setInflightData(data: OrderData)`: Track pending transactions and navigate to inflight screen
* `openQrDeposit(quoteId: string)`: Open the QR deposit screen for a quote
* `selectToken(token: Token, isSource: boolean)`: Programmatically select the source or destination token
* `setSourceWalletMode(mode: SourceWalletMode)`: Update the source wallet mode used by the widget

***

## Type Exports

```tsx theme={null}
import type {
  WidgetConfig,
  WidgetImperativeAPIType,
  WalletAdapter,
  TronWebLike,
} from "@socket.tech/widget";
```

***

## Troubleshooting

| Issue                            | Fix                                                                                                    |
| -------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `No QueryClient set` error       | Mount `QueryClientProvider` above `<SocketWidget />`                                                   |
| Clicking connect does nothing    | Implement `eventHandlers.onOpenWalletConnect`                                                          |
| Transactions fail on wrong chain | Ensure `getEVMWalletClient(chainId)` returns a client for the requested chain, not just the active one |
| Chain switch feels inconsistent  | Make `switchChain` reject or throw on cancellation, not resolve silently                               |
| Solana actions fail immediately  | Mount Solana wallet-adapter providers above the widget; pass both `getSolanaSigner` and `rpcs.solana`  |
| Tron deposit unavailable         | Pass `getTronWeb` and include TRON accounts in `wallet.accounts`                                       |
| No widget styling                | Import `@socket.tech/widget/styles.css` and `@socket.tech/widget/fonts.css`                            |
