whisk
Getting Started

Mount the provider

Wrap your app with WhiskProvider and configure the wallet adapters it needs.

<WhiskProvider> is the only part of Whisk you have to set up by hand. It builds the engine, mounts the wallet stack, and exposes everything to the hooks and components below it. Once it's in place, the rest of Whisk is just children of it.

The shortest version

app/providers.tsx
"use client";

import { WhiskProvider, createWhiskConfig, evm } from "@usewhisk/react";

const config = createWhiskConfig({
  wallets: [
    evm({
      projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID!,
    }),
  ],
  chains: ["Arc_Testnet", "Base_Sepolia"],
});

export function Providers({ children }: { children: React.ReactNode }) {
  return <WhiskProvider config={config}>{children}</WhiskProvider>;
}

Then use it at the root of your tree:

app/layout.tsx
import { Providers } from "./providers";
import "@usewhisk/react/styles.css";

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

Wrap once, at the root. Don't sprinkle WhiskProvider around the tree because the engine should be a singleton per app.

Mode (testnet / mainnet)

Whisk operates in one of two modes. The mode is inferred from your chain list — pass all-testnet chains and you're in testnet mode, all-mainnet chains and you're in mainnet mode. You can also set it explicitly:

createWhiskConfig({
  mode: "testnet", // optional, inferred from chains
  chains: ["Arc_Testnet", "Base_Sepolia"],
  // ...
});

Mode drives three visible behaviours:

  1. A "Testnet" pill at the top of the widget. Always visible in testnet mode, from the moment the card mounts. Mainnet renders no pill — absence is the safer signal that real money is moving.
  2. The default ENS resolver. Testnet mode queries Sepolia ENS first, then falls back to mainnet ENS (so a dev who registers a Sepolia name for integration testing gets it, while vitalik.eth still resolves to his mainnet address). Mainnet mode queries mainnet only. Customise via createDefaultResolver({ mode }).
  3. Recovery persistence namespacing. Mid-flight failure snapshots are keyed on (mode, walletKind, address, sourceChain) — a testnet recovery cannot resurrect in a mainnet config, full stop.

Mixed configs (some mainnet chains, some testnet) almost always indicate a copy-paste mistake. Whisk defaults to testnet for safety in that case and logs a console warning so you notice.

Adding Solana

Drop the solana() adapter into the wallets array. Whisk only mounts the Solana provider stack when this adapter is present, so EVM-only apps don't pay for code they won't run.

import { createWhiskConfig, evm, solana } from "@usewhisk/react";

const config = createWhiskConfig({
  wallets: [
    evm({ projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID! }),
    solana({ network: "devnet" }),
  ],
  chains: ["Arc_Testnet", "Base_Sepolia", "Solana_Devnet"],
});

Reusing your existing wagmi setup

If your app already mounts <WagmiProvider>, Whisk detects it and reuses your config. In that case the evm() adapter becomes optional and so the host wagmi config becomes what drives EVM operations:

<WagmiProvider config={yourWagmiConfig}>
  <QueryClientProvider client={yourQueryClient}>
    <WhiskProvider config={createWhiskConfig({ chains: ["Base"] })}>
      {children}
    </WhiskProvider>
  </QueryClientProvider>
</WagmiProvider>

The same logic applies to @tanstack/react-query. An outer <QueryClientProvider> gets reused; pass queryClient explicitly to <WhiskProvider> only when you want to override the detection.

Pinning the theme

The default mode is "system". Whisk follows the OS via prefers-color-scheme. To pin it instead, pass theme:

<WhiskProvider config={config} theme="dark">
  {children}
</WhiskProvider>

When pinned, the widget root renders data-whisk-theme="dark". The selector lives at the bottom of the cascade so it beats the media query.

See Theming for the full token contract.

Next

Drop in your first widget.

On this page