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

decane-connect-kit

v1.0.3

Published

Wallet connection for EVM, Solana, Tron, and Bitcoin dApps. Detects installed wallets via EIP-6963, the Solana Wallet Standard, TronLink, and Unisat/OKX/MetaMask Snap. Manages sessions with CAIP-25 and ships a polished wallet selector UI. Works with React

Readme

decane-connect-kit

Wallet connection for EVM, Solana, Tron, and Bitcoin dApps. Detects installed wallets via EIP-6963, the Solana Wallet Standard, TronLink, and Unisat/OKX/MetaMask Snap. Manages sessions with CAIP-25 and ships a polished wallet selector UI. Works with React 18+ in any framework.


Install

npm install decane-connect-kit

React 18 or later is required as a peer dependency.


Quick start

1. Wrap your app

// main.tsx / _app.tsx / layout.tsx
import { DecaneKit } from "decane-connect-kit";

<DecaneKit config={{ theme: "auto" }}>
  <App />
</DecaneKit>

That's the entire setup. Wallet discovery starts immediately. If the user was previously connected, the session is restored from localStorage automatically.

2. Add a connect button

import { useDecane, useWalletSelector } from "decane-connect-kit";

function ConnectButton() {
  const { isConnected, connectedWallet, disconnect } = useDecane();
  const { open } = useWalletSelector();

  if (isConnected) {
    return (
      <>
        <span>{connectedWallet!.name}</span>
        <button onClick={disconnect}>Disconnect</button>
      </>
    );
  }

  return <button onClick={open}>Connect Wallet</button>;
}

The modal renders itself — there is no <WalletSelector> component to place anywhere.

3. Sign a message

import { useSignMessage } from "decane-connect-kit";

function SignMessage() {
  const { signMessage, signature, loading, error } = useSignMessage();

  return (
    <>
      <button onClick={() => signMessage("Hello world")} disabled={loading}>
        {loading ? "Signing…" : "Sign"}
      </button>
      {signature && <p>{signature}</p>}
      {error && <p style={{ color: "red" }}>{error.message}</p>}
    </>
  );
}

Chain and account are resolved automatically from the active session. Pass options.chainId to target a specific chain explicitly.


Framework setup

Next.js (App Router)

Client components are required for all hooks. Wrap DecaneKit in a "use client" boundary so the server layout stays a server component.

// src/components/Providers.tsx
"use client";

import { DecaneKit } from "decane-connect-kit";
import type { ReactNode } from "react";

export function Providers({ children }: { children: ReactNode }) {
  return (
    <DecaneKit config={{ theme: "auto" }}>
      {children}
    </DecaneKit>
  );
}
// src/app/layout.tsx
import { Providers } from "@/components/Providers";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Add "use client" to every component that uses a decane hook.

Add transpilePackages to next.config.ts:

const nextConfig = {
  transpilePackages: ["decane-connect-kit"],
};

Vite / Create React App

No extra config needed. Wrap your root component with <DecaneKit> and use hooks anywhere inside it.


Configuration

All options are optional.

<DecaneKit config={{
  // Which wallet types to show and connect
  // "evm" | "solana" | "tron" | "bitcoin" | "all" — default: "all"
  networks: "all",

  // Restrict which built-in chains are available
  // Uses CAIP-2 IDs. Custom chains (via `chains`) are always included.
  supportedChainIds: [CHAINS.ETHEREUM, CHAINS.POLYGON, CHAINS.ARBITRUM],

  // Custom chains to register at startup
  chains: [
    {
      id: "eip155:31337",
      type: "evm",
      chainId: 31337,
      name: "Hardhat Local",
      nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
      rpcUrl: "http://localhost:8545",
      isCustom: true,
    },
  ],

  // UI theme — "light" | "dark" | "auto" — default: "auto"
  theme: "auto",

  // Default CAIP-2 chain ID to request when connecting
  defaultChain: "eip155:1",
}}>

networks

Controls which wallets appear in the selector and which chain types are offered.

// EVM-only dApp — all other wallets hidden
<DecaneKit config={{ networks: "evm" }}>

// Solana-only dApp
<DecaneKit config={{ networks: "solana" }}>

// Tron-only dApp
<DecaneKit config={{ networks: "tron" }}>

// Bitcoin-only dApp
<DecaneKit config={{ networks: "bitcoin" }}>

// All chains (default)
<DecaneKit config={{ networks: "all" }}>

supportedChainIds

Restricts the chain list used throughout the SDK — the wallet selector, provider.chains, and wallet_requestPermissions all respect it.

import { CHAINS } from "decane-connect-kit";

<DecaneKit config={{
  supportedChainIds: [CHAINS.ETHEREUM, CHAINS.BASE, CHAINS.SOLANA, CHAINS.TRON, CHAINS.BITCOIN],
}}>

Hooks

useDecane()

Reactive state hook. Re-renders on any wallet or session change.

const {
  // Detected wallets
  wallets,           // all wallets
  evmWallets,        // EVM wallets
  solanaWallets,     // Solana wallets
  tronWallets,       // Tron wallets (TronLink)
  bitcoinWallets,    // Bitcoin wallets (Unisat, OKX, MetaMask Snap)
  multiChainWallets, // wallets supporting 2+ chains

  // Connection state
  isConnected,
  connectedWallet,   // UnifiedWalletAccount | null
  activeSession,     // ActiveSession | null
  activeChain,       // CAIP-2 string | null

  // Registered chains
  chains,            // ChainDescriptor[]

  // Theme
  theme,             // "light" | "dark" | "auto"
  setTheme,          // (t: Theme) => void

  // Actions
  connect,           // (wallet, preference?) => Promise<void>
  disconnect,        // () => Promise<void>
  addChain,          // (chain: ChainDescriptor) => void
  removeChain,       // (chainId: string) => void
} = useDecane();

useWalletSelector()

Controls the wallet modal.

const { isOpen, open, close } = useWalletSelector();

<button onClick={open}>Connect Wallet</button>

useSignMessage()

Works on EVM, Solana, Tron, and Bitcoin. The active chain determines the signing method used.

const { signMessage, signature, loading, error, reset } = useSignMessage();

// Uses active chain and account automatically
await signMessage("Hello world");

// Override chain or account
await signMessage("Hello world", { chainId: CHAINS.POLYGON, account: "0xAbc…" });
await signMessage("Hello world", { chainId: CHAINS.TRON });
await signMessage("Hello world", { chainId: CHAINS.BITCOIN });

useSendTransaction()

Works on EVM, Solana, Tron, and Bitcoin.

const { sendTransaction, txHash, loading, error, reset } = useSendTransaction();

// EVM — value in wei
await sendTransaction({
  to: "0xRecipient",
  value: "1000000000000000", // decimal string or hex
  data: "0x",               // optional calldata
  gas: "21000",             // optional
});

// Tron — value in SUN (1 TRX = 1,000,000 SUN)
await sendTransaction({ to: "TRecipient…", value: "1000000" }, { chainId: CHAINS.TRON });

// Bitcoin — value in satoshis
await sendTransaction({ to: "bc1q…", value: "10000" }, { chainId: CHAINS.BITCOIN });

// Override chain
await sendTransaction({ to: "0xRecipient" }, { chainId: CHAINS.ARBITRUM });

useSignTypedData()

EVM only. Throws DecaneErrorCode.EVM_ONLY_METHOD if called on a non-EVM chain.

const { signTypedData, signature, loading, error, reset } = useSignTypedData();

await signTypedData({
  domain:  { name: "MyApp", version: "1", chainId: 1 },
  types:   { Permit: [{ name: "owner", type: "address" }, …] },
  message: { owner: "0xAbc…", spender: "0xDef…", value: "1000" },
});

useChainSwitch()

Switch the active chain within the current session.

const { switchChain, activeChain, grantedChains, loading, error } = useChainSwitch();

// grantedChains — CAIP-2 IDs granted in the current session
await switchChain(CHAINS.POLYGON);
await switchChain(CHAINS.TRON);
await switchChain(CHAINS.BITCOIN);

Wallet detection

EVM

Detected via EIP-6963 — standard event-based discovery. All compliant wallets (MetaMask, Rabby, Coinbase Wallet, Brave, OKX, and others) are discovered automatically. window.ethereum is never used.

Solana

Detected via the Wallet Standard (@wallet-standard/app). Wallets must expose standard:connect, solana:signTransaction, and solana:signMessage. Multi-chain wallets like Phantom and Backpack are merged into a single entry when detected on both EVM and Solana.

Tron

Detected via TronLink's injected provider (window.tronLink). The SDK listens for tronLink#initialized and polls for up to 3 seconds to handle extensions that load after the page. Transactions are built via window.tronWeb.transactionBuilder when available, falling back to the TronGrid HTTP API.

Bitcoin

Three detection paths run in parallel:

| Wallet | Detection | |--------|-----------| | Unisat | window.unisat injected provider | | OKX Wallet | window.okxwallet.bitcoin — shares rdns with OKX EVM, auto-merges to give EVM + Bitcoin support | | MetaMask Bitcoin Snap | After each EVM wallet is discovered, wallet_getSnaps is called silently. If npm:@metamask/bitcoin-snap or npm:@consensys/btc-snap is enabled, the wallet gains Bitcoin support with no user interaction |


Chain constants

Use CHAINS instead of bare strings to get autocomplete and catch typos at compile time.

import { CHAINS, type ChainId } from "decane-connect-kit";

// Tier-1 EVM
CHAINS.ETHEREUM         // "eip155:1"
CHAINS.BASE             // "eip155:8453"
CHAINS.ARBITRUM         // "eip155:42161"
CHAINS.OPTIMISM         // "eip155:10"
CHAINS.BNB              // "eip155:56"
CHAINS.POLYGON          // "eip155:137"

// Extended EVM (selected)
CHAINS.ABSTRACT         // "eip155:2741"
CHAINS.APE_CHAIN        // "eip155:33139"
CHAINS.AVALANCHE        // "eip155:43114"
CHAINS.BERACHAIN        // "eip155:80094"
CHAINS.BLAST            // "eip155:81457"
CHAINS.CELO             // "eip155:42220"
CHAINS.GNOSIS           // "eip155:100"
CHAINS.LINEA            // "eip155:59144"
CHAINS.MANTLE           // "eip155:5000"
CHAINS.SCROLL           // "eip155:534352"
CHAINS.SONIC            // "eip155:146"
CHAINS.TAIKO            // "eip155:167000"
CHAINS.UNICHAIN         // "eip155:130"
CHAINS.WORLD_CHAIN      // "eip155:480"
CHAINS.ZKSYNC_ERA       // "eip155:324"
CHAINS.ZORA             // "eip155:7777777"
// …58 chains total — see Built-in chains table below

// Dev
CHAINS.LOCALHOST        // "eip155:31337"

// Solana
CHAINS.SOLANA           // "solana:mainnet"
CHAINS.SOLANA_DEVNET    // "solana:devnet"

// Tron
CHAINS.TRON             // "tron:mainnet"
CHAINS.TRON_SHASTA      // "tron:shasta"

// Bitcoin
CHAINS.BITCOIN          // "bip122:mainnet"

ChainId is the union type of all built-in chain ID strings.


Custom chains

Add any EVM chain (local Hardhat, private L2) or Solana network at runtime.

const { addChain, removeChain } = useDecane();

// Add a local Hardhat node
addChain({
  id: "eip155:31337",
  type: "evm",
  chainId: 31337,
  name: "Hardhat Local",
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpcUrl: "http://localhost:8545",
  isCustom: true,
});

// Add a custom Solana network
addChain({
  id: "solana:localnet",
  type: "solana",
  name: "Solana Localnet",
  nativeCurrency: { name: "SOL", symbol: "SOL", decimals: 9 },
  rpcUrl: "http://localhost:8899",
  isCustom: true,
});

// Remove a custom chain (built-in chains cannot be removed)
removeChain("eip155:31337");

Custom chains can also be registered at init via config.chains. When addChain is called while a wallet is connected, it automatically calls wallet_addEthereumChain on the wallet so it knows about the network.


Error handling

All hooks return error: DecaneError | null. Branch on error.code instead of parsing error strings.

import { DecaneError, DecaneErrorCode } from "decane-connect-kit";

const { signMessage, error } = useSignMessage();

if (error) {
  switch (error.code) {
    case DecaneErrorCode.USER_REJECTED:
      // User dismissed the wallet prompt — not an error, just reset
      break;
    case DecaneErrorCode.NO_ACTIVE_SESSION:
      // Prompt the user to connect a wallet first
      break;
    case DecaneErrorCode.CHAIN_NOT_IN_SCOPE:
      // Call switchChain() to add this chain to the session
      break;
    case DecaneErrorCode.SCOPE_MISMATCH:
      // The account isn't in the current session
      break;
    default:
      console.error(error.message);
  }
}

Error codes

| Code | Value | When thrown | |------|-------|-------------| | USER_REJECTED | 4001 | User dismissed the wallet prompt | | UNAUTHORIZED | 4100 | Wallet refused the request | | NO_ACTIVE_SESSION | 5001 | Signing called before connecting | | SCOPE_MISMATCH | 5002 | Account not in session scope | | SESSION_EXPIRED | 5003 | Session is no longer valid | | UNSUPPORTED_CHAIN | 5010 | Chain ID not in registry | | CHAIN_NOT_IN_SCOPE | 5011 | Chain not granted in session | | INVALID_CHAIN_CONFIG | 5012 | Custom chain descriptor is malformed | | NO_WALLET_CONNECTED | 5020 | Action requires a connected wallet | | WALLET_DISCONNECTED | 5021 | Wallet disconnected mid-session | | PROVIDER_ERROR | 5022 | Underlying wallet threw an error | | METHOD_NOT_SUPPORTED | 5030 | Method not recognised | | EVM_ONLY_METHOD | 5031 | wallet_signTypedData on a non-EVM chain |


Theme

The modal theme is controlled through DecaneKit config and toggled at runtime via useDecane.

// Follow system preference (default)
<DecaneKit config={{ theme: "auto" }}>

// Force dark
<DecaneKit config={{ theme: "dark" }}>
// Toggle at runtime — the modal follows automatically
const { theme, setTheme } = useDecane();

<button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
  Toggle theme
</button>

To apply the same tokens to your own app UI, the SDK injects CSS custom properties into document.head whenever the modal opens:

var(--dc-bg)
var(--dc-surface)
var(--dc-border)
var(--dc-text)
var(--dc-text-secondary)
var(--dc-text-muted)
var(--dc-accent)        /* gold */
var(--dc-accent-hover)
var(--dc-accent-text)
var(--dc-danger)
var(--dc-success)

TypeScript

The package ships full type declarations. Key types:

import type {
  DecaneProvider,       // full provider interface
  DecaneConfig,         // config passed to <DecaneKit>
  UnifiedWalletAccount, // a detected wallet entry
  ChainDescriptor,      // chain definition object
  ActiveSession,        // CAIP-25 session state
  ChainScope,           // methods + accounts for one chain
  ChainType,            // "evm" | "solana" | "tron" | "bitcoin"
  ChainId,              // union of all built-in CAIP-2 chain IDs
  Theme,                // "light" | "dark" | "auto"
  TxParams,             // params for useSendTransaction
  CAIP25Method,         // all supported method strings
} from "decane-connect-kit";

What is not included

  • Social sign-in or email login
  • Any backend, server, or API calls (except the TronGrid fallback when TronWeb is unavailable)
  • window.ethereum — detection uses EIP-6963 exclusively
  • Private key or seed phrase management
  • State management libraries (Redux, Zustand) — pure React context

Built-in chains

The following chains are available out of the box. Pass supportedChainIds in config to restrict to a subset.

Tier-1 EVM

| Name | CAIP-2 ID | CHAINS constant | |------|-----------|-------------------| | Ethereum | eip155:1 | CHAINS.ETHEREUM | | Base | eip155:8453 | CHAINS.BASE | | Arbitrum One | eip155:42161 | CHAINS.ARBITRUM | | Optimism | eip155:10 | CHAINS.OPTIMISM | | BNB Chain | eip155:56 | CHAINS.BNB | | Polygon | eip155:137 | CHAINS.POLYGON |

Extended EVM

| Name | CAIP-2 ID | CHAINS constant | |------|-----------|-------------------| | Abstract | eip155:2741 | CHAINS.ABSTRACT | | Ancient8 | eip155:888888888 | CHAINS.ANCIENT8 | | Animechain | eip155:69000 | CHAINS.ANIMECHAIN | | ApeChain | eip155:33139 | CHAINS.APE_CHAIN | | Arbitrum Nova | eip155:42170 | CHAINS.ARBITRUM_NOVA | | Avalanche | eip155:43114 | CHAINS.AVALANCHE | | B3 | eip155:8333 | CHAINS.B3 | | Berachain | eip155:80094 | CHAINS.BERACHAIN | | Blast | eip155:81457 | CHAINS.BLAST | | BOB | eip155:60808 | CHAINS.BOB | | Boba Network | eip155:288 | CHAINS.BOBA | | Celo | eip155:42220 | CHAINS.CELO | | Corn | eip155:21000000 | CHAINS.CORN | | Cronos | eip155:25 | CHAINS.CRONOS | | Cyber | eip155:7560 | CHAINS.CYBER | | Degen | eip155:666666666 | CHAINS.DEGEN | | Flow EVM | eip155:747 | CHAINS.FLOW_EVM | | Gnosis | eip155:100 | CHAINS.GNOSIS | | Gunz | eip155:49321 | CHAINS.GUNZ | | Hemi | eip155:43111 | CHAINS.HEMI | | HyperEVM | eip155:999 | CHAINS.HYPER_EVM | | Ink | eip155:57073 | CHAINS.INK | | Linea | eip155:59144 | CHAINS.LINEA | | Lisk | eip155:1135 | CHAINS.LISK | | Manta Pacific | eip155:169 | CHAINS.MANTA_PACIFIC | | Mantle | eip155:5000 | CHAINS.MANTLE | | MegaETH | eip155:6342 | CHAINS.MEGA_ETH | | Metis | eip155:1088 | CHAINS.METIS | | Mode | eip155:34443 | CHAINS.MODE | | Monad | eip155:10143 | CHAINS.MONAD | | Morph | eip155:2818 | CHAINS.MORPH | | Plume | eip155:98866 | CHAINS.PLUME | | RARI | eip155:1380012617 | CHAINS.RARI | | Redstone | eip155:690 | CHAINS.REDSTONE | | Ronin | eip155:2020 | CHAINS.RONIN | | Scroll | eip155:534352 | CHAINS.SCROLL | | Sei | eip155:1329 | CHAINS.SEI | | Shape | eip155:360 | CHAINS.SHAPE | | Somnia | eip155:50312 | CHAINS.SOMNIA | | Soneium | eip155:1868 | CHAINS.SONEIUM | | Sonic | eip155:146 | CHAINS.SONIC | | Story | eip155:1514 | CHAINS.STORY | | Superposition | eip155:55244 | CHAINS.SUPERPOSITION | | Superseed | eip155:5330 | CHAINS.SUPERSEED | | SwellChain | eip155:1923 | CHAINS.SWELL_CHAIN | | Taiko | eip155:167000 | CHAINS.TAIKO | | Unichain | eip155:130 | CHAINS.UNICHAIN | | World Chain | eip155:480 | CHAINS.WORLD_CHAIN | | ZERO | eip155:543210 | CHAINS.ZERO | | Zircuit | eip155:48900 | CHAINS.ZIRCUIT | | zkSync Era | eip155:324 | CHAINS.ZKSYNC_ERA | | Zora | eip155:7777777 | CHAINS.ZORA |

Dev / local

| Name | CAIP-2 ID | CHAINS constant | |------|-----------|-------------------| | Localhost | eip155:31337 | CHAINS.LOCALHOST |

Solana

| Name | CAIP-2 ID | CHAINS constant | |------|-----------|-------------------| | Solana | solana:mainnet | CHAINS.SOLANA | | Solana Devnet | solana:devnet | CHAINS.SOLANA_DEVNET |

Tron

| Name | CAIP-2 ID | CHAINS constant | |------|-----------|-------------------| | Tron | tron:mainnet | CHAINS.TRON | | Tron Shasta Testnet | tron:shasta | CHAINS.TRON_SHASTA |

Bitcoin

| Name | CAIP-2 ID | CHAINS constant | |------|-----------|-------------------| | Bitcoin | bip122:mainnet | CHAINS.BITCOIN |