butr
API reference

@usebutr/wallet-standard-shared

Wallet Standard discovery, the adapter core every Wallet Standard adapter shares, and getFeature.

The layer @usebutr/svm, @usebutr/sui, @usebutr/bitcoin and @usebutr/polkadot build on. App code usually needs only getFeature and findAccount; the rest is for adapter authors. No React dependency.

npm install @usebutr/wallet-standard-shared @wallet-standard/app zustand

@wallet-standard/app is an optional peer in the manifest, but the default discovery loader needs it; a custom loader can supply a registry for tests. @usebutr/wallets installs it for you.

Signer

Importing the package registers the wallet-standard signer kind, so every adapter built on it resolves getSigner() to { kind: "wallet-standard", wallet: WalletStandardWallet }.

Features

getFeature<Feature>(wallet, name, method): (WalletStandardFeature & Feature) | undefined

The spec keys features by name with no fixed shape, so the caller names the feature type and the method that proves it. undefined when the wallet does not advertise the feature or the method is missing. No cast needed:

import type { SolanaSignMessageFeature } from "@usebutr/svm";
import { findAccount, getFeature } from "@usebutr/wallet-standard-shared";

const signer = await wallet.connector.getSigner();
if (signer.kind === "wallet-standard") {
  const feature = getFeature<SolanaSignMessageFeature>(
    signer.wallet,
    "solana:signMessage",
    "signMessage",
  );
  const account = findAccount(signer.wallet.accounts, wallet.account.walletAddress);
  if (feature && account) {
    const [output] = await feature.signMessage({ account, message });
  }
}

The returned feature is the wallet's own object, so its methods keep their this.

findAccount(accounts, address): WalletStandardWalletAccount | undefined

The Wallet Standard account for a butr address. undefined for an address the wallet does not expose, never another account in its place.

Adapter authoring

slugify(platformPrefix, name): string

wallet-standard:<prefix>-<slug>, e.g. slugify("svm", "Phantom") is wallet-standard:svm-phantom. The prefix gives a multi-chain wallet one id per platform.

createWalletStandardCore(input): WalletStandardCore | null

The members every Wallet Standard adapter shares. null when the wallet advertises no chain in input.namespace or lacks standard:connect.

WalletStandardCoreInput: chains (the platform's registry, for names), id, label ("Solana", for errors), namespace ("solana"), preferredChainIds, registerDisconnector?, trackChainChanges, wallet.

WalletStandardCore:

MemberNotes
baseSpread into the adapter: connect, getAccounts, getSigner, icon, id, name, plus disconnect, subscribe and switchChain when supported. Account reads and events include only accounts advertising the selected chain.
resolveTarget(feature, options?)Returns { account, chain } together. Selects the requested account, or the first account supporting the target chain and operation feature. Rejects unsupported targets.
toAccount(rawAccount)Builds an Account on the current chain after checking the raw account advertises it, including sign-in results.
currentChain()The active registry chain.

options accepts account and chain. Chain matching recognizes registry aliases; returned accounts retain their original Wallet Standard records, and chain uses the wallet's advertised spelling. Switching changes the scoped account view.

import type { SvmAdapter } from "@usebutr/core";
import { SVM_CHAINS_LIST } from "@usebutr/core";
import type { WalletStandardWallet } from "@usebutr/wallet-standard-shared";
import { createWalletStandardCore, slugify } from "@usebutr/wallet-standard-shared";

export const buildAdapter = (wallet: WalletStandardWallet): SvmAdapter | null => {
  const core = createWalletStandardCore({
    chains: SVM_CHAINS_LIST,
    id: slugify("svm", wallet.name),
    label: "Solana",
    namespace: "solana",
    preferredChainIds: ["solana:mainnet"],
    trackChainChanges: true,
    wallet,
  });
  return core === null ? null : { ...core.base, chainPlatform: "svm" };
};

discoverWalletStandard(routes, { loadModule?, onReady? }): () => void

Loads the registry once and feeds every route from that one subscription. Each WalletStandardRoute is { build, onAdapter }: build turns a registered wallet into an adapter or null, and onAdapter receives each new id once. unregister becomes a disconnected event on that wallet's adapters. onReady runs once the wallets already registered are routed, or once the module failed to load. A missing @wallet-standard/app logs one warning and disables discovery. WalletStandardAdapterBuilder is (wallet, registerDisconnector) => WalletAdapter | null.

Types

WalletStandardWallet, WalletStandardWalletAccount, WalletStandardFeature, StandardConnectFeature, StandardDisconnectFeature, StandardEventsFeature, StandardEventsListener, WalletsApp, WalletStandardAppModule, WalletStandardModuleLoader, WalletStandardCore, WalletStandardCoreInput, WalletStandardAdapterBuilder, WalletStandardRoute.

See the Solana, Sui, Bitcoin, and Polkadot packages for complete adapters.

Source: packages/wallet-standard-shared/src/index.ts.