# EVM-only setup (/guides/evm-only)



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 [#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`.

<CodeBlockTabs defaultValue="npm" groupId="package-manager">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npm install @usebutr/react @usebutr/evm @usebutr/core zustand
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm add @usebutr/react @usebutr/evm @usebutr/core zustand
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn add @usebutr/react @usebutr/evm @usebutr/core zustand
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun add @usebutr/react @usebutr/evm @usebutr/core zustand
    ```
  </CodeBlockTab>
</CodeBlockTabs>

## Provider [#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.

```tsx title="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)](/getting-started/frameworks/nextjs).

## The bundle guarantee [#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](/concepts/platforms).

## Chains [#chains]

Pull the chain list from `@usebutr/evm` directly. `CHAINS_BY_PLATFORM` from
`@usebutr/wallets` would re-introduce the bundle you just avoided.

```tsx
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 [#capabilities-and-caveats]

`@usebutr/evm` discovers wallets via [EIP-6963](https://eips.ethereum.org/EIPS/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`](/concepts/capabilities) rather
than assuming a wallet supports an operation.

## Next steps [#next-steps]

* [Injected EVM connector](/connectors/injected-evm) — the discovery and
  injected-fallback detail.
* [viem integration](/integrations/viem) /
  [wagmi integration](/integrations/wagmi) — build and send transactions.
* [Provider setup](/guides/provider-setup) — auto, manual, and composed
  variants.
* [Next.js (App Router)](/getting-started/frameworks/nextjs) — the RSC `"use client"`
  boundary.

<Callout type="info">
  **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](https://github.com/pedroapfilho/usebutr).
</Callout>
