butr
Guides

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 zustand

Provider

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.

src/wallet-provider.tsx
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

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.

On this page