@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:
| Member | Notes |
|---|---|
base | Spread 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.