Dynamic powers Fireblocks embedded wallets on web. Dynamic does not need a dedicated Trails adapter — it plugs into wagmi via @dynamic-labs/wagmi-connector, and Trails shares that session through the standard wagmiAdapter.
No custom hook is required. Once the user connects with Dynamic’s embedded wallet, the Trails widget reads the same wagmi connection state.
The division of labor:
- Dynamic owns the wallet: embedded wallet creation, auth, recovery, and connect UI (
DynamicWidget).
- Trails owns the payment: routing, quotes, and cross-chain execution, signed through the bridged wagmi session.
Install
pnpm add 0xtrails @0xtrails/adapter-wagmi \
@dynamic-labs/sdk-react-core @dynamic-labs/ethereum @dynamic-labs/wagmi-connector \
wagmi viem @tanstack/react-query
Dynamic documents wagmi compatibility up to v3.1.0. If you hit connector issues, pin wagmi to a version Dynamic supports and test before upgrading.
Create the wagmi config at module scope (not inside a component). Set multiInjectedProviderDiscovery: false — Dynamic handles injected provider discovery itself.
// wagmi.config.ts
import { createConfig, http } from 'wagmi'
import { base, mainnet } from 'viem/chains'
export const wagmiConfig = createConfig({
chains: [base, mainnet],
multiInjectedProviderDiscovery: false,
transports: {
[base.id]: http(),
[mainnet.id]: http(),
},
})
Include every chain you enable in the Dynamic dashboard. Dynamic no longer auto-syncs chains into your wagmi config — you declare them explicitly in both places.
2. Wrap the app
DynamicWagmiConnector keeps Dynamic’s active wallet in sync with wagmi. The user connects through DynamicWidget before using the Trails widget.
// App.tsx
import { DynamicContextProvider, DynamicWidget } from '@dynamic-labs/sdk-react-core'
import { EthereumWalletConnectors } from '@dynamic-labs/ethereum'
import { DynamicWagmiConnector } from '@dynamic-labs/wagmi-connector'
import { WagmiProvider } from 'wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { wagmiConfig } from './wagmi.config'
import { Checkout } from './Checkout'
const queryClient = new QueryClient()
export function App() {
return (
<DynamicContextProvider
settings={{
environmentId: 'YOUR_DYNAMIC_ENVIRONMENT_ID',
walletConnectors: [EthereumWalletConnectors],
}}
>
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<DynamicWagmiConnector>
<DynamicWidget />
<Checkout />
</DynamicWagmiConnector>
</QueryClientProvider>
</WagmiProvider>
</DynamicContextProvider>
)
}
Define adapters once at module scope. Pass the same wagmiConfig instance you use in WagmiProvider, or call wagmiAdapter() with no options to auto-bridge into the surrounding provider.
// Checkout.tsx
import { Fund } from '0xtrails/widget'
import { wagmiAdapter } from '@0xtrails/adapter-wagmi'
import { useAccount } from 'wagmi'
import { wagmiConfig } from './wagmi.config'
const adapters = [wagmiAdapter({ wagmiConfig })]
export function Checkout() {
const { isConnected } = useAccount()
if (!isConnected) {
return <p>Connect with Dynamic first.</p>
}
return (
<Fund
apiKey="YOUR_TRAILS_API_KEY"
adapters={adapters}
to={{ chain: "polygon", token: "USDC", amount: "100", recipient: "0x..." }}
/>
)
}
That’s the full integration — Dynamic connects the embedded wallet, wagmi holds the session, and Trails signs through wagmiAdapter.
Tips
- Keep config stable — define
wagmiConfig and adapters at module scope (or memoize them). Recreating them on every render remounts the wallet runtime.
- Connect before the widget — the Trails widget expects an active wagmi session. Use
DynamicWidget (or your own Dynamic login flow) first.
- Match chains — chains in
wagmiConfig, the Dynamic dashboard, and your Trails destination chain should align.