butr
Guides

Provider setup

One WalletManagerProvider and one config: auto-discovery, a single platform, built adapters, or all of them.

There is one provider: WalletManagerProvider from @usebutr/react. It takes a config of type WalletManagerConfig from @usebutr/core, and an optional initialState for server rendering.

The provider creates one manager per mount and reads config once, at that moment. Define it at module scope: a config built during render is ignored on every later render, and so are callbacks that close over component state.

Auto (batteries-included)

Put autoDiscovery() from @usebutr/wallets in sources. It discovers EVM (EIP-6963), SVM, Sui, and Bitcoin (Wallet Standard), and Polkadot (injectedWeb3) wallets. State persists to localStorage under storageKeyPrefix.

src/wallet-provider.tsx
import type { WalletManagerConfig } from "@usebutr/core";
import { WalletManagerProvider } from "@usebutr/react";
import { autoDiscovery } from "@usebutr/wallets";
import type { ReactNode } from "react";

const config: WalletManagerConfig = {
  sources: [autoDiscovery()],
  storageKeyPrefix: "butr-demo",
};

const WalletProvider = ({ children }: { children: ReactNode }) => (
  <WalletManagerProvider config={config}>{children}</WalletManagerProvider>
);

export { WalletProvider };

autoDiscovery takes an optional platform list and options:

autoDiscovery(["evm", "svm"]); // only these platforms
autoDiscovery(undefined, { fallbacks: false }); // skip window.ethereum, injected Bitcoin, Polkadot Wallet Standard

Platform-only bundles

Every discover*Adapters export is a wallet source as-is, so a single-platform app passes it straight into sources and never imports @usebutr/wallets:

import type { WalletManagerConfig } from "@usebutr/core";
import { discoverEvmAdapters } from "@usebutr/evm";

const config: WalletManagerConfig = { sources: [discoverEvmAdapters] };

Each has a complete path, including install, chains, and platform caveats:

Adding WalletConnect and Ledger

Some adapters are built rather than discovered. fromAdapters from @usebutr/core turns one adapter, several, or a promise of either into a source, so they sit next to discovery in sources and show up in useDiscoveredWallets() like any other wallet:

src/wallet-provider.tsx
import type { WalletManagerConfig } from "@usebutr/core";
import { fromAdapters } from "@usebutr/core";
import { createLedgerAdapter } from "@usebutr/ledger";
import { WalletManagerProvider } from "@usebutr/react";
import { autoDiscovery } from "@usebutr/wallets";
import { createWalletConnectAdapters } from "@usebutr/walletconnect";
import type { ReactNode } from "react";

import { showPairingQr } from "./pairing";

const config: WalletManagerConfig = {
  sources: [
    autoDiscovery(),
    fromAdapters(
      createWalletConnectAdapters({
        metadata: { name: "My dapp", url: "https://my-dapp.example" },
        namespaces: { evm: ["eip155:1"], svm: [] },
        onPairingUri: showPairingQr,
        projectId: "<your Reown project id>",
      }),
    ),
    fromAdapters(createLedgerAdapter({ id: "ledger-evm", platform: "evm" })),
  ],
  storageKeyPrefix: "my-app",
};

const WalletProvider = ({ children }: { children: ReactNode }) => (
  <WalletManagerProvider config={config}>{children}</WalletManagerProvider>
);

export { WalletProvider };

A promise that rejects is logged and contributes nothing, so a missing peer dependency or project id leaves the rest of the picker intact. If two sources announce the same id, the first one wins.

See WalletConnect and Ledger for their options.

Other config fields

FieldDefaultPurpose
sources[]where adapters come from
storageKeyPrefix"butr"namespaces the default storage keys
storagelocalStorage + sessionStoragea custom WalletPersistence
onConnect, onConnectError, onDisconnect, onHydrated, onSlowConnect, onStorageError—lifecycle callbacks
slowConnectThresholdMs5000when onSlowConnect fires

Without React

The provider is a thin binding over createWalletManager. Anything else calls it directly with the same config:

import { createWalletManager } from "@usebutr/core";

const manager = createWalletManager(config);
const stop = manager.start(); // discovery, hydration, wallet events

Source: apps/demo-vite/src/wallet-provider.tsx (auto discovery plus WalletConnect and Ledger) in the butr repository.