butr
Connectors

Overview

Every connector reaches butr through config.sources, discovered or built, and defines only the methods that work for it.

A connector is a WalletAdapter. Every one reaches the manager through config.sources, in one of two ways:

  • Discovered: browser wallets announce themselves. @usebutr/evm listens for EIP-6963; @usebutr/svm, @usebutr/sui and @usebutr/bitcoin listen for the Wallet Standard; @usebutr/bitcoin also probes injected providers such as window.unisat; @usebutr/polkadot reads window.injectedWeb3. autoDiscovery() from @usebutr/wallets composes all of them, and each discover*Adapters export is a source on its own.
  • Built: WalletConnect and Ledger are not injected into the page. Their factories resolve adapters, and fromAdapters from @usebutr/core turns an adapter, a list of them, or a promise of either into a source.

Both kinds land in useDiscoveredWallets() and connect the same way.

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";

const config: WalletManagerConfig = {
  sources: [
    autoDiscovery(),
    fromAdapters(
      createWalletConnectAdapters({
        namespaces: { evm: [] },
        onPairingUri: showQr,
        projectId: "<your Reown project id>",
      }),
    ),
    fromAdapters(createLedgerAdapter({ platform: "evm" })),
  ],
};

export const Providers = ({ children }: { children: React.ReactNode }) => (
  <WalletManagerProvider config={config}>{children}</WalletManagerProvider>
);

Give each factory its own fromAdapters: a rejected promise is logged and contributes nothing, so one factory that fails never hides the others. The first adapter announced for an id wins.

ConnectorPackagePlatformsReaches butr throughSigner kind
Injected EVM@usebutr/evmevmEIP-6963, window.ethereum fallbackeip1193
Solana Wallet Standard@usebutr/svmsvmWallet Standardwallet-standard
Sui Wallet Standard@usebutr/suisuiWallet Standardwallet-standard
Bitcoin@usebutr/bitcoinbitcoinWallet Standard, injected fallbackswallet-standard, unisat, sats-connect
Polkadot@usebutr/polkadotpolkadotinjectedWeb3, Wallet Standard fallbackpolkadot-injected, wallet-standard
WalletConnect@usebutr/walletconnectevm svm sui bitcoinfromAdapterseip1193 (EVM), walletconnect
Ledger@usebutr/ledgerevm svm sui bitcoinfromAdaptersledger-evm, ledger-svm, ledger-sui, ledger-bitcoin

What each connector defines

A method exists only when calling it can succeed for that wallet, so check it before calling. ✓ means always, a feature name means only when the wallet advertises it.

MethodInjected EVMWallet Standard (SVM, Sui, BTC)Unisat-styleXversePolkadot injectedWalletConnect EVMWalletConnect SVM, Sui, BTCLedger
signMessage✓its feature✓✓after connect, with signRaw✓✓not on Sui
sendTx✓its featurewith sendBitcoin✓✓✓
signTransactionits feature✓✓✓not on EVM
signInsolana:signIn
switchChain✓2+ chains advertisedwith switchNetwork✓✓2+ chains configured
requestAccounts✓
getBalance✓✓
getTransactionReceipt✓✓
subscribe✓✓with on✓after connect, with accounts.subscribe✓✓
disconnect✓standard:disconnect✓✓✓✓✓

Polkadot's Wallet Standard adapters follow the Wallet Standard column, with signMessage behind polkadot:signMessage and never sendTx or signTransaction.

Chains and accounts

sendTx and signTransaction take { account, chain }. What a transport does with a chain that is not its current one depends on what the wallet can do:

TransportA different chainswitchChain
Injected EVM, WalletConnect EVMSwitches the wallet's network first (wallet_switchEthereumChain), then sends.Switches the wallet's network.
Wallet StandardRoutes that one call; the wallet must advertise the chain.Re-points butr's view; the wallet is not asked.
WalletConnect SVM, Sui, BTCRoutes that one call; the session must have approved the chain.Re-points butr's view to another approved chain.
Unisat, XverseSwitches the wallet's network first, or rejects with ChainMismatch when it cannot.Switches the wallet's network, where the provider can.
LedgerRejects with ChainMismatch: build one adapter per chain.None.
PolkadotNot applicable: no sendTx, and signMessage takes no chain.Wallet Standard only, with 2+ chains advertised.

An account the wallet does not expose rejects everywhere. No adapter falls back to its first account.