npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@perawallet/walletconnect

v1.0.0

Published

Modern, security-forward WalletConnect v1 client maintained by Pera Wallet

Readme

@perawallet/walletconnect

A modern, security-forward implementation of the WalletConnect v1 client protocol, maintained by Pera Wallet. It provides both sides of the protocol — the wallet API (receive session and call requests, approve or reject them) and the dapp API (create sessions, send requests) — with full wire compatibility with the original @walletconnect/[email protected].

Why this exists

  • WC v1 is still in production. Pera's infrastructure and ecosystem integrations are pinned to the WalletConnect v1 protocol, which speaks a simple, self-hostable bridge protocol.
  • Upstream is abandoned. The original walletconnect-monorepo v1.x line is unmaintained, with stale dependencies and no security fixes.
  • WC v2+ is a walled garden. ReOwn's v2+ protocol requires their hosted relay and project registration; v1 can run entirely on infrastructure you control.
  • Supply-chain control. The legacy client pulled in a long tail of transitive dependencies. This package re-implements everything on top of exactly two audited cryptography libraries and nothing else.

Install

pnpm add @perawallet/walletconnect
# or
npm install @perawallet/walletconnect
# or
yarn add @perawallet/walletconnect

Runtime dependencies: @noble/ciphers and @noble/hashes — that's all.

Supported environments: Node.js ≥ 22 (uses the native WebSocket global), modern browsers, and React Native (see React Native below). Ships as dual ESM + CJS with full TypeScript types.

Usage

Wallet side

A wallet joins an existing session from a wc: URI (scanned from a QR code or opened via deep link), then responds to requests from the dapp:

import WalletConnect from "@perawallet/walletconnect";

const connector = new WalletConnect({
  uri, // "wc:..." URI from the dapp's QR code / deep link
  clientMeta: {
    name: "Pera Wallet",
    description: "Algorand wallet",
    url: "https://perawallet.app",
    icons: ["https://perawallet.app/icon.png"],
  },
  // Required in React Native, optional elsewhere (defaults to localStorage):
  // storage: <ISessionStorage adapter, see "React Native" below>
});

// The dapp asks to connect
connector.on("session_request", (error, payload) => {
  if (error) throw error;
  const { peerMeta } = payload.params[0];
  // ...show approval UI for peerMeta...
  connector.approveSession({
    accounts: ["ALGORANDADDRESS..."],
    chainId: 4160,
  });
  // or: connector.rejectSession({ message: "User rejected" });
});

// The dapp sends a JSON-RPC call (e.g. a signing request)
connector.on("call_request", (error, payload) => {
  if (error) throw error;
  if (payload.method === "algo_signTxn") {
    // ...sign payload.params...
    connector.approveRequest({ id: payload.id, result: [signedTxn] });
    // or: connector.rejectRequest({ id: payload.id, error: { message: "Rejected" } });
  }
});

connector.on("disconnect", error => {
  // session ended by the peer
});

// End the session from the wallet side
await connector.killSession();

Dapp side

A dapp creates a session on a bridge and displays the pairing URI to the user:

import WalletConnect from "@perawallet/walletconnect";

const connector = new WalletConnect({
  bridge: "https://your-bridge.example.com", // your self-hosted bridge server
  clientMeta: {
    name: "My Dapp",
    description: "Example dapp",
    url: "https://dapp.example.com",
    icons: ["https://dapp.example.com/icon.png"],
  },
  qrcodeModal: {
    open: (uri, cb) => showQrCode(uri), // render the wc: URI as a QR code
    close: () => hideQrCode(),
  },
});

await connector.createSession({ chainId: 4160 });
// connector.uri now holds the "wc:..." pairing URI

connector.on("connect", (error, payload) => {
  if (error) throw error;
  const { accounts } = payload.params[0]; // wallet approved
});

connector.on("session_update", (error, payload) => {
  if (error) throw error;
  const { accounts } = payload.params[0]; // wallet changed accounts/chain
});

// Send a custom JSON-RPC request to the wallet
const signed = await connector.sendCustomRequest(
  { method: "algo_signTxn", params: [[{ txn: base64Txn }]] },
  { forcePushNotification: true },
);

await connector.killSession();

Note on bridges: the original public *.bridge.walletconnect.org servers have been shut down by ReOwn. Wallet-side connections take the bridge from the wc: URI automatically; dapp-side code should pass the URL of a bridge server you operate via the bridge option.

React Native

Two requirements, both enforced with clear errors:

  1. crypto.getRandomValues must exist globally before constructing WalletConnect. Install and import a polyfill such as react-native-quick-crypto or react-native-get-random-values at the top of your app's entry point. The constructor throws if it is missing.

  2. Inject a storage adapter. React Native has no localStorage, so pass a synchronous adapter via the storage option to persist sessions. With MMKV (synchronous, ideal):

import { MMKV } from "react-native-mmkv";
import WalletConnect, { type IWalletConnectSession } from "@perawallet/walletconnect";

const mmkv = new MMKV();
const STORAGE_KEY = "walletconnect";

const storage = {
  getSession: (): IWalletConnectSession | null => {
    const json = mmkv.getString(STORAGE_KEY);
    return json ? JSON.parse(json) : null;
  },
  setSession: (session: IWalletConnectSession) => {
    mmkv.set(STORAGE_KEY, JSON.stringify(session));
    return session;
  },
  removeSession: () => {
    mmkv.delete(STORAGE_KEY);
  },
};

const connector = new WalletConnect({ uri, clientMeta, storage });

The adapter interface is synchronous (getSession / setSession / removeSession). If you use AsyncStorage, hydrate the session into memory at app startup and back the adapter with that in-memory copy.

Security posture

  • Two runtime dependencies, both audited crypto primitives: @noble/ciphers (AES-CBC) and @noble/hashes (HMAC-SHA256, SHA-512, Keccak). Nothing else ships at runtime.
  • Proven wire compatibility: a golden interop test suite runs every session lifecycle (connect, approve, custom requests, update, kill) in both orientations against the original @walletconnect/[email protected] as an oracle, plus byte-level encryption/HMAC interop vectors.
  • 7-day dependency cooldown: minimumReleaseAge is enforced so freshly published (potentially compromised) dependency versions cannot enter the lockfile for a week.
  • Hardened CI: all GitHub Actions are SHA-pinned; CodeQL static analysis, OpenSSF Scorecard, and SBOM generation run on every change.
  • Provenance-verified releases: publishing uses npm OIDC trusted publishing with Sigstore provenance — no long-lived npm tokens exist. See RELEASING.md.

Development

pnpm install          # install (frozen lockfile in CI)
pnpm build            # build ESM + CJS + .d.ts into packages/walletconnect/dist
pnpm test             # run the full vitest suite (incl. interop tests)
pnpm test:coverage    # tests with coverage
pnpm lint             # oxlint
pnpm format           # oxfmt
pnpm typecheck        # tsc --noEmit

This is a pnpm workspace; the single published package lives at packages/walletconnect. Node.js ≥ 22 is required.

License

Apache-2.0. This project is a fork and modernization of WalletConnect v1.x (Copyright 2020 WalletConnect) — see NOTICE for full attribution.