Update here:
So here’s the current state of things:
Pat’s spec simply referred to as “WalletConnect” (WalletConnect + Paytaca Connector interface) has been implemented in 3 BCH wallets: Cashonize, Zapit and Paytaca.
The protocol is used by multiple dapps: Tapswap, CashTokens Studio, Cash-Ninjas mint with a few more in the works
Jim’s spec called “CashConnect” (WalletConnect + CashRPC) has been merged into mainline Cashonize but the spec is still marked as pre-alpha.
CashConnect is used by the BCH Guru price prediction game and by the CashRPC IDE
And then there is still the custom Paytaca Connect which is used by the bitcats and available as a 2nd option in the CashTokens studio. Paytaca connect was used by the Paytaca browser extension and was pioneering wallet connect functionality on BCH. Now it can be phased out, as Pat’s wallet connect spec is more general than for just browser extensions.
Without really knowing too much about it, I was impressed by Pat’s spec, and have been blown away by Jim’s spec, even at this early stage. The Guru beta is amazing. Can’t wait until we have that implemented across the ecosystem, and this is only the early version (a bit of work on just the UI to have more helpful links and info would already be a big step forward).
I maintain a list of BCH walletConnecta apps at Tokenaut.cash, it has been growing steadily through-out 2024, so the protocol is positioned to play an important role on BCH going forward.
There is a 4th wallet with support for BCH Wallet Connect on the way: Electron Cash. It will have WalletConnect support through an EC plugin but this is planned to be merged into the mainline wallet eventually.
In the Elecron Cash group the developer, ‘OPReturn’, wrote:
I think the alpha version for WalletConnect plugin for EC is almost ready. Doing final testings. Hopefully I’ll be able to do a release this week.
There’s now 10 dapps using the BCH WalletConnect protocol
The WalletConnect plugin Electron Cash also has been released in alpha version by now so that means 4 supporting wallets (link to the plugin)
Paytaca Connect is also being deprecated as a separate standard and will shortly be removed from Tapswap and from the CashTokens Studio as a user-option.
This means there is strong standardization of the BCH ecosystem around the WalletConnect standard which is great news for users and developers.
CashScript now also has a WalletConnect guide for contract developers to get started using the standard in their dapps.
has anyone been able to migrate from the deprecated “@walletconnect/modal” library?
Cashonize and Selene are using @reown/walletkit and @walletconnect/core:
Selene reference (basically a direct rip from Cashonize adapted for Selene’s architecture):
There’s this recent migration blogpost by Reown for the deprecated @walletconnect/modal library: WalletConnect Modal to Reown AppKit Core - Reown Docs
It seems the new library is @reown/appkit/core and you create the modal with a createAppKit function. The styling of the modal also seems to have changed somewhat.
@kzKallisti those are the libraries on the wallet side, Dagur as an app dev is asking about the libraries for the dapp side (the modal library used to display the walletconnect qr code)
oops my bad, thanks for the correction 
I have created @bch-wc2/interfaces and @bch-wc2/privkey-connector packages.
@bch-wc2/interfaces formalizes the specced interfaces and allows to import them to create signTransaction requests such as those in cashscript and in mainnet-js (see https://github.com/mainnet-cash/mainnet-js/releases/tag/2.7.7)
@bch-wc2/privkey-connector is a small piece of code which utilizes a private key to sign the WC2 requests locally, it is super important part for local development and automated testing.
See the repository https://github.com/mainnet-pat/bch-wc2
I was able to use the latest WalletConnect/AppKit libraries, not to migrate, but to start a new dApp implementation.
I haven’t tested everything, but pairing, getting the addresses, and signing a transaction already works. It also doesn’t support the custom wallets like Paytaca like the original reference, but I’ll try adding that eventually.
Set up
// config.ts
import type { AppKitNetwork } from "@reown/appkit/networks";
import type { InferredCaipNetwork } from "@reown/appkit-common";
import UniversalProvider from "@walletconnect/universal-provider";
import { AppKit, createAppKit } from "@reown/appkit/core";
export const projectId = process.env.NEXT_PUBLIC_REOWN_PROJECT_ID;
// you can configure your own network
const bch: InferredCaipNetwork = {
id: "bch",
chainNamespace: "bch" as const,
caipNetworkId: "bch:bitcoincash",
name: "Bitcoin Cash",
nativeCurrency: { name: "Bitcoin Cash", symbol: "BCH", decimals: 8 },
rpcUrls: { default: { http: [] } },
};
export const networks = [bch] as [AppKitNetwork, ...AppKitNetwork[]];
let provider: UniversalProvider | undefined;
let modal: AppKit | undefined;
export async function initializeProvider() {
if (!provider) {
provider = await UniversalProvider.init({
projectId,
metadata: {
name: "Project name",
description: "Project description",
url: "https://example.com",
icons: ["https://example.com/favicon.ico"],
},
});
}
return provider;
}
export function initializeModal(universalProvider?: UniversalProvider) {
if (!projectId) {
throw new Error("Project ID is not defined");
}
if (!modal && universalProvider != null) {
modal = createAppKit({
projectId,
networks,
/* @ts-expect-error https://docs.reown.com/appkit/next/core/installation#others-networks-appkit-core-2 */
universalProvider,
manualWCControl: true,
features: {
analytics: true, // Optional - defaults to your Cloud configuration
},
});
}
return modal;
}
// Provider.tsx
"use client";
import React, {
useState,
useEffect,
PropsWithChildren,
useContext,
} from "react";
import { initializeProvider, initializeModal } from "./config"; // previous config file
import UniversalProvider from "@walletconnect/universal-provider";
const requiredNamespaces = {
bch: {
chains: ["bch:bitcoincash"],
methods: ["bch_getAddresses", "bch_signTransaction", "bch_signMessage"],
events: ["addressesChanged"],
},
};
interface Context {
provider: UniversalProvider | null;
session: UniversalProvider["session"] | null;
isLoading: boolean;
isInitialized: boolean;
connect: () => void;
disconnect: () => void;
addresses: string[] | null;
}
const AppKitContext = React.createContext<Context>({
provider: null,
session: null,
addresses: null,
isLoading: false,
isInitialized: false,
connect: () => {},
disconnect: () => {},
});
export const useAppKit = () => useContext(AppKitContext);
export function AppKitProvider(props: PropsWithChildren) {
const [isInitialized, setIsInitialized] = useState(false);
const [provider, setProvider] = useState<Context["provider"]>(null);
const [session, setSession] = useState<Context["session"]>(null);
const [isLoading, setIsLoading] = useState(false);
const [addresses, setAddresses] = useState<string[] | null>(null);
// Initialize the Provider and AppKit on component mount, and check for existing session
useEffect(() => {
const init = async () => {
const dataProvider = await initializeProvider();
setProvider(dataProvider);
const modal = initializeModal(dataProvider);
modal?.subscribeEvents(({ data }) => {
switch (data.event) {
case "MODAL_OPEN":
setIsLoading(false);
default:
return;
}
});
if (dataProvider.session) {
// check if there is a session
setSession(dataProvider.session);
}
setIsInitialized(true);
};
init();
}, []);
useEffect(() => {
if (session == null || provider == null || isInitialized === false) return;
(async () => {
try {
const addresses = (await provider.client.request({
chainId: "bch:bitcoincash",
topic: session.topic,
request: {
method: "bch_getAddresses",
params: {},
},
})) as string[];
setAddresses(addresses);
} catch (e) {
console.error(e);
}
})();
}, [session, provider, isInitialized]);
useEffect(() => {
// Handler for when WalletConnect generates a connection URI
// Opens the AppKit modal with the URI and shows the connecting view
if (provider == null) return;
const handleDisplayUri = (uri: string) => {
const modal = initializeModal(provider);
modal?.open({ uri, view: "ConnectingWalletConnectBasic" });
};
// Handler for when a wallet successfully connects
// Updates the session state and closes the modal
const handleConnect = async ({
session,
}: {
session: Context["session"];
}) => {
setSession(session);
const modal = initializeModal(provider);
await modal?.close();
};
const handleDisconnect = async () => {
setSession(null);
};
// Subscribe to WalletConnect events
provider?.on("display_uri", handleDisplayUri); // Listen for connection URI
provider?.on("connect", handleConnect); // Listen for successful connections
provider?.on("disconnect", handleDisconnect);
return () => {
provider?.removeListener("display_uri", handleDisplayUri);
provider?.removeListener("connect", handleConnect);
provider?.removeListener("disconnect", handleDisconnect);
};
}, [provider]);
const connect = async () => {
setIsLoading(true);
try {
if (!provider) {
throw new Error("Provider is not initialized");
}
await provider.connect({
namespaces: requiredNamespaces,
});
} catch (error) {
console.error("Failed to connect:", error);
} finally {
setIsLoading(false);
}
};
const disconnect = async () => {
setIsLoading(true);
try {
if (!provider) {
throw new Error("Provider is not initialized");
}
await provider.disconnect();
} catch (error) {
console.error("Failed to disconnect:", error);
} finally {
setSession(null);
setIsLoading(false);
}
};
return (
<AppKitContext.Provider
{...props}
value={{
provider,
session,
isLoading,
connect,
disconnect,
isInitialized,
addresses,
}}
/>
);
}
Usage
const {
connect,
disconnect,
addresses,
isLoading,
isInitialized,
session
} = useAppKit();
// open modal
connect()
// request transaction signature
await provider.client.request({
chainId: "bch:bitcoincash",
topic: session?.topic,
request: {
method: "bch_signTransaction",
params: JSON.parse(stringify(wcTransactionObj)),
},
});
I built a React library to make wallet integration in Bitcoin Cash dApps effortless, implementing wc2-bch-bcr with the latest version of Reown AppKit (instead of the deprecated walletconnect packages). It’s inspired by RainbowKit and wagmi, which provide a seamless DX.
I aim to bring that DX to BCH dApp development, making wallet connection integration as simple as:
- Install the npm package
- Set the corresponding provider
- Use the features through your app (connect, address, signTransaction, signMessage, etc.)
Just like RainbowKit does.
I’ve shipped a minimal working version of bch-connect, which is already published on npm, thoroughly documented in the repository README, and with a live example using it.
I still need to write test suites, and it likely still contains a lot of bugs and issues. But I’ll be working on improving it and eventually scaling it (for instance, adding support for cashconnect). I’ve never maintained a library before, so any feedback and criticism is very welcome.
The wallets I know currently work fine are Cashonize (web) and Zapit. Paytaca doesn’t work yet, but I don’t know exactly why — I still have to investigate how to make it work.
Here’s a glimpse of how bch-connect looks like:
import { useWallet } from "bch-connect";
export const WalletButtons = () => {
const { connect, connectError, isConnected, disconnect, tokenAddress } =
useWallet();
return (
<>
<button onClick={connect}>
{isConnected ? tokenAddress : "Connect wallet"}
</button>
{isConnected && (
<button title="Disconnect wallet" onClick={disconnect}>
Disconnect
</button>
)}
{connectError && <p>Error connecting wallet: {connectError.message}</p>}
</>
);
};
Wow this is very cool. Our WalletConnect integration on Selene is still quite basic and shaky, so this might actually be extremely useful for us in upgrading that to be a lot cleaner & more robust of an integration.
This is also super useful tooling with BCH BLAZE coming up - I can see a LOT of interest & usage from fresh devs coming into the scene and onboarding straight to WalletConnect with this.
Very excited by this project, great job!
Bug report: Clicking “Connect Wallet” and then “Search Wallets” on the bottom of the pop up modal leads to a perma-loading stalled state.
I’m leaving here some information I’ve gathered while struggling with BCH Connect library, as it could be useful for other developers facing the same or similar issues in their projects.
The problem: While the wallet connection worked correctly in Cashonize web and Zapit with the implementation I made in BCH Connect, Paytaca mobile and Cashonize mobile weren’t working at all. (I’m not including the Paytaca browser extension, as I’ve tested it in all dApps listed in tokenaut.cash and it doesn’t work anywhere. It’s likely a bug in Paytaca’s codebase).
What I’ve found is that Paytaca Mobile and Cashonize Mobile only work with deprecated versions of the @walletconnect/sign-client package. From my testing, they work fine with the version 2.19.1.
So if you are implementing wallet connection in your project, you’ll need to install the deprecated @walletconnect/sign-client@2.19.1 instead of newer versions if you want to support the wallets mentioned above.
I’m currently working to add out-of-the-box support for all of this in BCH Connect, using the latest packages when possible and the deprecated ones when necessary, so developers don’t have to struggle with these kinds of issues. And hopefully, the wallet developers will be able to address these compatibility issues in future updates.
Thanks for a heads up. I am currently working to extract my web3modal+sign-client solution into an npm package with the same structure of hooks so that your reown based solution will become a drop in replacement when all issues will be solved. Will publish my package soonish
Thanks @fran-dv for sharing your findings, just did quite a bit of extra testing with BCH walletconnect myself and want to share my findings
I’ve tested the following 3 walletconnect @walletconnect/sign-client versions
- deprecated version using requiredNamespaces (v2.20.0)
- deprecated version using optionalNamespaces (v2.21.0)
- non deprecated version (v2.21.9)
since Cashonize release v0.5.5 the optionalNameSpaces key is properly supported
first, for me in my walletconnect testing with Cashonize:
Cashonize mobile (v0.5.6) works for all WC lib version
Cashonize dektop (v0.5.6) works for all WC lib version
Cashonize web - chrome desktop - works for all WC lib version
Cashonize web - mobile chrome - works unreliably for all WC lib version
@fran-dv can you share which version of Cashonize mobile you used for testing?
because i cannot replicate the issues you have wit Cashonize mobile
in my testing walletconnect in other BCH wallets
Zapit seems to work with all versions also
Paytaca mobile seems to work only with the deprecated version using requiredNamespaces (v2.20.0)
Selene mobile seems to work only with the deprecated version using requiredNamespaces (v2.20.0)
Hopefully @joemar_taganna and @kzKallisti can take a look at this
So from my testing the only meaningful change seemed to be the difference in optionalNamespaces
not the difference between v2.21.0 (deprecated) and v2.21.9 (supported, non-deprecated)
Thanks everyone for the replies!
@MathieuG you’re absolutely right. Cashonize mobile 0.5.6 works with the latest packages. I didn’t realize I was using a very outdated version of Cashonize; sorry about that. I’ll be more careful next time.
And as you said, the difference that causes the issues is optionalNamespaces. From what I understand, the newer versions that deprecated requiredNamespaces automatically assign them to the optional ones, which leads to the incompatibility.
Thanks again for the feedback. I’ll make sure to be more precise in future tests.
upcoming version of Selene (to be released within next few days) supports optionalNamespaces!
Hello everyone, I just wanted to share a quick update on BCH Connect, if anyone is interested. It’s taking me longer than I expected, but I want to reassure you that I’m still actively working on it and excited about shipping it ASAP.
Lately I’ve had very little free time and have run into some issues, mainly with packages compatibility, trying to make everything just work out of the box. Because of that, I decided to start building a custom UI (similar to RainbowKit, which offers a custom modal) instead of relying on Reown AppKit’s modal, with which, for instance, trying to use custom wallets buttons for cashonize or zapit just don’t work, at least with the version I’ve been working with. This will decouple the connection logic from the UI, making the library easily extensible (e.g. towards the CashConnect spec).
The idea is to get closer to the kind of DX the ETH ecosystem offers, standardizing the process of implementing wallet connections for BCH builders with a good UX UI for users that feels native to the BCH ecosystem.
In my free time I’m working on:
- The custom UI I mentioned above
- A modern documentation site for the library (with handy tools such as a CLI like
npm create bch-dapp) - Improving the codebase and API to make it as simple to use as possible
Adapting the library for non-React apps (Vue, vanilla JS) is on my roadmap.
I’m really excited and eager to ship the first acceptable version, and to avoid spamming here with updates, I created an X account where I’ll announce releases and updates: @fran__dv
As part of the ParityUSD project we implemented bch_cancelPendingRequests, a custom WalletConnect method that allows a dapp to request cancellation of pending signing requests.
This provides a better UX when users cancel an operation in the dapp UI as opposed to the wallet UI. The wallet can dismiss its approval dialog rather than leaving it open, which allows the user to sign a transaction that is no longer required or valid.
It’s documented here and comments or feedback would be greatly appreciated.
Works with Cashonize, ParityUSD and a minimal demo app that I created for testing. Try it out here with Cashonize.

