# WalletConnect (/connectors/walletconnect)



`@usebutr/walletconnect` is a WalletConnect v2 adapter for **mobile** wallets
(Trust, Rainbow, Argent, Zerion, MetaMask Mobile, Phantom Mobile, Slush, Magic
Eden, …). It is not browser-injected — you build the adapter once and register
it through `createConnector`.

It ships namespace builders for all four `ChainPlatform` variants — `eip155`
(EVM), `solana` (SVM), `sui`, and `bip122` (Bitcoin) — and a multi-namespace
factory so a single pairing can hand back one adapter per platform.

## Install [#install]

<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/walletconnect @walletconnect/universal-provider
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm add @usebutr/walletconnect @walletconnect/universal-provider
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn add @usebutr/walletconnect @walletconnect/universal-provider
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun add @usebutr/walletconnect @walletconnect/universal-provider
    ```
  </CodeBlockTab>
</CodeBlockTabs>

`@walletconnect/universal-provider` is an optional peer dependency; the adapter
dynamically imports it, so it never bloats your bundle unless used.

## Build the adapter [#build-the-adapter]

```ts
import { createWalletConnectAdapters } from "@usebutr/walletconnect";

const wcs = await createWalletConnectAdapters({
  projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID!,
  metadata: { name: "My dapp", url: "https://my-dapp.example" },
  namespaces: {
    evm: ["eip155:1", "eip155:137"],
    svm: ["solana:mainnet"],
    sui: ["sui:mainnet"],
    bitcoin: ["bip122:000000000019d6689c085ae165831e93"],
  },
  onPairingUri: (uri) => setQrUri(uri),
});
```

`createWalletConnectAdapters(options)` returns `Promise<Array<WalletAdapter>>`
— one per requested namespace, all sharing the same paired session. When more
than one namespace is requested, each adapter's id is suffixed with the
platform (`walletconnect-evm`, `walletconnect-svm`, …) so they coexist in
butr's pool. With a single namespace, the id stays the base
`options.id ?? "walletconnect"`.

Pass an empty array for a platform to use the namespace builder's default
chains. Omit a key entirely to skip that platform.

### Options [#options]

| Option         | Type                                                    | Notes                                                                                                     |
| -------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `projectId`    | `string` (required)                                     | From [Reown Cloud](https://cloud.reown.com).                                                              |
| `namespaces`   | `Partial<Record<ChainPlatform, ReadonlyArray<string>>>` | Per-platform CAIP-2 chain map. Omit a key to skip the namespace; empty array uses defaults.               |
| `metadata`     | `{ name?; url?; description?; icons? }`                 | Shown in the mobile wallet during pairing. &#x2A;*Some wallets refuse to pair without `name` and `url`.** |
| `onPairingUri` | `(uri: string) => void`                                 | Fires when a QR / deep link must be shown.                                                                |
| `id`           | `string`                                                | Adapter id base. Default `"walletconnect"`. Suffixed with `-<platform>` when multi-namespace.             |
| `name`         | `string`                                                | Display name. Default `"WalletConnect"`.                                                                  |
| `icon`         | `string`                                                | Override icon (`WALLETCONNECT_DEFAULT_ICON` is the fallback).                                             |

## Register it [#register-it]

The adapter is fully formed but **un-paired** — pairing happens when butr's
runtime calls `adapter.connect()` (when the user clicks "Connect"). Build the
adapter once at module scope, then pass it through the unified provider:

```tsx
import { WalletManagerProvider } from "@usebutr/react";
import { autoDiscovery } from "@usebutr/wallets";
import { createWalletConnectAdapters } from "@usebutr/walletconnect";

const discovery = autoDiscovery();
const wcs = await createWalletConnectAdapters({
  projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID!,
  namespaces: { evm: ["eip155:1"], svm: ["solana:mainnet"] },
  onPairingUri: (uri) => setQrUri(uri),
});
const extra = new Map(wcs.map((a) => [a.id, a] as const));

<WalletManagerProvider
  discovery={discovery}
  connectors={wcs.map((a) => ({ id: a.id, name: a.name, chainPlatform: a.chainPlatform }))}
  createConnector={(id) => extra.get(id) ?? null}
>
  {children}
</WalletManagerProvider>;
```

Build the adapter **once at app boot**, cache it, and re-register on each
mount. butr's hydration reconnects through the same session if it's still live
on the relay.

## Rendering the QR [#rendering-the-qr]

<Callout type="warn">
  butr ships **no** QR renderer. `onPairingUri` hands you the URI string; you render it
  (`@walletconnect/modal`, a `qrcode` lib, or your own UI). On mobile, forward it to
  `window.location` to trigger the OS wallet picker.
</Callout>

## Namespace builders [#namespace-builders]

Each platform's RPC shape lives in its own builder. The package exports them so
you can compose your own factory if needed:

```ts
import {
  KNOWN_NAMESPACES,
  bitcoinNamespace,
  evmNamespace,
  solanaNamespace,
  suiNamespace,
} from "@usebutr/walletconnect";
```

`KNOWN_NAMESPACES` is the registry `createWalletConnectAdapters` dispatches
through — keyed by `ChainPlatform`. Adding a fifth platform is three touches:
write a builder under `src/namespaces/<platform>.ts`, add an entry to
`KNOWN_NAMESPACES`, and re-export it.

## Capabilities & caveats [#capabilities--caveats]

Per-namespace capabilities are fixed once paired. Each builder exposes its
own constant:

```ts
import {
  WALLETCONNECT_CAPABILITIES, // EVM — single-platform factory uses this
  WALLETCONNECT_BITCOIN_CAPABILITIES,
  WALLETCONNECT_SUI_CAPABILITIES,
  WALLETCONNECT_SVM_CAPABILITIES,
} from "@usebutr/walletconnect";
```

| Capability              | EVM | SVM | Sui | Bitcoin | Notes                                                                  |
| ----------------------- | :-: | :-: | :-: | :-----: | ---------------------------------------------------------------------- |
| `signMessage`           |  ✓  |  ✓  |  ✓  |    ✓    | EVM: EIP-191/712; SVM: bytes; Sui: personal message; BTC: BIP-322-ish. |
| `sendTransaction`       |  ✓  |  ✓  |  ✓  |    ✓    | BTC routes through `bip122:signPsbt` with `broadcast: true`.           |
| `signTransaction`       |     |     |  ✓  |    ✓    | Sui: raw tx bytes; BTC: PSBT round-trip.                               |
| `switchChain`           |  ✓  |  ✓  |  ✓  |         | BTC: switching network ≈ re-pair.                                      |
| `requestAccounts`       |     |     |     |         | No EIP-2255 equivalent — "more accounts" means re-pairing.             |
| `switchAccount`         |     |     |     |         | Pick the account in the mobile wallet.                                 |
| `subscribe`             |  ✓  |  ✓  |  ✓  |    ✓    | Relayed via session events (`accountsChanged`, `chainChanged`, …).     |
| `getBalance`            |  ✓  |     |     |         | EVM: via the relay's `eth_getBalance`. Others have no RPC contract.    |
| `getTransactionReceipt` |  ✓  |     |     |         | Same.                                                                  |

* Changing the account set means tearing down the session and re-pairing.
* Session events (`accountsChanged`, `chainChanged`, `disconnect`) are relayed
  through `adapter.subscribe()` automatically.
* **Bitcoin RPC spec is unstable.** The `bip122` namespace follows
  [Reown's reference](https://docs.reown.com/advanced/multichain/rpc-reference/bitcoin-rpc).
  Method names and response shapes still drift between wallets.

<Callout type="info">
  **Source:** `packages/walletconnect/src` (`adapter.ts`, `capabilities.ts`,
  `namespaces/{evm,svm,sui,bitcoin}.ts`) in the [butr
  repository](https://github.com/pedroapfilho/usebutr/tree/main/packages/walletconnect).
</Callout>
