Live Demo
Explore a fully working implementation in this live demo:This demo includes a complete working implementation with Starknet wallets integration using Dynamic Labs SDK. You can explore code at this repository.
Quick Start
Installation
Install the Layerswap Widget along with the necessary wallet providers. This installation includes support for Starknet, Ethereum, Solana, and Bitcoin wallets:Copy
Ask AI
npm install @layerswap/widget zustand @layerswap/wallet-starknet @layerswap/wallet-evm wagmi viem @tanstack/react-query @layerswap/wallet-svm @layerswap/wallet-bitcoin @bigmi/client @bigmi/core @bigmi/react
Initial Configuration
Create a custom Starknet wallet connection hook that bridges Dynamic Labs SDK with Layerswap Widget.View complete hook implementation (hooks/useCustomStarknet.ts)
View complete hook implementation (hooks/useCustomStarknet.ts)
Copy
Ask AI
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,
};
}
Copy
Ask AI
import { Swap, LayerswapProvider } from '@layerswap/widget'
import { StarknetWalletConnectors } from "@dynamic-labs/starknet";
import { DynamicContextProvider } from "@dynamic-labs/sdk-react-core";
import { EVMProvider } from "@layerswap/wallet-evm"
import { StarknetProvider } from "@layerswap/wallet-starknet"
import { SVMProvider } from "@layerswap/wallet-svm"
import { BitcoinProvider } from "@layerswap/wallet-bitcoin"
import useCustomStarknet from "../hooks/useCustomStarknet";
import { WalletProvider } from "@layerswap/widget/types";
import "@layerswap/widget/index.css"
const PageComponent = () => {
const starknetProvider: WalletProvider = {
...StarknetProvider,
walletConnectionProvider: useCustomStarknet
}
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={[EVMProvider, starknetProvider, SVMProvider, BitcoinProvider]}
>
<Swap />
</LayerswapProvider>
</DynamicContextProvider>
)
}
Environment Variables
Create a.env.local file with your API credentials:
.env.local
Copy
Ask AI
DYNAMIC_ENVIRONMENT_ID=your_dynamic_environment_id
LAYERSWAP_API_KEY=your_layerswap_api_key
Get Your API Keys:
- Dynamic Labs: Sign up at Dynamic
- Layerswap: Generate from the Partner Dashboard
Complete Example
Here’s a full implementation example combining all concepts:Copy
Ask AI
import { Swap, LayerswapProvider } from '@layerswap/widget'
import { StarknetWalletConnectors } from "@dynamic-labs/starknet";
import { DynamicContextProvider } from "@dynamic-labs/sdk-react-core";
import { EVMProvider } from "@layerswap/wallet-evm"
import { StarknetProvider } from "@layerswap/wallet-starknet"
import { SVMProvider } from "@layerswap/wallet-svm"
import { BitcoinProvider } from "@layerswap/wallet-bitcoin"
import useCustomStarknet from "../hooks/useCustomStarknet";
import { WalletProvider } from "@layerswap/widget/types";
import "@layerswap/widget/index.css"
const PageComponent = () => {
const starknetProvider: WalletProvider = {
...StarknetProvider,
walletConnectionProvider: useCustomStarknet
}
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={[EVMProvider, starknetProvider, SVMProvider, BitcoinProvider]}
>
<Swap />
</LayerswapProvider>
</DynamicContextProvider>
)
}
Testing
Testnet Configuration
Test your integration on testnet before going live:Copy
Ask AI
const config = {
apiKey: 'YOUR_TESTNET_API_KEY',
version: 'testnet',
initialValues: {
to: 'STARKNET_SEPOLIA',
toAsset: 'USDC'
},
}