> ## Documentation Index
> Fetch the complete documentation index at: https://layerswaplabsv0-main-depositactionsguide.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Starknet wallets with Dynamic

> Complete guide for integrating and customizing Layerswap Widget with Starknet wallets using Dynamic Labs SDK

## Live Demo

Explore a fully working implementation in this live demo:

<iframe src="https://layerswap-dynamic-example.vercel.app/" style={{ width:"100%",height:"800px",border:"0",borderRadius:"4px",overflow:"hidden" }} title="arentant/layerswap-widget-nextjs-example/main" allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" />

<Note>
  This demo includes a complete working implementation with Starknet wallets integration using Dynamic Labs SDK. You can explore code at this [repository](https://github.com/layerswap/layerswapapp/tree/dev-monorepo/examples/nextjs-dynamic).
</Note>

## Quick Start

### Installation

Install the Layerswap Widget along with the necessary wallet providers. This installation includes support for Starknet, Ethereum, Solana, and Bitcoin wallets:

<CodeGroup>
  ```typescript npm theme={null}
  npm install @layerswap/widget zustand@4.5.7 @layerswap/wallet-starknet @layerswap/wallet-evm wagmi viem @tanstack/react-query @layerswap/wallet-svm @layerswap/wallet-bitcoin @bigmi/client @bigmi/core @bigmi/react
  ```

  ```typescript yarn theme={null}
  yarn add @layerswap/widget zustand@4.5.7 @layerswap/wallet-starknet @layerswap/wallet-evm wagmi viem @tanstack/react-query @layerswap/wallet-svm @layerswap/wallet-bitcoin @bigmi/client @bigmi/core @bigmi/react
  ```

  ```typescript pnpm theme={null}
  pnpm add @layerswap/widget zustand@4.5.7 @layerswap/wallet-starknet @layerswap/wallet-evm wagmi viem @tanstack/react-query @layerswap/wallet-svm @layerswap/wallet-bitcoin @bigmi/client @bigmi/core @bigmi/react
  ```
</CodeGroup>

If you want to customize the wallet provider selection, please refer to the [Widget Quickstart](/integration/UI/Widget/Quickstart).

### Initial Configuration

Create a custom Starknet wallet connection hook that bridges Dynamic Labs SDK with Layerswap Widget.

<Accordion title="View complete hook implementation (hooks/useCustomStarknet.ts)">
  <CodeGroup>
    ```typescript hooks/useCustomStarknet.ts theme={null}
    import { useCallback, useEffect, useMemo } from "react";
    import {
      useUserWallets,
      useDynamicContext,
      dynamicEvents,
      Wallet as DynamicWallet,
    } from "@dynamic-labs/sdk-react-core";
    import {
      resolveWalletConnectorIcon,
      NetworkWithTokens,
    } from "@layerswap/widget";
    import { WalletConnectionProvider, Wallet, WalletConnectionProviderProps } from "@layerswap/widget/types"

    export default function useStarknet({ networks }: WalletConnectionProviderProps): WalletConnectionProvider {
      const name = "Starknet";
      const id = "starknet";

      // Dynamic SDK
      const { setShowAuthFlow, handleLogOut } = useDynamicContext();
      const userWallets = useUserWallets();

      // Starknet network names
      const starknetNetworkNames = [
        "STARKNET_MAINNET",
        "STARKNET_SEPOLIA",
      ]

      // Supported-networks
      const supportedNetworks = useMemo(
        () => ({
          asSource: starknetNetworkNames,
          autofill: starknetNetworkNames,
          withdrawal: starknetNetworkNames,
        }),
        [starknetNetworkNames],
      );

      // Clean up dynamicEvents listeners on unmount
      useEffect(() => {
        return () => {
          dynamicEvents.removeAllListeners("walletAdded");
          dynamicEvents.removeAllListeners("authFlowCancelled");
        };
      }, []);
      // connectWallet: log out existing, show authFlow, wait for event, then resolve
      const connectWallet = useCallback(async (): Promise<Wallet | undefined> => {
        if (userWallets.length) {
          await handleLogOut();
        }

        const newDynWallet = await new Promise<DynamicWallet>((resolve, reject) => {
          setShowAuthFlow(true);

          const onAdded = (w: DynamicWallet) => {
            cleanup();
            resolve(w);
          };
          const onCancelled = () => {
            cleanup();
            reject(new Error("User cancelled the connection"));
          };
          const cleanup = () => {
            dynamicEvents.off("walletAdded", onAdded);
            dynamicEvents.off("authFlowCancelled", onCancelled);
          };

          dynamicEvents.on("walletAdded", onAdded);
          dynamicEvents.on("authFlowCancelled", onCancelled);
        });

        return resolveWallet({
          connection: newDynWallet,
          networks,
          supportedNetworks,
          disconnect: handleLogOut,
          providerName: name,
        });
      }, [userWallets, handleLogOut, setShowAuthFlow, networks, supportedNetworks]);

      // Logout
      const disconnectWallets = useCallback(async () => {
        await handleLogOut();
      }, [handleLogOut]);

      // Map wagmi connectors → Dynamic SDK wallets → our Wallet shape
      const connectedWallets: Wallet[] = useMemo(
        () =>
          userWallets
            .map((dyn) => {
              if (!dyn) return;
              return resolveWallet({
                connection: dyn,
                networks,
                supportedNetworks,
                disconnect: disconnectWallets,
                providerName: name,
              });
            })
            .filter(Boolean) as Wallet[],
        [userWallets, networks, supportedNetworks, disconnectWallets],
      );

      const logo = networks.find((n) => n.name.toLowerCase().includes("starknet"))?.logo;

      return {
        connectWallet,
        activeWallet: connectedWallets.find((w) => w.isActive),
        connectedWallets,
        asSourceSupportedNetworks: supportedNetworks.asSource,
        autofillSupportedNetworks: supportedNetworks.autofill,
        withdrawalSupportedNetworks: supportedNetworks.withdrawal,
        name,
        id,
        providerIcon: logo,
      };
    }

    /** Reusable helper to turn a DynamicWallet + context into our `Wallet` shape */
    function resolveWallet(props: {
      connection: DynamicWallet;
      networks: NetworkWithTokens[];
      supportedNetworks: {
        asSource: string[];
        autofill: string[];
        withdrawal: string[];
      };
      disconnect: () => Promise<void>;
      providerName: string;
    }): Wallet | undefined {
      const { connection, networks, supportedNetworks, disconnect, providerName } = props;

      const connectorName = connection.connector.name;
      const address = connection.address;
      if (!connectorName || !address) return;

      const displayName = `${connectorName} – ${providerName}`;
      const networkIcon = networks.find((n) => n.name.toLowerCase().includes("starknet"))?.logo;

      return {
        id: connectorName,
        isActive: true,
        address,
        addresses: [address],
        displayName,
        providerName,
        icon: resolveWalletConnectorIcon({ iconUrl: connection.connector.metadata.icon }),
        disconnect: () => disconnect(),
        asSourceSupportedNetworks: supportedNetworks.asSource,
        autofillSupportedNetworks: supportedNetworks.autofill,
        withdrawalSupportedNetworks: supportedNetworks.withdrawal,
        networkIcon,
      };
    }

    ```
  </CodeGroup>
</Accordion>

Set up the providers and widget in your main component:

```typescript theme={null}
import { Swap, LayerswapProvider } from '@layerswap/widget'
import { StarknetWalletConnectors } from "@dynamic-labs/starknet";
import { DynamicContextProvider } from "@dynamic-labs/sdk-react-core";
import { createEVMProvider, createStarknetProvider, createSVMProvider, createBitcoinProvider } from "@layerswap/wallets"
import useCustomStarknet from "../hooks/useCustomStarknet";
import "@layerswap/widget/index.css"

const PageComponent = () => {
    const walletConnectConfigs = {
        projectId: "YOUR_WALLETCONNECT_PROJECT_ID",
        name: "Your App Name",
        description: "Your app description",
        url: "https://yourapp.com",
        icons: ["https://yourapp.com/icon.png"]
    }

    const walletProviders = [
        createEVMProvider({ walletConnectConfigs }),
        createStarknetProvider({
            walletConnectConfigs,
            customHook: useCustomStarknet
        }),
        createSVMProvider({ walletConnectConfigs }),
        createBitcoinProvider()
    ]

    return (
        <DynamicContextProvider
            settings={{
                environmentId: {DYNAMIC_ENVIRONMENT_ID},
                walletConnectors: [StarknetWalletConnectors],
            }}
        >
            <LayerswapProvider
                config={{
                    apiKey: {LAYERSWAP_API_KEY}, //optional
                    version: 'mainnet',
                    initialValues: {
                        to: 'STARKNET_MAINNET',
                        toAsset: 'USDC',
                        lockTo: true
                    },
                }}
                walletProviders={walletProviders}
            >
                <Swap />
            </LayerswapProvider>
        </DynamicContextProvider>
    )
}
```

You can generate an API key from the [Partner Dashboard](/api-keys) to track swaps done through the widget.

### Environment Variables

Create a `.env.local` file with your API credentials:

```bash .env.local theme={null}
DYNAMIC_ENVIRONMENT_ID=your_dynamic_environment_id
LAYERSWAP_API_KEY=your_layerswap_api_key
```

<Note>
  **Get Your API Keys:**

  * Dynamic Labs: [Sign up at Dynamic](https://www.dynamic.xyz/)
  * Layerswap: Generate from the [Partner Dashboard](/api-keys)
</Note>

## Complete Example

Here's a full implementation example combining all concepts:

<CodeGroup>
  ```typescript App.tsx theme={null}
  import { Swap, LayerswapProvider } from '@layerswap/widget'
  import { StarknetWalletConnectors } from "@dynamic-labs/starknet";
  import { DynamicContextProvider } from "@dynamic-labs/sdk-react-core";
  import { createEVMProvider, createStarknetProvider, createSVMProvider, createBitcoinProvider } from "@layerswap/wallets"
  import useCustomStarknet from "../hooks/useCustomStarknet";
  import "@layerswap/widget/index.css"

  const PageComponent = () => {
      const walletConnectConfigs = {
          projectId: "YOUR_WALLETCONNECT_PROJECT_ID",
          name: "Your App Name",
          description: "Your app description",
          url: "https://yourapp.com",
          icons: ["https://yourapp.com/icon.png"]
      }

      const walletProviders = [
          createEVMProvider({ walletConnectConfigs }),
          createStarknetProvider({
              walletConnectConfigs,
              customHook: useCustomStarknet
          }),
          createSVMProvider({ walletConnectConfigs }),
          createBitcoinProvider()
      ]

      return (
          <DynamicContextProvider
              settings={{
                  environmentId: {DYNAMIC_ENVIRONMENT_ID},
                  walletConnectors: [StarknetWalletConnectors],
              }}
          >
              <LayerswapProvider
                  config={{
                      apiKey: {LAYERSWAP_API_KEY},
                      version: 'mainnet',
                      initialValues: {
                          to: 'STARKNET_MAINNET',
                          toAsset: 'USDC',
                          lockTo: true
                      },
                  }}
                  walletProviders={walletProviders}
              >
                  <Swap />
              </LayerswapProvider>
          </DynamicContextProvider>
      )
  }
  ```

  ```typescript hooks/useCustomStarknet.ts theme={null}
  import { useCallback, useEffect, useMemo } from "react";
  import {
    useUserWallets,
    useDynamicContext,
    dynamicEvents,
    Wallet as DynamicWallet,
  } from "@dynamic-labs/sdk-react-core";
  import {
    resolveWalletConnectorIcon,
    NetworkWithTokens,
  } from "@layerswap/widget";
  import { WalletConnectionProvider, Wallet, WalletConnectionProviderProps } from "@layerswap/widget/types"

  export default function useStarknet({ networks }: WalletConnectionProviderProps): WalletConnectionProvider {
    const name = "Starknet";
    const id = "starknet";

    // Dynamic SDK
    const { setShowAuthFlow, handleLogOut } = useDynamicContext();
    const userWallets = useUserWallets();

    // Starknet network names
    const starknetNetworkNames = [
      "STARKNET_MAINNET",
      "STARKNET_SEPOLIA",
    ]

    // Supported-networks
    const supportedNetworks = useMemo(
      () => ({
        asSource: starknetNetworkNames,
        autofill: starknetNetworkNames,
        withdrawal: starknetNetworkNames,
      }),
      [starknetNetworkNames],
    );

    // Clean up dynamicEvents listeners on unmount
    useEffect(() => {
      return () => {
        dynamicEvents.removeAllListeners("walletAdded");
        dynamicEvents.removeAllListeners("authFlowCancelled");
      };
    }, []);
    // connectWallet: log out existing, show authFlow, wait for event, then resolve
    const connectWallet = useCallback(async (): Promise<Wallet | undefined> => {
      if (userWallets.length) {
        await handleLogOut();
      }

      const newDynWallet = await new Promise<DynamicWallet>((resolve, reject) => {
        setShowAuthFlow(true);

        const onAdded = (w: DynamicWallet) => {
          cleanup();
          resolve(w);
        };
        const onCancelled = () => {
          cleanup();
          reject(new Error("User cancelled the connection"));
        };
        const cleanup = () => {
          dynamicEvents.off("walletAdded", onAdded);
          dynamicEvents.off("authFlowCancelled", onCancelled);
        };

        dynamicEvents.on("walletAdded", onAdded);
        dynamicEvents.on("authFlowCancelled", onCancelled);
      });

      return resolveWallet({
        connection: newDynWallet,
        networks,
        supportedNetworks,
        disconnect: handleLogOut,
        providerName: name,
      });
    }, [userWallets, handleLogOut, setShowAuthFlow, networks, supportedNetworks]);

    // Logout
    const disconnectWallets = useCallback(async () => {
      await handleLogOut();
    }, [handleLogOut]);

    // Map wagmi connectors → Dynamic SDK wallets → our Wallet shape
    const connectedWallets: Wallet[] = useMemo(
      () =>
        userWallets
          .map((dyn) => {
            if (!dyn) return;
            return resolveWallet({
              connection: dyn,
              networks,
              supportedNetworks,
              disconnect: disconnectWallets,
              providerName: name,
            });
          })
          .filter(Boolean) as Wallet[],
      [userWallets, networks, supportedNetworks, disconnectWallets],
    );

    const logo = networks.find((n) => n.name.toLowerCase().includes("starknet"))?.logo;

    return {
      connectWallet,
      activeWallet: connectedWallets.find((w) => w.isActive),
      connectedWallets,
      asSourceSupportedNetworks: supportedNetworks.asSource,
      autofillSupportedNetworks: supportedNetworks.autofill,
      withdrawalSupportedNetworks: supportedNetworks.withdrawal,
      name,
      id,
      providerIcon: logo,
    };
  }

  /** Reusable helper to turn a DynamicWallet + context into our `Wallet` shape */
  function resolveWallet(props: {
    connection: DynamicWallet;
    networks: NetworkWithTokens[];
    supportedNetworks: {
      asSource: string[];
      autofill: string[];
      withdrawal: string[];
    };
    disconnect: () => Promise<void>;
    providerName: string;
  }): Wallet | undefined {
    const { connection, networks, supportedNetworks, disconnect, providerName } = props;

    const connectorName = connection.connector.name;
    const address = connection.address;
    if (!connectorName || !address) return;

    const displayName = `${connectorName} – ${providerName}`;
    const networkIcon = networks.find((n) => n.name.toLowerCase().includes("starknet"))?.logo;

    return {
      id: connectorName,
      isActive: true,
      address,
      addresses: [address],
      displayName,
      providerName,
      icon: resolveWalletConnectorIcon({ iconUrl: connection.connector.metadata.icon }),
      disconnect: () => disconnect(),
      asSourceSupportedNetworks: supportedNetworks.asSource,
      autofillSupportedNetworks: supportedNetworks.autofill,
      withdrawalSupportedNetworks: supportedNetworks.withdrawal,
      networkIcon,
    };
  }
  ```
</CodeGroup>

For a complete list of configuration options, see [Configurations](/integration/UI/Configurations).

## Testing

### Testnet Configuration

Test your integration on testnet before going live:

```typescript theme={null}
const config = {
  apiKey: 'YOUR_TESTNET_API_KEY',
  version: 'testnet',
  initialValues: {
    to: 'STARKNET_SEPOLIA',
    toAsset: 'USDC'
  },
}
```
