Skip to main content
This page applies only to the self-bundled @layerswap/widget integration. The loader packages do not accept custom wallet-provider factories. If your EVM wallet manager exposes a wagmi Config, use Sharing your wagmi config instead.
Use custom wallet management when your application already owns the wallet UI and connection lifecycle through a service such as Dynamic, Privy, or another host-managed wallet SDK. The current API is store-based. A chain factory receives customConnection, which creates a WalletConnectionStore backed by a vanilla Zustand store. The previous customHook and walletConnectionProvider fields are no longer part of the provider contract. The chain factory still supplies its normal balance, gas, transfer, gasless, and other resolvers. customConnection replaces only its connection state.

Choose the integration shape

  • You read your wallet SDK through React hooks: return a WalletConnectionProvider snapshot from a custom hook, bridge it with createReactHookConnectionAdapter, and render the adapter’s Hydrator.
  • Your wallet SDK exposes an external store or event API: create the vanilla Zustand store directly and return a WalletConnectionStore. No hydrator is needed.
The repository’s Dynamic Starknet example uses the React-hook adapter described below.

Adapt a React hook

1. Install the eager chain package

Custom connections are configured on a chain’s eager provider factory. Import that factory from its chain package, not a lazy descriptor from @layerswap/wallets:
Replace @layerswap/wallet-starknet with the package for the chain family you are adapting.
Next.js hosts must add @layerswap/widget, @layerswap/widget-types, @layerswap/utils, @layerswap/ui-kit, @layerswap/wallet-core, and every installed @layerswap/wallet-* package to transpilePackages. The published next builds contain extensionless ESM imports that Node’s SSR loader can otherwise reject with ERR_MODULE_NOT_FOUND, often for a path ending in /knownIds. See Build troubleshooting for the configuration.

2. Return the current connection snapshot

The hook translates third-party wallet state into WalletConnectionProvider. Both files below belong to the integrating application: the first adapts Dynamic’s React state, and the second turns a generic Dynamic wallet into the concrete Starknet account required by Layerswap.
useCustomStarknet.ts
createReactHookConnectionAdapter creates one singleton store per adapter. Create the adapter once, outside a component. Two Widget instances that use the same adapter also share that connection store and its state. Dynamic’s getWalletAccount() is asynchronous. Resolve it before assigning metadata.starknetAccount; do not assign the promise itself. The resulting account supplies the estimateInvokeFee and execute methods used by the default Starknet gas and transfer resolvers. If your wallet SDK does not expose a compatible Starknet account, leave asSourceSupportedNetworks and withdrawalSupportedNetworks empty so the Widget does not offer a signing flow it cannot complete, or replace the default gas and transfer resolvers. ready should stay false until the third-party SDK can service connection requests. Use connectedWallets: undefined while restoring an unknown session and connectedWallets: [] once initialization has finished with no connected wallet. The Widget shows a restoring state while the value is undefined; if the SDK’s account resolution never settles, the wallet UI remains blocked, so consider applying a timeout. This sample marks only the first resolved wallet as isActive and does not implement switchAccount. The Widget therefore cannot switch between multiple Dynamic wallets. Implement switchAccount and keep isActive and activeWallet synchronized if your integration needs account switching.

3. Render the hydrator

The adapter’s Hydrator runs the hook and mirrors each snapshot into the external store. It must be inside both the third-party SDK provider and LayerswapProvider, because it consumes both contexts. Its props also require a network adapter.
walletNetworkAdapter.ts
networkAdapter is required by the Hydrator contract, but the Widget does not currently export the adapter it uses internally. This host-side copy mirrors the Widget’s NetworkWithTokens adapter and derives its type through WalletConnectionProviderProps, so the host does not need a direct @layerswap/wallet-core dependency for the adapter type.
CustomStarknetHydrator.tsx
Render this Hydrator only on the client. It uses useLayoutEffect internally; in the Next.js Pages Router, load it with next/dynamic and ssr: false to avoid the server-render warning.

4. Pass customConnection to the chain factory

Layerswap.tsx
Keep the adapter, provider object, and walletProviders array stable. Recreating them during render tears down and recreates connection state.
createReactHookConnectionAdapter is exported from @layerswap/widget/internal. Keep @layerswap/widget and every @layerswap/wallet-* package on compatible releases when using this advanced integration.

External-store wallet managers

If the third-party SDK already exposes subscribe/get-state primitives, create the Zustand store directly. The Widget calls updateProps when settings networks change and destroy when the connection is removed or the provider unmounts.
The ./walletManager module below is illustrative and is not provided by Layerswap. Implement its wallets, activeWalletId, ready, connect, disconnect, and subscribe operations—and the mapWallet and supportedNetworkNames helpers—against your SDK. Its connect operation must resolve undefined when the user cancels.
createCustomConnection.ts
Pass this factory directly as customConnection:
Because no React hook is involved, do not create or render a Hydrator.

Current contract

WalletConnectionStore

Required connection snapshot fields

Common optional fields include disconnectWallets, switchAccount, switchChain, availableConnectors, asSourceSupportedNetworks, autofillSupportedNetworks, providerIcon, unsupportedPlatforms, and hideFromList.

Wallet

These are the fields most custom adapters need:
Give each wallet a stable, unique id. icon is now an image string; omit it to let the Widget render its address-based fallback.

Preserve signing support

The connection snapshot tells the Widget which accounts exist; it does not automatically teach the chain package how your third-party SDK signs.
  • The default Starknet gas and transfer resolvers read wallet.metadata.starknetAccount.
  • Other chain packages can use package-owned SDK state or signer adapters. A custom connection must either populate compatible state or replace those resolvers.
  • balanceProviders, gasProviders, and transferProviders can be passed beside customConnection. Supplying one of these fields replaces that factory’s default list for the capability.
  • For EVM integrations backed by wagmi, pass the existing wagmiConfig so the EVM transfer resolver uses the same signer. In most cases, the dedicated wagmi integration is simpler than a custom connection.
Test connection, account restoration, address autofill, balance loading, gas estimation, signing, disconnect, and account or chain changes before shipping. Cancel the SDK’s modal as well and confirm the Widget returns to its idle state instead of remaining on “Connecting…”.

Migrating an older custom provider

Remove the old object-spreading pattern as well; provider constants such as StarknetProvider are no longer the customization surface.

Wallet management

Understand the self-bundled provider architecture.

Wallet providers

Choose the eager chain factory and configure its native credentials.

Sharing your wagmi config

Reuse an app-owned EVM connection without a custom store.

Self-bundled Widget

Install and render the package-based Widget.