Skip to main content

Dynamic.xyz Integration

Complete integration with Dynamic.xyz for multi-chain wallet support.
import { EthereumWalletConnectors } from '@dynamic-labs/ethereum';
import { DynamicContextProvider, mergeNetworks } from '@dynamic-labs/sdk-react-core';
import { SolanaWalletConnectors, isSolanaWallet } from '@dynamic-labs/solana';
import { DynamicWagmiConnector } from '@dynamic-labs/wagmi-connector';
import { chainToViemChain, ChainArchitecture } from '@metalayer/sdk';
import { WidgetProvider, Widget } from '@metalayer/widget';
import { useState, useMemo } from 'react';

function App() {
  const [evmNetworks, setEvmNetworks] = useState([]);

  return (
    <DynamicContextProvider
      settings={{
        environmentId: 'your-dynamic-environment-id',
        walletConnectors: [EthereumWalletConnectors, SolanaWalletConnectors],
        overrides: {
          evmNetworks: (networks) => mergeNetworks(evmNetworks, networks),
        },
      }}
    >
      <WidgetProvider
        sdkConfig={{
          apiKey: 'your-api-key',
          environment: 'production',
        }}
        defaultSource={{
          chainId: 1,
          tokenAddress: '0xa0b86a33e6441e073b793e4e36b4de0d82cd5e22', // USDC - see Default Source/Destination section
        }}
        onSupportedChainsLoad={(chains) => {
          // See Chain Loading Callback section for details
          const evmNetworks = chains
            .filter(chain => chain.identifier?.architecture === ChainArchitecture.ETHEREUM)
            .map(chain => {
              const viemChain = chainToViemChain(chain);
              return viemChainToEvmNetwork(viemChain, chain.imageUrl);
            });
          setEvmNetworks(evmNetworks);
        }}
        onError={(error) => console.error('Widget error:', error)}
      >
        <DynamicWagmiConnector>
          <WidgetWrapper />
        </DynamicWagmiConnector>
      </WidgetProvider>
    </DynamicContextProvider>
  );
}

function WidgetWrapper() {
  const { setShowAuthFlow, primaryWallet } = useDynamicContext();

  const solanaSigner = useMemo(() => {
    if (!primaryWallet || !isSolanaWallet(primaryWallet)) return undefined;

    return {
      address: primaryWallet.address,
      isConnected: () => !!primaryWallet.address,
      signTransaction: async (transaction) => {
        const signer = await primaryWallet.getSigner();
        return await signer.signTransaction(transaction);
      },
    };
  }, [primaryWallet]);

  return (
    <Widget
      config={{
        solanaSigner,
        onOpenConnectModal: () => setShowAuthFlow(true),
      }}
    />
  );
}

// Helper function to convert Viem chain to EVM network
function viemChainToEvmNetwork(viemChain, iconUrl) {
  return {
    chainId: viemChain.id,
    name: viemChain.name,
    networkId: viemChain.id,
    nativeCurrency: viemChain.nativeCurrency,
    rpcUrls: Object.values(chain.rpcUrls.default).flat(),
    blockExplorerUrls: viemChain.blockExplorers?.default?.url ? [viemChain.blockExplorers.default.url] : [],
    isTestnet: chain.testnet,
    iconUrls: iconUrl ? [iconUrl] : [],
  };
}

RainbowKit Integration

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { RainbowKitProvider, useConnectModal } from '@rainbow-me/rainbowkit';
import { WidgetProvider, Widget } from '@metalayer/widget';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <WidgetProvider
        sdkConfig={{
          apiKey: 'your-api-key',
          environment: 'production',
        }}
      >
        <RainbowKitProvider>
          <BridgePage />
        </RainbowKitProvider>
      </WidgetProvider>
    </QueryClientProvider>
  );
}

function BridgePage() {
  const { openConnectModal } = useConnectModal();

  return (
    <Widget config={{ onOpenConnectModal: openConnectModal }} />
  );
}

Next.js Setup

App Router

In your layout.tsx:
import '@metalayer/widget/styles.css';
import 'material-symbols/rounded.css';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Pages Router

In your _app.tsx:
import '@metalayer/widget/styles.css';
import 'material-symbols/rounded.css';

export default function App({ Component, pageProps }) {
  return (
    <Providers>
      <Component {...pageProps} />
    </Providers>
  );
}

Advanced Configuration

Configure the widget with advanced options for production use.
import { WidgetProvider, Widget } from '@metalayer/widget';

function AdvancedBridgeApp() {
  return (
    <WidgetProvider
      sdkConfig={{
        apiKey: process.env.NEXT_PUBLIC_METALAYER_API_KEY,
        environment: process.env.NODE_ENV === 'production'
          ? 'production'
          : 'staging',
      }}
      defaultSource={{
        chainId: 1, // Ethereum Mainnet
        tokenAddress: '0x0000000000000000000000000000000000000000', // ETH
      }}
      defaultDestination={{
        chainId: 42161, // Arbitrum One
        tokenAddress: '0x0000000000000000000000000000000000000000', // ETH
      }}
      onSupportedChainsLoad={(chains) => {
        // Update your application's chain configuration
        console.log('Supported chains loaded:', chains.length);
      }}
      onError={(error) => {
        // Send to error tracking service
        console.error('Widget error:', error);
        // trackError(error);
      }}
      debugEnabled={process.env.NODE_ENV === 'development'}
    >
      <Widget
        config={{
          onOpenConnectModal: () => {
            // Your wallet connection logic
            openWalletModal();
          },
          solanaSigner: getSolanaSigner(), // If supporting Solana
        }}
      />
    </WidgetProvider>
  );
}

Analytics Integration

Track widget usage and user interactions:
import { WidgetProvider, Widget } from '@metalayer/widget';

function AnalyticsEnabledWidget() {
  const trackEvent = (eventName, properties) => {
    // Your analytics implementation
    analytics.track(eventName, properties);
  };

  return (
    <WidgetProvider
      sdkConfig={{
        apiKey: 'your-api-key',
        environment: 'production',
      }}
      onSupportedChainsLoad={(chains) => {
        trackEvent('widget_chains_loaded', { 
          chainCount: chains.length 
        });
      }}
    >
      <Widget
        config={{
          onOpenConnectModal: () => {
            trackEvent('wallet_connect_initiated');
            openWalletModal();
          },
          onSubmitTransaction: (
            sourceChainId?: number, 
            destChainId?: number, 
            amount?: string
          ) => {
            trackEvent('bridge_transaction_submitted', {
              sourceChainId,
              destChainId,
              amount
            });
          },
        }}
      />
    </WidgetProvider>
  );
}