EVM-only setup
Ship @usebutr/react + @usebutr/evm with no @usebutr/svm or @usebutr/wallets in the bundle.
Pick this path when your app only touches EVM chains — a viem, wagmi, or ethers
app with no Solana surface. You import @usebutr/evm for discovery instead of
autoDiscovery() from @usebutr/wallets, and the Solana packages never enter your
bundle. Nothing else about the provider or hooks changes.
Install
@usebutr/react gives you the provider and hooks, @usebutr/evm does EIP-6963
discovery, and createWalletSource comes from @usebutr/core. No @usebutr/wallets,
no @usebutr/svm.
npm install @usebutr/react @usebutr/evm @usebutr/core zustandProvider
Build the WalletSource with createWalletSource from @usebutr/core and
discoverEvmAdapters from @usebutr/evm. Hoist it to module scope so it is created
once, not on every render.
import type { ReactNode } from "react";
import { createWalletSource } from "@usebutr/core";
import { WalletManagerProvider, useDiscoveredWallets } from "@usebutr/react";
import { discoverEvmAdapters } from "@usebutr/evm";
// EVM-only: @usebutr/react + @usebutr/evm. No @usebutr/svm / @usebutr/wallets in the
// bundle — discovery is a WalletSource built from the EVM discoverer.
const evmDiscovery = createWalletSource(discoverEvmAdapters);
const WalletProvider = ({ children }: { children: ReactNode }) => (
<WalletManagerProvider discovery={evmDiscovery} storageKeyPrefix="butr-demo">
{children}
</WalletManagerProvider>
);
export { WalletProvider, useDiscoveredWallets };demo-with-viem, demo-with-wagmi, demo-next, and demo-tanstack-start all
use exactly this pattern. They re-export useDiscoveredWallets from the local
wallet-provider module so consuming files import it from one place.
On Next.js the same module needs a "use client" directive at the top — see
Next.js (App Router).
The bundle guarantee
The isolation is not a flag — it is your import graph. @usebutr/evm depends only
on @usebutr/core; it carries no Wallet Standard or Solana code. autoDiscovery()
lives in @usebutr/wallets, which depends on both @usebutr/evm and @usebutr/svm, so
importing it would pull Solana in. Here you import discoverEvmAdapters from
@usebutr/evm directly, so @usebutr/svm and @usebutr/wallets are never referenced and
the bundler tree-shakes them out ("sideEffects": false is set on every
package). See Platforms.
Chains
Pull the chain list from @usebutr/evm directly. CHAINS_BY_PLATFORM from
@usebutr/wallets would re-introduce the bundle you just avoided.
import { EVM_CHAINS_LIST } from "@usebutr/evm";
const CHAINS_BY_PLATFORM = { evm: EVM_CHAINS_LIST, svm: [] as const };EVM_CHAINS (keyed: ethereum, sepolia, arbitrum, optimism, base,
polygon, bsc) and EVM_CHAINS_LIST (the same as an array) are both exported
from @usebutr/evm. butr itself never reads this list — it is for your
chain-switcher UI. Connector.switchChain accepts any ChainBase.
Capabilities and caveats
@usebutr/evm discovers wallets via EIP-6963,
the standard where wallets announce themselves through window events instead of
fighting over window.ethereum. Some regional or legacy wallets only expose a
raw EIP-1193 window.ethereum and never announce; discoverInjectedAdapter
(also from @usebutr/evm) is the last-resort fallback for those.
EVM connectors switch chains for real via wallet_switchEthereumChain.
Capability values are derived from the wallet's EIP-6963 provider info — always
branch on wallet.connector.capabilities rather
than assuming a wallet supports an operation.
Next steps
- Injected EVM connector — the discovery and injected-fallback detail.
- viem integration / wagmi integration — build and send transactions.
- Provider setup — auto, manual, and composed variants.
- Next.js (App Router) — the RSC
"use client"boundary.
Source: apps/demo-with-viem/src/wallet-provider.tsx,
apps/demo-with-wagmi/src/wallet-provider.tsx, and apps/demo-next/src/wallet-provider.tsx in
the butr repository.