Skip to content
usewhiskPublic

About

Accept USDC from any chain. Open-source SDK for cross-chain stablecoin payments on Circle CCTP V2.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

19 stars

Watchers

0 watching

Forks

Latest commit

 

History

136 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Whisk Logo

Whisk

Embeddable React widget for USDC payments and cross-chain bridges. Built directly on CCTP V2.

Drop-in React component: same-chain sends and cross-ecosystem bridges over CCTP V2 Fast Transfer. EVM, Solana, Stellar, and Starknet wallets. Multichain ENS resolution in the box. Mid-flight recovery if a burn lands but the mint doesn't. Theme with CSS variables, go headless with useWhisk(). MIT-licensed.

npm @usewhisk/react npm @usewhisk/core npm @usewhisk/cctp License: MIT Types PRs Welcome CCTP V2


What is Whisk?

Whisk is a drop-in React component for USDC payments. One React component, four ecosystems, native CCTP V2 Fast Transfers under the hood:

  • Send USDC to any address on the same chain
  • Bridge USDC across chains and ecosystems via CCTP V2
  • Pay through any wallet: MetaMask, Phantom, Freighter, Argent X, and dozens more
  • See a transparent fee breakdown before confirming
  • Watch the transfer progress through every step (approve → burn → fetchAttestation → mint)

Whisk speaks CCTP V2 natively: no third-party SDKs, no adapter layers to keep up to date. When Circle ships a new CCTP chain, we add it in one file and everyone gets it.

<WhiskProvider config={config}>
  <WhiskSend onSuccess={(r) => console.log("done:", r.finalTxHash)} />
</WhiskProvider>

That's it. The widget handles wallet connection, chain switching, recipient validation, fee preview, and the whole transaction lifecycle.


Why Whisk?

Building USDC payments from scratch means:

  • A UI for the multi-step CCTP burn → attest → mint state machine
  • Wallet connection across four ecosystems (EVM, Solana, Stellar, Starknet)
  • Per-ecosystem address validation
  • Fee math across burn fees, forwarder fees, and gas
  • Iris polling with retry and recovery
  • Manual mint into Solana, Stellar and Starknet (Circle only forwards mints into EVM chains)
  • The Cairo ByteArray encoding for Starknet destinations
  • The Stellar CctpForwarder pattern for inbound Stellar mints

That's the work Whisk does once, well, and ships as a widget so you spend your time on the rest of your product.


Quickstart

Install

pnpm add @usewhisk/react @tanstack/react-query

Drop it in

import {
  WhiskProvider,
  WhiskSend,
  createWhiskConfig,
  evm,
} from "@usewhisk/react";
import "@usewhisk/react/styles.css";

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

export default function App() {
  return (
    <WhiskProvider config={config}>
      <WhiskSend />
    </WhiskProvider>
  );
}

That's the entire integration.

Add other ecosystems

Whisk mounts each ecosystem's provider only when its factory is present in wallets. Every pair of ecosystems can bridge in both directions.

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

const config = createWhiskConfig({
  wallets: [evm(), solana(), stellar(), starknet()],
  chains: [
    "Base_Sepolia",
    "Solana_Devnet",
    "Stellar_Testnet",
    "Starknet_Sepolia",
  ],
});

Pick a theme

<WhiskProvider config={config} theme="auto">
  <WhiskSend />
</WhiskProvider>

"light" (the default), "dark" and "auto" are built in, alongside a few named palettes. See Theming.


Features

Capability Notes
Send (same-chain) Direct ERC-20 (EVM), SPL (Solana), Stellar Asset (Stellar), or Cairo transfer (Starknet).
Bridge (cross-chain) CCTP V2 Fast Transfer where the source offers it, Standard otherwise. Approve → burn → attestation → mint, all automatic.
Cross-ecosystem Every pair of the four ecosystems, both directions.
Smart routing Whisk picks same-chain vs bridge from the source/destination chains.
Multi-wallet Ecosystem-first connect modal: EVM (wagmi connectors), Solana (Wallet Standard), Stellar (Stellar Wallets Kit), Starknet (get-starknet-core).
Recipient resolvers Address + ENSIP-11 multichain ENS built in; bring your own.
Bound quotes Burn + forwarder + gas shown before confirm. send takes the quote the payer saw and refuses it if it expired or fees rose.
Fee bearer feeBearer: "sender" (default) grosses up the burn so the recipient nets the exact amount; "receiver" deducts fees from the transfer.
Max button Fills in the largest amount the wallet can send after fees, when the balance can be read.
Progress streaming Live step events over the whole approve → burn → fetchAttestation → mint lifecycle.
Mid-flight recovery Every bridge is saved from the moment the burn is signed (localStorage by default) and kept until dismissed. After a reload the widget lists it and finishes the mint without a second burn.
Network from the chain Mainnet or testnet always follows the source chain. Mixing the two is refused with NetworkMismatchError.
Typed errors RouteUnavailableError, QuoteExpiredError, QuoteChangedError, InsufficientBalanceError and more, each with a stable code.
Headless mode useWhisk() hook for full UI control, or import @usewhisk/core for server flows.
Theming light, dark and auto presets, --whisk-* CSS variables, optional Tailwind preset.
Open source MIT. Read every line, fork it, ship your own.

Architecture

Whisk is a small monorepo. Three packages, one architecture.

whisk/
├── packages/
│   ├── cctp/         # @usewhisk/cctp: CCTP V2 protocol layer (chains, ABIs, Iris, builders)
│   ├── core/         # @usewhisk/core: framework-agnostic engine
│   └── react/        # @usewhisk/react: components, hooks, provider
├── examples/
│   ├── playground/         # Every-prop showcase + control panel
│   ├── ecommerce-checkout/ # Next.js storefront
│   ├── donate-button/      # Vite donation page
│   ├── themed-saas/        # Next.js dark dashboard
│   ├── payroll-batch/      # Vite batch payouts
│   ├── invoice-link/       # Next.js invoice links
│   ├── node-headless/      # Server-side scripts (send / payroll / refund)
│   └── vue-headless/       # Engine driving a Vue UI
└── apps/
    └── docs/         # Documentation site (Fumadocs)
  • @usewhisk/cctp: CCTP V2 protocol layer. Chain registry (EVM + Solana + Stellar + Starknet), TokenMessengerV2 / MessageTransmitterV2 ABIs, Iris client, burn intent builders, manual mint builders. No engine logic, no UI.
  • @usewhisk/core: the engine. Pure TypeScript, no React, no DOM. Exports createWhisk(), the adapter interfaces, the state machine, resolver composition, fee logic, and error classes.
  • @usewhisk/react: components, hooks, and the provider. Wraps wagmi (EVM), Wallet Standard (Solana), Stellar Wallets Kit, and get-starknet-core. Ships <WhiskSend> (drop-in) and useWhisk() (headless).

Deeper design docs (engine boundary, state machine, fee model, resolvers, errors) live on the documentation site.


Recipes

Five reference integrations, each a themed mini-app. All run on testnet. Grab test USDC from the Circle faucet.

Recipe What it shows Live demo
E-commerce checkout Cart total + merchant address locked; the widget is confirm-and-pay demo
Donate button Pinned treasury + preset amounts that seed defaultAmount demo
Themed SaaS --whisk-* overrides repaint the widget into a dark dashboard demo
Payroll batch Widget remounts per payee, bridging treasury USDC to each one's chain demo
Invoice link A shareable URL opens a pre-filled, locked checkout demo

Two headless examples, node-headless for server flows and vue-headless for a non-React UI, cover the engine-only path.


Supported chains

A selection of the supported chains. The full list, with domains and Fast Transfer support, is in the @usewhisk/cctp README.

Ecosystem Testnet chain Mainnet chain
EVM Ethereum_Sepolia Ethereum
Base_Sepolia Base
Arbitrum_Sepolia Arbitrum
Optimism_Sepolia Optimism
Polygon_Amoy_Testnet Polygon
Avalanche_Fuji Avalanche
Linea_Sepolia Linea
Unichain_Sepolia Unichain
World_Chain_Sepolia World_Chain
Arc_Testnet Arc
Solana Solana_Devnet Solana
Stellar Stellar_Testnet Stellar
Starknet Starknet_Sepolia Starknet

Adding a chain is a new entry in packages/cctp/src/chains/. An EVM chain also needs its viem chain in packages/react/src/config/adapters/evm.ts.


Theming

Pick a preset on the provider: "light" (the default), "dark", "wine", "indigo", "emerald", "monochrome", or "auto", which follows prefers-color-scheme in CSS alone. To change some colors, pass a preset with tokens:

<WhiskProvider
  config={config}
  theme={{ preset: "dark", tokens: { primary: "#6366f1", radius: "0.625rem" } }}
>
  <WhiskSend />
</WhiskProvider>

Everything is driven by --whisk-* CSS variables on [data-whisk]. With "light", "dark" or "auto", a rule in your own stylesheet (loaded after styles.css) overrides any of them. The other presets set their colors inline, so change those with tokens:

[data-whisk] {
  --whisk-radius: 0.625rem;
  --whisk-font: "Inter", system-ui, sans-serif;
}

Tailwind users can opt into the preset:

// tailwind.config.js
import { whiskTheme } from "@usewhisk/react/tailwind";

export default {
  presets: [whiskTheme()],
};

Security model

  • No private keys ever touch Whisk. The widget is browser-side; signing happens in the user's wallet.
  • No telemetry. Nothing phones home.
  • Open source under MIT. Audit every line. Fork it. Ship your own.
  • Type-safe end to end. No any casts in the source. Every ecosystem's adapter is a discriminated union member.
  • Branch protection. main is protected; every change goes through PR review including changes from the maintainer.
  • CI on every PR. Format, lint, typecheck, tests, production build and a dependency audit.
  • Nightly testnet matrix. pnpm test:testnet sends real testnet USDC through createWhisk() across EVM, Solana, Stellar and Starknet routes, plus a burn-then-resume scenario.

Contributing

Whisk is community-maintained. Anyone can:

  • File a bug or feature request: open an issue
  • Improve the code: fork the repo, branch off main, open a pull request
  • Improve the docs: same flow; small docs PRs are very welcome

Read CONTRIBUTING.md for development setup, project layout, PR conventions, and the security-disclosure flow.

Local development

git clone https://github.com/usewhisk/whisk.git
cd whisk
pnpm install
pnpm -r build       # build all packages
pnpm -r typecheck   # strict type-check all packages
pnpm -r test        # run all package tests

Acknowledgements

  • Built directly on Circle's CCTP V2, the protocol doing the underlying settlement.
  • Inspired by Uniswap Widgets, shadcn/ui for the theming approach, and wagmi for the config-driven adapter pattern.
  • Not affiliated with Circle. Whisk is a community-built widget over Circle's public protocol.

License

MIT · Built by SignorDev

About

Accept USDC from any chain. Open-source SDK for cross-chain stablecoin payments on Circle CCTP V2.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

19 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages