diff --git a/.changeset/widget-usdh-migration.md b/.changeset/widget-usdh-migration.md
new file mode 100644
index 0000000..5cbd418
--- /dev/null
+++ b/.changeset/widget-usdh-migration.md
@@ -0,0 +1,5 @@
+---
+'@usdh-kit/widget': minor
+---
+
+Add `USDHMigration`, an exit widget that converts a HyperCore USDH balance back to USDC as USDH is sunset on Hyperliquid.
diff --git a/README.md b/README.md
index e67f85e..89b832c 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
+USDH sunset migration kit for Hyperliquid.
-TypeScript SDK for USDH on Hyperliquid.
-
-USDH is the native stablecoin on Hyperliquid, issued by Bridge and designed by Native Markets, with 50% of reserve revenue routed to the Hyperliquid Assistance Fund. `@usdh-kit/sdk` ships the retail-side plumbing (pair resolution, signing, transport) so apps and bots can convert into USDH without writing the Hyperliquid action layer themselves. `@usdh-kit/widget` is an embeddable React component on top of the SDK so dapps can drop in a swap form in a few lines.
+USDH is being sunset in favour of USDC. The final purpose of `usdh-kit` is to
+help users migrate remaining HyperCore USDH balances back to USDC, while keeping
+the original USDH integration work available as legacy reference code.
- **Source:** [github.com/sumfxn/usdh-kit](https://github.com/sumfxn/usdh-kit)
- **Issues:** [github.com/sumfxn/usdh-kit/issues](https://github.com/sumfxn/usdh-kit/issues)
- **USDH:** [usdh.com](https://usdh.com) (issued by [Bridge](https://bridge.xyz), designed by [Native Markets](https://www.nativemarkets.com))
-- **Hyperliquid:** [hyperliquid.xyz](https://hyperliquid.xyz) · [docs](https://hyperliquid.gitbook.io/hyperliquid-docs)
+- **Hyperliquid:** [hyperliquid.xyz](https://hyperliquid.xyz) / [docs](https://hyperliquid.gitbook.io/hyperliquid-docs)
## Status
Pre-release. Public API is unstable until `1.0.0`.
-What works today:
+This repo is in sunset/migration mode:
-- `getQuote()` and `swap()` for `USDC → USDH` and `USDH → USDC` end to end
-- `bridgeToCore()` for moving USDC from HyperEVM to HyperCore, with credit polling
-- `bridgeFromCore()` for moving linked USDC/USDH spot assets from HyperCore to HyperEVM
-- `getHypercoreBalance()` for spendable HyperCore balances (`total - hold`)
-- `getRoute()` / `preflightSwap()` to choose direct HyperCore swap vs HyperEVM bridge
-- `bridgeAndSwap()` for the common route → bridge → swap retail flow
-- Hyperliquid agent-wallet support for browser-safe L1 order signing
-- React widget with built-in source-chain selection (HyperEVM bridge or direct HyperCore swap), short-lived trading sessions, friendly errors, and full theming via CSS variables
+- `@usdh-kit/widget` exports `USDHMigration`, a wallet-gated `USDH -> USDC` exit widget.
+- `@usdh-kit/sdk` keeps the USDH quote, swap, bridge, and signing helpers needed for migration.
+- `USDHSwap` and `bridgeAndSwap()` remain available only as legacy compatibility surfaces.
+- HIP-4 and outcome helpers remain historical/read-only reference work, not the future product surface.
+- Future USDC or HIP-4 tooling should live in a separate repo/package with a clean name and API.
+- No release, merge, or npm publish is implied without explicit approval.
-Deferred to follow-up PRs:
+## Migration Widget
-- USDT pricing and swap (USDT/USDC/USDH double-hop)
-- Multi-chain source via LiFi/Squid (Ethereum, Arbitrum, Base)
+```tsx
+// app/layout.tsx
+import '@usdh-kit/widget/styles.css'
-## Install
+// app/page.tsx
+import { USDHMigration } from '@usdh-kit/widget'
-```sh
-pnpm add @usdh-kit/sdk
+export default function Page() {
+ return
+}
```
-For the React widget:
+The migration widget:
-```sh
-pnpm add @usdh-kit/widget wagmi viem @tanstack/react-query react react-dom
-```
+- reads the connected wallet through wagmi;
+- shows the user's HyperCore USDH balance;
+- reads the live `USDH/USDC` book before wallet writes;
+- never fakes a `1:1` receive estimate when the quote is unavailable;
+- asks for a short-lived Hyperliquid trading session before submitting the `USDH -> USDC` order;
+- does not bridge the resulting USDC out to HyperEVM.
-The widget depends on `@usdh-kit/sdk` internally. Install the SDK separately
-only when your app imports SDK APIs directly.
-
-## SDK quickstart
+## SDK Migration Flow
```ts
import { approveAgent, createUsdhKit } from '@usdh-kit/sdk'
-// Browser apps should use an approved Hyperliquid agent wallet for L1 orders.
await approveAgent({
network: 'mainnet',
signer: masterWalletSigner,
@@ -83,110 +84,63 @@ const kit = createUsdhKit({
slippageBps: 30,
})
-// quote
-const amount = 11_000_000n // 11 USDC; Hyperliquid spot orders must be >10 USDC
-
-const quote = await kit.getQuote({ from: 'USDC', amount })
-console.log(`would receive ~${quote.estimatedReceived} USDH`)
+const amount = 11_000_000n // 11 USDH; Hyperliquid spot orders must be >10 USDH
-// move USDC from HyperEVM to HyperCore (skip if already on HC)
-const bridge = await kit.bridgeToCore({ asset: 'USDC', amount })
+const quote = await kit.getQuote({ from: 'USDH', to: 'USDC', amount })
+console.log(`would receive ~${quote.estimatedReceived} USDC`)
-// swap on HyperCore via IOC limit at mid + slippageBps
-const result = await kit.swap({ from: 'USDC', amount })
-console.log(`got ${result.received} USDH for ${result.spent} USDC`)
-console.log(`realised slippage: ${result.slippageBps}bps`)
-
-// reverse direction on HyperCore
-const reverse = await kit.swap({ from: 'USDH', to: 'USDC', amount: 11_000_000n })
-console.log(`got ${reverse.received} USDC`)
-
-// or let the SDK route, bridge if needed, then swap
-const routed = await kit.bridgeAndSwap({
- from: 'USDC',
- amount,
- onProgress: (event) => console.log(event.phase),
-})
-console.log(`route: ${routed.route.sourceChain}`)
-console.log(`order: ${routed.swap.orderId}`)
+const result = await kit.swap({ from: 'USDH', to: 'USDC', amount })
+console.log(`got ${result.received} USDC for ${result.spent} USDH`)
```
-`swap()` submits an IOC limit order priced from the current mid: `USDC -> USDH` buys up to `mid + slippageBps`, while `USDH -> USDC` sells down to `mid - slippageBps`. The returned `result.slippageBps` is the realised slippage versus mid.
-
-## Widget quickstart
+`swap()` submits an IOC limit order priced from the current mid. The sunset path
+sells `USDH -> USDC` down to `mid - slippageBps`. Legacy `USDC -> USDH`
+acquisition remains in the package for existing integrators, but it is no longer
+the migration path.
-The widget reads the connected wallet from wagmi. Wrap your tree in `WagmiProvider` and `QueryClientProvider` (e.g. via ConnectKit or RainbowKit), import the stylesheet once at your app root, then drop the component in.
+## Packages
-```tsx
-// app/layout.tsx (Next.js)
-import '@usdh-kit/widget/styles.css'
-
-// app/page.tsx
-import { USDHSwap } from '@usdh-kit/widget'
-
-export default function Page() {
- return
-}
+```sh
+pnpm add @usdh-kit/sdk
+pnpm add @usdh-kit/widget wagmi viem @tanstack/react-query react react-dom
```
-The widget defaults to `theme="auto"` (follows the user's system). Force a palette with `` or ``. Override any colour token from your own stylesheet — see [docs/theming.md](./docs/theming.md).
-
-On first use, the widget asks the connected wallet to approve a short-lived Hyperliquid trading session. That agent signs only the HyperCore USDH order. If the route starts on HyperEVM, the connected wallet still submits the USDC approval/deposit transactions required for the Circle bridge.
-
-
-
-## Use cases
+## Archive Contents
-A few real flows the SDK is shaped for today. Runnable examples are still on the roadmap; until they land, treat these as the integration targets to copy into your own app.
+The repo also preserves the original USDH work:
-- **End-to-end CLI** — bridge + quote + swap from a private key on the command line. Smallest possible integration.
-- **Discord bot** — slash command that quotes `USDC → USDH`, confirms the route, then calls `bridgeAndSwap()` with progress updates.
-- **Subscription billing** — collect or rebalance USDC into USDH from a merchant wallet after a payment webhook.
-- **Treasury rebalance** — scheduled job that converts a fraction of HyperCore USDC above a floor into USDH. Designed for cron.
+- HyperCore/HyperEVM balance and bridge helpers;
+- USDH spot pair discovery;
+- Hyperliquid agent-wallet signing;
+- legacy `USDC -> USDH` swap and bridge flows;
+- experimental read-only HIP-4/outcome helpers;
+- a demo registry for migration and historical component references.
-## Features (V1)
-
-- `USDC → USDH` quote and swap via the canonical HL spot pair
-- `USDH → USDC` reverse swap on HyperCore
-- HyperEVM → HyperCore bridge with credit polling (`bridgeToCore`)
-- HyperCore → HyperEVM bridge-out for linked USDC/USDH spot assets (`bridgeFromCore`)
-- HyperCore balance, route/preflight helpers plus `bridgeAndSwap()` orchestration
-- Experimental read-only outcome market metadata, books, and mids
-- USDH-only spot order helpers for placing, cancelling, and reading USDH-pair orders
-- Wallet-agnostic `Signer` interface (works with viem, ethers, Privy, Turnkey, raw private key)
-- Approved Hyperliquid agent wallet flow for browser apps (`approveAgent`, `accountAddress`)
-- Read-only `InfoClient` (spotMeta, outcomeMeta, spot clearinghouse state, L2 book, allMids) for consumers building custom UIs
-- Typed error hierarchy rooted at `UsdhKitError`, including `BridgeAndSwapError` phase/cause context and `isBridgeAndSwapError()` for orchestration failures
-- `friendlyError()` helper to map SDK errors to short, copy-safe strings
-- React widget (`@usdh-kit/widget`) with light, dark and auto theming (WCAG AA defaults, CSS variables for integrator overrides)
-- npm provenance on every release
-- Mainnet and testnet support, no signing on read paths
+Those surfaces are kept for compatibility and reference. They are not a roadmap
+for turning `usdh-kit` into a USDC, generic spot, or HIP-4 SDK.
## Docs
-- [docs/architecture.md](./docs/architecture.md) — what the SDK does under the hood, in the order it does it (msgpack, signing, bridge polling, error model).
-- [docs/agent-wallets.md](./docs/agent-wallets.md) — secure signing patterns for builders: backend agent, browser trading session, externally managed signer.
-- [docs/bridge-and-swap.md](./docs/bridge-and-swap.md) — the full USDC HyperEVM → USDH HyperCore flow, including wallet prompts and recovery.
-- [docs/glossary.md](./docs/glossary.md) — Hyperliquid terms used across the SDK and widget (HyperEVM vs HyperCore, IOC, system address, weiDecimals, …).
-- [docs/theming.md](./docs/theming.md) — widget CSS variable list, override patterns, SSR-flash mitigation, Tailwind setup.
-- [docs/troubleshooting.md](./docs/troubleshooting.md) — common errors with concrete fixes (`MissingEvmWalletError`, `BridgeTimeoutError`, "borders render bright white", …).
+- [docs/README.md](./docs/README.md) - docs index
+- [docs/architecture.md](./docs/architecture.md) - SDK internals and legacy architecture
+- [docs/agent-wallets.md](./docs/agent-wallets.md) - secure signing patterns
+- [docs/bridge-and-swap.md](./docs/bridge-and-swap.md) - legacy acquisition flow and migration notes
+- [docs/glossary.md](./docs/glossary.md) - Hyperliquid terms used in the repo
+- [docs/roadmap.md](./docs/roadmap.md) - sunset roadmap and non-goals
+- [docs/theming.md](./docs/theming.md) - widget CSS variables and theming
+- [docs/troubleshooting.md](./docs/troubleshooting.md) - common errors and recovery notes
-## Runtime support
+## Runtime Support
-- Node.js >= 18.18 (native `fetch`, `AbortController`, `bigint`)
+- Node.js >= 18.18
- Bun >= 1.1
-- Modern evergreen browsers (Chrome >= 107, Safari >= 16, Firefox >= 104)
-- Edge runtimes (Cloudflare Workers, Vercel Edge)
-
-Consumers targeting older environments must downlevel via their bundler.
-
-## Why USDH
-
-Hyperliquid's primary stable was USDC, bridged from Arbitrum. USDH is native, fully reserved (cash plus US Treasuries), and routes 50% of reserve revenue to the Assistance Fund instead of an issuer. Apps that hold or pay out stables on Hyperliquid have a reason to prefer USDH; this SDK removes the friction.
+- Modern evergreen browsers
+- Edge runtimes with `fetch`, `AbortController`, and `bigint`
## Contributing
-See [`CONTRIBUTING.md`](./CONTRIBUTING.md). Security disclosures: [`SECURITY.md`](./SECURITY.md).
+See [`CONTRIBUTING.md`](./CONTRIBUTING.md). Security disclosures:
+[`SECURITY.md`](./SECURITY.md).
## License
diff --git a/apps/demo/next-env.d.ts b/apps/demo/next-env.d.ts
index 1b3be08..830fb59 100644
--- a/apps/demo/next-env.d.ts
+++ b/apps/demo/next-env.d.ts
@@ -1,5 +1,6 @@
///
///
+///
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/apps/demo/src/app/layout.tsx b/apps/demo/src/app/layout.tsx
index a9bab4d..6102f3c 100644
--- a/apps/demo/src/app/layout.tsx
+++ b/apps/demo/src/app/layout.tsx
@@ -9,7 +9,7 @@ import '../../../../packages/widget/src/styles.css'
export const metadata: Metadata = {
title: 'usdh-kit demo',
- description: 'Swap stables into USDH on Hyperliquid, end-to-end demo',
+ description: 'Migrate remaining USDH back to USDC on Hyperliquid.',
}
export const viewport: Viewport = {
diff --git a/apps/demo/src/app/page.tsx b/apps/demo/src/app/page.tsx
index cb78b94..35a4db4 100644
--- a/apps/demo/src/app/page.tsx
+++ b/apps/demo/src/app/page.tsx
@@ -11,7 +11,7 @@ export default function Home() {
- Swap stables into USDH on Hyperliquid.
+ Migrate remaining USDH back to USDC on Hyperliquid.
diff --git a/apps/demo/src/components/ComponentDocsShell.tsx b/apps/demo/src/components/ComponentDocsShell.tsx
index cb69892..faf0af7 100644
--- a/apps/demo/src/components/ComponentDocsShell.tsx
+++ b/apps/demo/src/components/ComponentDocsShell.tsx
@@ -48,7 +48,7 @@ export function ComponentDocsShell({ activeSlug, children }: ComponentDocsShellP
Components
- USDH surfaces for builder apps.
+ USDH sunset migration surfaces.
@@ -103,7 +103,7 @@ export function ComponentDocsShell({ activeSlug, children }: ComponentDocsShellP
Registry
- Copyable USDH and HIP-4 patterns with preview, code, contract, and examples.
+ A migration widget for remaining USDH balances, with the legacy swap kept only for
+ compatibility.
diff --git a/apps/demo/src/components/SwapSection.tsx b/apps/demo/src/components/SwapSection.tsx
index 0d69c39..5c29540 100644
--- a/apps/demo/src/components/SwapSection.tsx
+++ b/apps/demo/src/components/SwapSection.tsx
@@ -1,11 +1,11 @@
'use client'
-import { USDHSwap } from '@usdh-kit/widget'
+import { USDHMigration } from '@usdh-kit/widget'
export function SwapSection() {
return (
-
+
)
}
diff --git a/apps/demo/src/components/registry/previews/market-board.tsx b/apps/demo/src/components/registry/previews/market-board.tsx
index 385dd92..15c7d55 100644
--- a/apps/demo/src/components/registry/previews/market-board.tsx
+++ b/apps/demo/src/components/registry/previews/market-board.tsx
@@ -108,7 +108,7 @@ function QuoteSummary({
Quote summary
- Read-only context for a USDC to USDH quote.
+ Read-only context for a USDH to USDC migration quote.
diff --git a/apps/demo/src/components/registry/previews/widget.tsx b/apps/demo/src/components/registry/previews/widget.tsx
index f589036..6fa9f80 100644
--- a/apps/demo/src/components/registry/previews/widget.tsx
+++ b/apps/demo/src/components/registry/previews/widget.tsx
@@ -1,8 +1,8 @@
'use client'
import { type L2Book, createQuoteSummaryData } from '@usdh-kit/sdk'
-import { USDHSwap } from '@usdh-kit/widget'
-import { CheckCircle2, LockKeyhole, WalletCards } from 'lucide-react'
+import { USDHMigration, USDHSwap } from '@usdh-kit/widget'
+import { ArrowLeftRight, CheckCircle2, LockKeyhole, WalletCards } from 'lucide-react'
import { CardContent } from '@/components/ui/card'
import { cn } from '@/lib/utils'
@@ -48,7 +48,7 @@ export function UsdhWidgetPreview({
Swap module
- Packaged USDHSwap with read-only quote before connect.
+ Legacy USDHSwap preserved for historical integrations.
+ Packaged USDHMigration: convert a HyperCore USDH balance back to USDC.
+
+
+
+ exit path
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
function PreWalletContext({
snapshot,
compact,
diff --git a/apps/demo/src/lib/component-recipes.ts b/apps/demo/src/lib/component-recipes.ts
index 2a769de..23ee681 100644
--- a/apps/demo/src/lib/component-recipes.ts
+++ b/apps/demo/src/lib/component-recipes.ts
@@ -16,7 +16,7 @@ export function getComponentRecipes(slug: ComponentSlug): ComponentRecipe[] {
title: 'Drop in the swap entry',
description: 'Use the packaged widget as the only write boundary.',
steps: [
- 'Mount USDHSwap inside your wallet route.',
+ 'Mount USDHMigration inside your wallet route.',
'Keep quote context around it read-only.',
'Handle completion and analytics in the parent app.',
],
diff --git a/apps/demo/src/lib/component-registry.ts b/apps/demo/src/lib/component-registry.ts
index 1b45042..fcc3858 100644
--- a/apps/demo/src/lib/component-registry.ts
+++ b/apps/demo/src/lib/component-registry.ts
@@ -1,4 +1,5 @@
import {
+ ArrowLeftRight,
BookOpen,
Boxes,
Braces,
@@ -16,6 +17,7 @@ export type RegistryDataMode = 'sample' | 'live'
export type ComponentSlug =
| 'usdh-widget'
+ | 'usdh-migration'
| 'market-board'
| 'quote-readiness'
| 'outcome-reads'
@@ -85,12 +87,12 @@ const sdkInstall = 'pnpm add @usdh-kit/sdk'
export const componentEntries: ComponentEntry[] = [
{
slug: 'usdh-widget',
- title: 'USDH Widget',
+ title: 'USDH Swap Widget',
shortTitle: 'Widget',
- eyebrow: 'Drop-in swap',
+ eyebrow: 'Legacy swap',
category: 'Widget',
description:
- 'The packaged swap component for USDC to USDH flows, composed with pre-wallet quote context.',
+ 'The packaged legacy swap component for historical USDC to USDH flows, kept only for compatibility.',
icon: WalletCards,
tags: ['widget', 'swap', 'usdc', 'usdh', 'wallet'],
liveCapable: true,
@@ -133,16 +135,17 @@ export function SwapCard({ context }) {
},
],
useCase: {
- usedFor: 'Wallet swap entry, app dashboard modules, and onboarding flows.',
+ usedFor: 'Legacy USDH acquisition flows and historical integration reference.',
reads: 'Pair, best ask, spread, receive estimate, and quote readiness before connect.',
- doesNot: 'Change the widget API, submit swaps, or unlock writes before wallet/session state.',
+ doesNot:
+ 'Represent the migration path, change the widget API, or unlock writes before wallet/session state.',
},
usage: {
title: 'Pre-wallet swap entry',
language: 'tsx',
code: `export function SwapEntry({ quoteContext }) {
return (
-
+
@@ -150,7 +153,54 @@ export function SwapCard({ context }) {
}`,
},
installCommand: 'pnpm add @usdh-kit/widget wagmi viem',
- composition: 'Use USDHSwap as the write boundary and place read-only quote context around it.',
+ composition:
+ 'Keep USDHSwap as a legacy write boundary; prefer USDHMigration for the sunset path.',
+ },
+ {
+ slug: 'usdh-migration',
+ title: 'USDH Migration',
+ shortTitle: 'Migration',
+ eyebrow: 'Drop-in exit',
+ category: 'Widget',
+ description:
+ 'The primary sunset component: convert a HyperCore USDH balance back to USDC with wallet-gated writes.',
+ icon: ArrowLeftRight,
+ tags: ['widget', 'migration', 'usdh', 'usdc', 'exit'],
+ liveCapable: true,
+ visible: true,
+ snippets: [
+ {
+ title: 'Render migration widget',
+ language: 'tsx',
+ code: `'use client'
+
+import { USDHMigration } from '@usdh-kit/widget'
+import '@usdh-kit/widget/styles.css'
+
+export function UsdhMigrationEntry() {
+ return
+}`,
+ },
+ ],
+ useCase: {
+ usedFor: 'Wallet exit flows, USDH wind-down banners, and balance migration prompts.',
+ reads: 'HyperCore USDH balance, USDH/USDC pair, and the sell-side receive estimate.',
+ doesNot:
+ 'Bridge to HyperEVM, fake receive estimates, or submit swaps before wallet/session state.',
+ },
+ usage: {
+ title: 'USDH exit entry',
+ language: 'tsx',
+ code: `export function MigrationEntry() {
+ return (
+
+
+
+ )
+}`,
+ },
+ installCommand: 'pnpm add @usdh-kit/widget wagmi viem',
+ composition: 'Use USDHMigration as the write boundary for the USDH wind-down exit path.',
},
{
slug: 'market-board',
@@ -1062,26 +1112,18 @@ if (walletConnected && writesEnabled && draft.placeOrderInput) {
},
]
-export const visibleComponentEntries = componentEntries.filter((entry) => entry.visible)
+const visibleEntryOrder = new Map(
+ ['usdh-migration', 'usdh-widget'].map((slug, index) => [slug as ComponentSlug, index]),
+)
+
+export const visibleComponentEntries = componentEntries
+ .filter((entry) => entry.visible && visibleEntryOrder.has(entry.slug))
+ .sort((a, b) => (visibleEntryOrder.get(a.slug) ?? 999) - (visibleEntryOrder.get(b.slug) ?? 999))
export const componentSections: ComponentSection[] = [
{
- title: 'USDH',
- items: ['usdh-widget', 'market-board', 'quote-readiness'],
- },
- {
- title: 'HIP-4',
- items: [
- 'outcome-reads',
- 'outcome-market-row',
- 'outcome-odds-selector',
- 'outcome-order-book',
- 'outcome-position-row',
- ],
- },
- {
- title: 'Trading',
- items: ['order-ticket-mock'],
+ title: 'Migration',
+ items: ['usdh-migration', 'usdh-widget'],
},
]
diff --git a/apps/demo/src/lib/component-sdk-reads.ts b/apps/demo/src/lib/component-sdk-reads.ts
index 0ea66e1..974b0fe 100644
--- a/apps/demo/src/lib/component-sdk-reads.ts
+++ b/apps/demo/src/lib/component-sdk-reads.ts
@@ -13,7 +13,7 @@ export function getComponentSdkReads(slug: ComponentSlug): ComponentSdkRead[] {
return [
{
rawRead:
- 'USDHSwap owns its packaged quote flow; companion context can read spotMeta + l2Book.',
+ 'USDHSwap owns its legacy quote flow; companion context can read spotMeta + l2Book.',
adapter: 'createQuoteSummaryData from @usdh-kit/sdk for companion read context.',
produces: 'pair, best ask, spread, receive estimate',
parentOwns: 'wallet provider, page placement, analytics, and surrounding cache',
diff --git a/apps/demo/src/lib/wagmi.ts b/apps/demo/src/lib/wagmi.ts
index f532f8a..21d512f 100644
--- a/apps/demo/src/lib/wagmi.ts
+++ b/apps/demo/src/lib/wagmi.ts
@@ -15,7 +15,7 @@ export const wagmiConfig = createConfig(
},
walletConnectProjectId: WALLETCONNECT_PROJECT_ID,
appName: 'usdh-kit demo',
- appDescription: 'Swap stables into USDH on Hyperliquid',
+ appDescription: 'Migrate remaining USDH back to USDC on Hyperliquid',
appUrl: 'https://github.com/sumfxn/usdh-kit',
}),
)
diff --git a/docs/README.md b/docs/README.md
index 292a9e1..9bf41b8 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,22 +1,23 @@
# usdh-kit
-TypeScript SDK and React widget for USDH on Hyperliquid.
+USDH sunset migration kit for Hyperliquid.
-`usdh-kit` helps apps work with USDH without reimplementing Hyperliquid spot discovery, EIP-712 order signing, HyperEVM bridge transactions, or bridge-credit polling.
+`usdh-kit` helps apps migrate remaining HyperCore USDH balances back to USDC.
+The original SDK, widget, and HIP-4 work stays in the repo as legacy reference
+code, not as an active product roadmap.
## Packages
| Package | Purpose |
|---|---|
-| `@usdh-kit/sdk` | Quote, route, bridge, and swap USDH-focused flows. |
-| `@usdh-kit/widget` | Embeddable React swap widget built on the SDK. |
+| `@usdh-kit/sdk` | USDH quote, route, bridge, signing, and migration helpers kept for sunset support. |
+| `@usdh-kit/widget` | Embeddable React migration widget plus the legacy swap widget. |
## What works today
-* Quote and swap `USDC -> USDH` and `USDH -> USDC` on the canonical Hyperliquid spot pair.
-* Route from existing HyperCore USDC when available.
-* Bridge USDC from HyperEVM to HyperCore, wait for credit, then swap.
-* Bridge linked USDC/USDH spot assets from HyperCore back to HyperEVM.
+* Migrate `USDH -> USDC` on the canonical Hyperliquid spot pair.
+* Keep legacy `USDC -> USDH` quote and swap support for existing integrations.
+* Preserve bridge, discovery, and HIP-4 read-only helpers as archive/reference surfaces.
* Use approved Hyperliquid agent wallets so browser apps do not ask Rabby or other injected wallets to sign L1 order payloads directly.
* Display HyperEVM and HyperCore balances for USDC and USDH in the widget.
@@ -38,11 +39,11 @@ only when your app imports SDK APIs directly.
## Minimal widget
```tsx
-import { USDHSwap } from '@usdh-kit/widget'
+import { USDHMigration } from '@usdh-kit/widget'
import '@usdh-kit/widget/styles.css'
export default function Page() {
- return
+ return
}
```
@@ -67,17 +68,17 @@ const kit = createUsdhKit({
slippageBps: 30,
})
-const result = await kit.bridgeAndSwap({
- from: 'USDC',
+const result = await kit.swap({
+ from: 'USDH',
+ to: 'USDC',
amount: 11_000_000n,
- onProgress: (event) => console.log(event.phase),
})
-console.log(result.swap.orderId)
+console.log(result.orderId)
```
## Read next
-* [Bridge and swap flow](bridge-and-swap.md) explains the full user journey and Rabby prompts.
+* [Bridge and swap flow](bridge-and-swap.md) explains the legacy acquisition journey and Rabby prompts.
* [Agent wallets](agent-wallets.md) explains secure signing patterns for builders.
* [Architecture](architecture.md) documents the SDK internals.
diff --git a/docs/agent-wallets.md b/docs/agent-wallets.md
index d5d9186..a851c77 100644
--- a/docs/agent-wallets.md
+++ b/docs/agent-wallets.md
@@ -9,7 +9,7 @@ Some browser wallets reject or mis-handle that direct order-signing flow. The pr
| Role | What it does |
|---|---|
| Master wallet | Owns funds, signs agent approval, sends HyperEVM bridge transactions. |
-| Agent wallet | Signs Hyperliquid L1 orders such as `USDC -> USDH`. |
+| Agent wallet | Signs Hyperliquid L1 orders such as the sunset `USDH -> USDC` migration swap. |
| `accountAddress` | Tells the SDK which master account to read for balances, routes, and bridge ownership. |
The SDK never treats the agent as the funded account when `accountAddress` is set.
diff --git a/docs/architecture.md b/docs/architecture.md
index d35a3e6..b934533 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -2,6 +2,10 @@
What `@usdh-kit/sdk` actually does under the hood, in the order it does it.
+Status: this architecture is preserved for USDH sunset support and historical
+reference. The primary current path is `USDH -> USDC` migration; `USDC -> USDH`
+flows remain documented as legacy acquisition support.
+
## Layout
```
diff --git a/docs/bridge-and-swap.md b/docs/bridge-and-swap.md
index eb1d9b5..30cb8a8 100644
--- a/docs/bridge-and-swap.md
+++ b/docs/bridge-and-swap.md
@@ -1,8 +1,8 @@
# Bridge and swap flow
-The main retail path is `USDC HyperEVM -> USDH HyperCore`.
+This is the legacy acquisition flow for historical `USDC HyperEVM -> USDH HyperCore` integrations. The current sunset path is `USDH -> USDC` migration, usually through `USDHMigration` or `kit.swap({ from: 'USDH', to: 'USDC' })`.
-`bridgeAndSwap()` handles the full flow:
+`bridgeAndSwap()` still handles the full legacy flow:
1. quote the `USDH/USDC` spot pair
2. inspect spendable HyperCore USDC
diff --git a/docs/glossary.md b/docs/glossary.md
index 1962a3b..99e6f55 100644
--- a/docs/glossary.md
+++ b/docs/glossary.md
@@ -28,9 +28,9 @@ Hyperliquid-specific terms used across `@usdh-kit/sdk` and `@usdh-kit/widget`.
## Stablecoins
-**USDH** — Hyperliquid's native stablecoin, issued by Bridge and designed by Native Markets. Backed by cash + US Treasuries. 50% of reserve revenue routes to the Hyperliquid Assistance Fund.
+**USDH** — Hyperliquid stablecoin issued by Bridge and designed by Native Markets. USDH is being sunset in favour of USDC, so current `usdh-kit` work is focused on migration and historical reference.
-**USDC (HyperEVM)** — Circle's USDC bridged onto HyperEVM. The default source asset for `@usdh-kit/sdk`.
+**USDC (HyperEVM)** — Circle's USDC bridged onto HyperEVM. It was the default source asset for the legacy `USDC -> USDH` acquisition flow.
**USDT** — Tether's USDT. Pricing and swap support are deferred (USDT/USDC/USDH double-hop).
diff --git a/docs/roadmap.md b/docs/roadmap.md
index 628c0e9..0e895d7 100644
--- a/docs/roadmap.md
+++ b/docs/roadmap.md
@@ -1,306 +1,70 @@
# Roadmap
-> Status: living plan. Tracks 1-4 have landed. Track 5 HyperEVM direct swap is
-> paused as a later spike until liquidity, routing, allowance, and failure modes
-> are validated. Release remains intentionally gated until live testnet/IRL
-> validation and generated release output are reviewed.
-> Direction: keep `usdh-kit` centered on USDH, but expand from "obtain USDH via
-> USDC" to "interact cleanly with USDH surfaces on Hyperliquid".
+> Status: sunset plan. `usdh-kit` stays focused on USDH migration and
+> maintenance. It should not become a generic USDC, spot, or HIP-4 SDK.
+> Release remains gated on review, CI, and explicit approval.
## TL;DR
-`usdh-kit` should not become a generic Hyperliquid SDK. It should expose the
-small set of primitives that make USDH useful:
+The repo now has two jobs:
-1. discover USDH markets and USDH-denominated surfaces
-2. work with USDH outcomes first, if markets are natively `/USDH`
-3. trade USDH markets through a focused order API
-4. keep the current USDC -> USDH acquisition flow simple
-5. treat HyperEVM direct swaps as a separate spike until liquidity/routing is
- validated
+1. Help users migrate remaining HyperCore USDH back to USDC.
+2. Preserve the SDK/widget/demo work as open-source legacy reference material.
-## Current SDK baseline
+Future HIP-4 SDK or UI tooling should live in a separate repo/package with a
+clean name and API. `usdh-kit` should not absorb that future product surface.
-What already works:
-
-- `USDC -> USDH` quote and swap on HyperCore
-- HyperEVM -> HyperCore bridge for USDC
-- HyperCore balance reads and route/preflight helpers
-- `bridgeAndSwap()` for route -> optional bridge -> swap
-- USDH spot discovery with `listPairs`, `getPair`, `getBook`, and `getMids`
-- experimental read-only outcome discovery with `listOutcomeMarkets`,
- `getOutcomeMarket`, `getOutcomeBook`, and `getOutcomeMids`
-- USDH-only spot orders with `placeOrder`, `cancelOrder`, `getOpenOrders`, and
- `getOrderStatus`
-- `InfoClient` reads for `spotMeta`, `outcomeMeta`,
- `spotClearinghouseState`, `l2Book`, `allMids`, `frontendOpenOrders`, and
- `orderStatus`
-- typed lifecycle errors, including `BridgeAndSwapError` and
- `isBridgeAndSwapError()`
-- React widget on top of the SDK
-
-- `USDH -> USDC` HyperCore reverse swaps
-- `bridgeFromCore()` for linked USDC/USDH spot assets moving from HyperCore to
- HyperEVM
-
-This remains the core retail path. New roadmap items should preserve that simple
-path instead of forcing integrators into a broader trading abstraction.
-
-## Track 1 - Discovery USDH
-
-Owner: @Yaugourt
-
-Status: landed for spot market discovery in PR #49. HIP-3 remains watchlist,
-and outcomes continue as the separate Track 2 surface.
-
-Expose the markets and surfaces related to USDH. Start with spot markets, keep
-outcomes clearly in scope, and keep HIP-3 as experimental/watchlist until the
-shape is validated.
-
-### Goals
-
-- Replace one-off `USDH/USDC` pair lookup with USDH-aware discovery.
-- Let consumers list USDH spot markets without hand-parsing Hyperliquid metadata.
-- Preserve explicit orientation: USDH can be base or quote.
-- Return enough metadata for UI, quoting, and later order placement.
-- Avoid promising generic Hyperliquid market discovery.
-
-### Proposed API
-
-```ts
-kit.listPairs({ quote?: 'USDH', kind?: 'spot' }): Promise
-kit.getPair({ base, quote, kind?: 'spot' }): Promise
-kit.getBook(pair: string, opts?: { nSigFigs?: NSigFigs }): Promise
-kit.getMids(opts?: { quote?: 'USDH' }): Promise>
-```
-
-Types should make orientation explicit:
-
-```ts
-type UsdhPair = {
- kind: 'spot'
- name: string
- base: string
- quote: string
- usdhRole: 'base' | 'quote'
- index: number
- tokens: [number, number]
-}
-```
-
-### Scope
-
-- Shipped:
- - spot pairs where USDH is base or quote
- - book/mid helpers for those pairs
- - caching by pair name or token tuple
- - testnet/mainnet token-index handling behind existing network config
-- Watchlist:
- - HIP-3 USDH-denominated markets
- - outcome write support, only after denomination/settlement behavior is
- verified
-- Out of scope:
- - generic pair discovery for all assets
- - generic perps SDK
- - routing across arbitrary token graphs
-
-## Track 2 - Outcomes USDH
-
-Owner: @sumfxn
-
-Status: landed as PR #51. The API is read-only and experimental: metadata, side
-encoding helpers, books, and mids only. It does not add outcome orders,
-cancellations, or settlement/denomination claims.
-
-Prioritize this if outcomes are natively denominated in USDH. This is a stronger
-USDH use case than generic perps because it creates direct demand for USDH as the
-settlement/quote asset.
-
-### Goals
-
-- Discover USDH-denominated outcome markets.
-- Read outcome books and mids with the same ergonomics as spot.
-- Make outcome support clearly experimental until tested against live/testnet
- markets.
-- Keep the outcome API narrow and product-shaped.
-
-### Proposed API
-
-```ts
-kit.listOutcomeMarkets(): Promise
-kit.getOutcomeMarket({ outcome }): Promise
-kit.getOutcomeBook({ outcome, side, nSigFigs? }): Promise
-kit.getOutcomeMids(): Promise>
-```
-
-Possible later write path:
-
-```ts
-kit.placeOutcomeOrder({
- market,
- side,
- price,
- size,
- tif,
-}): Promise
-```
-
-### Spike findings
-
-- `outcomeMeta` exposes a separate outcome namespace from spot pairs.
-- Side coins use encoded `#...` names derived from outcome id and binary side.
-- Live read-only probes validate `outcomeMeta`, `l2Book`, and outcome mids on
- mainnet and testnet.
-- USDH settlement/denomination remains unclaimed until verified separately.
-- Write support remains out of scope.
+## Current Baseline
-## Track 3 - Targeted USDH trading
-
-Owner: @Yaugourt
-
-Status: landed as PR #54. The final API stays USDH-scoped while accepting both
-live Hyperliquid pair names such as `@230` and ergonomic token aliases such as
-`USDH/USDC`.
-
-Build only the trading primitives needed for USDH markets:
-
-```ts
-kit.placeOrder({ pair, side, size, price?, tif?, slippageBps? })
-kit.cancelOrder({ pair, oid })
-kit.getOpenOrders({ pair? })
-kit.getOrderStatus({ pair, oid })
-```
-
-This should be a focused USDH-market order layer, not a full Hyperliquid SDK.
-`pair` accepts the live `listPairs()` name such as `@230` and ergonomic token
-aliases such as `USDH/USDC` or `HYPE/USDH`; reads remain filtered to USDH-bearing
-spot pairs.
-
-### Scope
-
-- In scope:
- - `placeOrder`
- - `cancelOrder`
- - `getOpenOrders`
- - `getOrderStatus`
- - shared order formatting/signing reused by `swap()`
- - typed order errors and `friendlyError()` mappings
-- Later:
- - modify order
- - batch helpers
- - vault/subaccount support
- - agent wallets
- - TWAP/dead-man switch
-
-`swap()` should remain a high-level convenience wrapper, not be replaced by a
-lower-level order API in docs.
-
-## Track 4 - Useful USDH flows
-
-Status: landed in PR #56. Reverse swap and bridge-out are implemented in the SDK
-with conservative constraints. No live write-path bridge/swap test has been run
-yet, so release remains gated on IRL validation.
-
-Keep the UX simple:
-
-- `USDC -> USDH` remains the core path
-- add `USDH -> USDC`
-- add `bridgeFromCore`
-- avoid arbitrary multi-hop routing for now
-
-### Proposed additions
-
-```ts
-kit.swap({ from: 'USDH', to: 'USDC', amount, ... })
-kit.bridgeFromCore({ asset: 'USDC' | 'USDH', amount })
-```
-
-Implementation notes from PR #56:
-
-- `USDH -> USDC` is HyperCore-only. HyperEVM direct swap stays a separate
- Track 5 spike.
-- `bridgeFromCore()` uses Hyperliquid `sendAsset` to the token system address.
-- The HyperEVM recipient is the Core action sender, so v1 does not expose an
- arbitrary `recipient`.
-- Approved agent wallets cannot bridge funds out for a master account;
- `signer.address` must match `accountAddress`.
-- Live validation for #56 is read-only only: mainnet/testnet `spotMeta`,
- `l2Book`, SDK `getQuote()`, and SDK `getRoute()`.
-
-Multi-hop via arbitrary intermediate assets should stay out of scope until there
-is a clear product need and enough tests to make route selection safe.
-
-## Track 5 - HyperEVM direct swap
-
-Treat as a separate spike.
-
-Before promising this in public API, validate:
-
-- USDH liquidity on HyperEVM
-- which DEX/router to integrate first
-- quote accuracy
-- slippage and `minOut` behavior
-- allowance flow
-- gas and failure modes
+What already works:
-Possible future shape:
+- `USDH -> USDC` HyperCore migration swaps.
+- `USDHMigration`, a wallet-gated React migration widget.
+- Legacy `USDC -> USDH` quote/swap and `bridgeAndSwap()` flows for historical integrations.
+- HyperEVM -> HyperCore bridge for USDC.
+- HyperCore -> HyperEVM bridge-out for linked USDC/USDH spot assets.
+- USDH spot discovery with `listPairs`, `getPair`, `getBook`, and `getMids`.
+- Experimental read-only outcome discovery with `listOutcomeMarkets`,
+ `getOutcomeMarket`, `getOutcomeBook`, and `getOutcomeMids`.
+- USDH-scoped spot orders with `placeOrder`, `cancelOrder`, `getOpenOrders`, and
+ `getOrderStatus`.
+- Demo registry patterns for migration UX and archived HIP-4 read-only references.
-```ts
-kit.evmQuote({ from, to, amount }): Promise
-kit.evmSwap({ from, to, amount, minOut?, recipient?, deadline? }): Promise
-```
+## Release Gate
-Do not block shipped tracks on this.
+A final release, if approved, should be explicitly framed as a sunset/migration
+release:
-## Landed Split
+- Promote `USDHMigration` as the primary widget.
+- Keep `USDHSwap` available but documented as legacy/historical.
+- Do not publish a generic spot SDK.
+- Do not publish React HIP-4 components from this repo.
+- Do not add new USDH acquisition roadmap items.
+- Keep changesets intentional and review package output before publish.
-The initial SDK expansion landed as four focused PRs:
+## HIP-4 Direction
-1. @Yaugourt: Track 1, Discovery USDH
- - spot USDH market discovery first
- - book/mid helpers
- - API and tests only for confirmed metadata shape
- - leave hooks/types clean enough for outcomes, but do not implement outcomes
- in the same PR
+The HIP-4 work in this repo is useful as prior art and reference material:
-2. @sumfxn: Track 2, Outcomes USDH
- - inspect real outcome metadata/API shape
- - land a read-only experimental API if the shape is stable enough
- - document any unknowns before write support
+- outcome market reads;
+- side coin decoding;
+- book summaries;
+- builder-oriented UI patterns in `apps/demo`.
-3. @Yaugourt: Track 3, Targeted USDH trading
- - spot order placement and cancellation for USDH-bearing pairs
- - USDH-filtered open orders and order status reads
- - live pair names plus token-pair aliases
- - no generic Hyperliquid account/order surface
+It is not the final HIP-4 product surface. If the team proceeds with HIP-4
+tooling, start a new repo/package and decide the public boundaries there:
-4. @sumfxn: Track 4, Useful USDH flows
- - `USDH -> USDC` reverse swap on HyperCore
- - `bridgeFromCore()` for linked USDC/USDH spot assets
- - no arbitrary bridge-out recipient
- - no HyperEVM direct swap or arbitrary multi-hop routing
+- headless SDK helpers;
+- optional hooks package;
+- no bundled visual design system unless explicitly scoped;
+- clear write/read boundaries;
+- live market fixtures and docs from day one.
## Non-goals
-- Becoming a generic Hyperliquid SDK
-- Generic perps support
-- Arbitrary routing/multi-hop
-- HyperEVM direct swap before liquidity and router validation
-- Broad agent/vault support before the USDH-specific API is settled
-
-## Decisions And Open Questions
-
-Resolved decisions:
-
-1. `listPairs()` is spot-only and USDH-scoped.
-2. Outcomes use separate `listOutcomeMarkets()` style APIs.
-3. Track 3 supports only USDH-bearing spot pairs, not generic Hyperliquid
- trading.
-4. `bridgeFromCore()` v1 is sender-owned only; no arbitrary recipient.
-
-Open questions:
-
-1. Which API should expose HIP-3 USDH markets, if any? Proposed: experimental
- watchlist after spot/outcomes.
-2. Which examples should become first-class maintained demos before the next
- release?
+- Becoming a generic Hyperliquid SDK.
+- Becoming a generic USDC spot SDK.
+- Expanding `@usdh-kit/widget` into a broad widget suite.
+- Publishing registry/demo UI components as package API.
+- Adding new USDH acquisition features while USDH is sunset.
+- Merging the USDC-canonical spike as-is.
diff --git a/docs/theming.md b/docs/theming.md
index 233b00c..4cb8989 100644
--- a/docs/theming.md
+++ b/docs/theming.md
@@ -5,9 +5,9 @@
## The `theme` prop
```tsx
- // default — follows prefers-color-scheme
- // force dark
- // force light
+ // default - follows prefers-color-scheme
+ // force dark
+ // force light
```
`auto` listens to the system preference via `matchMedia('(prefers-color-scheme: dark)')` and re-renders when it changes. SSR renders dark by default to match the most common DeFi expectation; the client effect corrects to light if the system says so. This causes a one-frame flash for light-mode auto users; the standard fix is to read a server-side cookie and pass it as `theme` from the parent (see Next.js example below).
@@ -62,19 +62,19 @@ Override any token in your own stylesheet, loaded **after** the widget's stylesh
}
```
-You don't need to override every token — unset ones inherit from the defaults.
+You don't need to override every token - unset ones inherit from the defaults.
## Loading the stylesheet
The widget's compiled stylesheet is exposed at `@usdh-kit/widget/styles.css`. Import it once at your application root:
```ts
-// Next.js — app/layout.tsx
+// Next.js - app/layout.tsx
import '@usdh-kit/widget/styles.css'
```
```ts
-// Vite — main.tsx
+// Vite - main.tsx
import '@usdh-kit/widget/styles.css'
```
@@ -91,7 +91,7 @@ import { cookies } from 'next/headers'
const themeCookie = cookies().get('usdh-theme')?.value as 'dark' | 'light' | undefined
const theme = themeCookie ?? 'auto'
-return
+return
```
Then on the client, write the cookie when the resolved theme is known:
@@ -108,7 +108,7 @@ function ThemeCookie({ theme }: { theme: 'dark' | 'light' | 'auto' }) {
}
```
-`useEffectiveTheme(theme)` is the same hook the widget uses internally — you can also call it standalone if you're building custom UI with the SDK and want auto-detection without rendering the widget.
+`useEffectiveTheme(theme)` is the same hook the widget uses internally - you can also call it standalone if you're building custom UI with the SDK and want auto-detection without rendering the widget.
## Tailwind setup
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index 19ea012..9c98ed3 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -153,9 +153,9 @@ Without this, every `var(--usdh-*)` falls back to `currentColor`. See [theming](
Default `theme="auto"` follows `prefers-color-scheme`. If your app's page background is hardcoded dark while your OS is in light mode, you'll see a light widget on a dark page. Either:
- Make your page background follow `prefers-color-scheme` too (recommended), or
-- Force the widget with ``
+- Force the widget with ``
-### SSR flash light → dark on first paint
+### SSR flash light -> dark on first paint
Standard `prefers-color-scheme` tradeoff. See the cookie-based fix in [theming](./theming.md#avoiding-the-ssr-flash).
@@ -163,7 +163,7 @@ Standard `prefers-color-scheme` tradeoff. See the cookie-based fix in [theming](
### Quote refreshes feel slow
-`getQuote` debounces by 400ms in the widget. If you're calling the SDK directly, you control the cadence — `getQuote` is a single `/info` round-trip with no signing.
+`getQuote` debounces by 400ms in the widget. If you're calling the SDK directly, you control the cadence - `getQuote` is a single `/info` round-trip with no signing.
### Bundle size is too large
diff --git a/packages/sdk/README.md b/packages/sdk/README.md
index b60144a..5da49ff 100644
--- a/packages/sdk/README.md
+++ b/packages/sdk/README.md
@@ -6,29 +6,35 @@
**Current SDK version:** `0.3.0`
-TypeScript SDK for USDH on Hyperliquid.
+TypeScript SDK for USDH sunset support on Hyperliquid.
-USDH is the native stablecoin on Hyperliquid, issued by Bridge and designed by Native Markets, with 50% of reserve revenue routed to the Hyperliquid Assistance Fund. `@usdh-kit/sdk` ships the retail-side plumbing (pair resolution, signing, transport) so apps and bots can convert into USDH without writing the Hyperliquid action layer themselves.
+`@usdh-kit/sdk` now serves migration and maintenance use cases: pair resolution, signing, transport, and order helpers for moving remaining USDH balances back to USDC. The original USDH and HIP-4 work remains available as legacy reference code.
-Contributors: [Yaugourt](https://x.com/Yaugourt) · [Sumfxn](https://x.com/sumfxn)
+Contributors: [Yaugourt](https://x.com/Yaugourt) / [Sumfxn](https://x.com/sumfxn)
## Status
Pre-release. Public API is unstable until `1.0.0`.
+USDH sunset status: this package is in maintenance/migration mode. It keeps the
+USDH read/write primitives needed for users to migrate back to USDC and preserves
+the HIP-4 read-only work as reference code. Future HIP-4 tooling should live in a
+separate repo/package rather than turning `usdh-kit` into a generic spot SDK.
+
What works today:
-* `getQuote()` and `swap()` for `USDC → USDH` and `USDH → USDC` end to end (signing + msgpack + IOC limit submission)
+* `getQuote()` and `swap()` for the sunset `USDH -> USDC` migration path
+* Legacy `USDC -> USDH` quote and swap support for historical integrations
* `bridgeToCore()` for moving USDC from HyperEVM to HyperCore, with credit polling
* `bridgeFromCore()` for moving linked USDC/USDH spot assets from HyperCore to HyperEVM
* `getHypercoreBalance()` for spendable HyperCore balances (`total - hold`)
* `getRoute()` / `preflightSwap()` for HyperCore-vs-HyperEVM source selection
-* `bridgeAndSwap()` for route → optional bridge → swap orchestration
+* Legacy `bridgeAndSwap()` for route -> optional bridge -> swap orchestration
* USDH spot market discovery (`listPairs`, `getPair`, `getBook`, `getMids`)
* Experimental read-only outcome market metadata, books, and mids
* Read-only `InfoClient` (spotMeta, outcomeMeta, spotClearinghouseState, L2 book, allMids)
-Deferred to follow-up PRs: USDT pricing/swap and multi-chain source.
+No new USDH acquisition roadmap is planned while USDH is sunset.
## Install
@@ -39,28 +45,13 @@ pnpm add @usdh-kit/sdk
## Quickstart
```ts
-import { BridgeTimeoutError, createUsdhKit, isBridgeAndSwapError } from '@usdh-kit/sdk'
+import { createUsdhKit } from '@usdh-kit/sdk'
const kit = createUsdhKit({ network: 'mainnet', signer, evmWallet, slippageBps: 30 })
-const amount = 11_000_000n // 11 USDC; Hyperliquid spot orders must be >10 USDC
-
-try {
- const result = await kit.bridgeAndSwap({
- from: 'USDC',
- amount,
- onProgress: (event) => console.log(event.phase),
- })
-
- console.log(`got ${result.swap.received} USDH for ${result.swap.spent} USDC`)
-} catch (err) {
- if (isBridgeAndSwapError(err)) {
- console.error(`${err.phase} failed`, err.cause)
- if (err.cause instanceof BridgeTimeoutError) {
- console.log(`bridge tx ${err.cause.txHash} is still pending HyperCore credit`)
- }
- }
- throw err
-}
+const amount = 11_000_000n // 11 USDH; Hyperliquid spot orders must be >10 USDH
+
+const result = await kit.swap({ from: 'USDH', to: 'USDC', amount })
+console.log(`got ${result.received} USDC for ${result.spent} USDH`)
```
`swap()` submits an IOC limit order priced from the book mid plus/minus
@@ -103,22 +94,24 @@ Backend and bot builders can provide an already-approved agent signer from a pri
`getQuote()` returns a mid-price snapshot with a 30-second validity window.
```ts
-const quote = await kit.getQuote({ from: 'USDC', amount: 11_000_000n })
+const quote = await kit.getQuote({ from: 'USDH', to: 'USDC', amount: 11_000_000n })
if (Date.now() < quote.validUntil) {
console.log(`mid-price on ${quote.pair}: ${quote.midPrice}`)
- console.log(`would receive ~${quote.estimatedReceived} USDH`)
+ console.log(`would receive ~${quote.estimatedReceived} USDC`)
}
-const reverse = await kit.getQuote({ from: 'USDH', to: 'USDC', amount: 11_000_000n })
-console.log(`would receive ~${reverse.estimatedReceived} USDC`)
+// Legacy acquisition remains supported for existing integrators.
+const legacy = await kit.getQuote({ from: 'USDC', amount: 11_000_000n })
+console.log(`would receive ~${legacy.estimatedReceived} USDH`)
```
## Route and preflight
`getHypercoreBalance()` returns total, held, and spendable HyperCore balance for
a source stable. `getRoute()` decides whether `USDC -> USDH` can swap directly
-from HyperCore or needs to bridge from HyperEVM first. `USDH -> USDC` is
-HyperCore-only: bridge USDH to HyperCore first, swap, then call
+from HyperCore or needs to bridge from HyperEVM first. This is legacy
+acquisition support. The sunset `USDH -> USDC` path is HyperCore-only: bridge
+USDH to HyperCore first, swap, then call
`bridgeFromCore()` if you need the resulting USDC on HyperEVM.
```ts
@@ -201,14 +194,17 @@ const outcomeMids = await kit.getOutcomeMids()
console.log(market.name, yesBook.coin, outcomeMids[market.sides[0].coin])
```
-## Experimental HIP-4 builder helpers
+## Archived HIP-4 builder helpers
-The SDK also exports public, experimental, headless helpers for app builders.
+The SDK also exports public, experimental, headless helpers that were built for
+the HIP-4 registry work.
They do not render React components; they turn raw SDK reads into UI-ready data
contracts for HIP-4 event cards, market rows, side selectors, order books,
positions, plus USDH quote guards and order drafts.
-These helpers are additive and read-only/draft-only. Until `1.0.0`, treat the
+These helpers are additive and read-only/draft-only. They are preserved as
+reference material in `usdh-kit`, not as the future HIP-4 product surface.
+Until `1.0.0`, treat the
exact return shapes as pre-release API, but prefer them over app-local parsing:
they centralize side-coin encoding, quote health checks, decimal-safe position
math, and signer-ready order draft validation.
@@ -325,14 +321,13 @@ Package boundaries:
| Layer | Import today | Owns |
| --- | --- | --- |
-| `@usdh-kit/sdk` | Read clients, USDH spot discovery, HIP-4 metadata, order methods, and builder data helpers. | Typed reads, normalization, checks, and signer-ready input shapes. |
-| `@usdh-kit/widget` | The drop-in USDH swap widget. | A packaged swap UI with wallet-gated writes. |
-| `apps/demo` registry | Copy/paste React patterns only. | Example component composition, docs, and visual states. |
+| `@usdh-kit/sdk` | Migration reads/writes, legacy USDH spot helpers, HIP-4 reference helpers. | Typed reads, normalization, checks, and signer-ready input shapes. |
+| `@usdh-kit/widget` | The drop-in USDH migration widget plus legacy swap widget. | Packaged wallet-gated migration UI. |
+| `apps/demo` registry | Migration and archived reference patterns only. | Example component composition, docs, and visual states. |
| Your app | Your product shell. | Routing, cache policy, wallet/session state, balances, PnL, settlement, and final writes. |
-No React hooks or HIP-4 UI package is published in this release. A future
-`@usdh-kit/react` package, if added, should stay hooks-only with optional cache
-adapters and no bundled visual design system.
+No React hooks or HIP-4 UI package is published from this repo. Future HIP-4
+tooling should be designed in a separate repo/package with a clean name and API.
## Trade USDH spot pairs
diff --git a/packages/sdk/package.json b/packages/sdk/package.json
index 9692380..34937d6 100644
--- a/packages/sdk/package.json
+++ b/packages/sdk/package.json
@@ -1,7 +1,7 @@
{
"name": "@usdh-kit/sdk",
"version": "0.3.0",
- "description": "TypeScript SDK for USDH on Hyperliquid",
+ "description": "TypeScript SDK for USDH sunset support on Hyperliquid",
"license": "MIT",
"author": "sumfxn",
"homepage": "https://github.com/sumfxn/usdh-kit#readme",
diff --git a/packages/widget/README.md b/packages/widget/README.md
index 1fa6478..214269f 100644
--- a/packages/widget/README.md
+++ b/packages/widget/README.md
@@ -1,6 +1,6 @@
# @usdh-kit/widget
-Embeddable React widget for swapping stablecoins into USDH on Hyperliquid.
+Embeddable React widgets for USDH sunset migration on Hyperliquid.
## Install
@@ -18,17 +18,19 @@ The widget reads the connected wallet from wagmi. Wrap your tree in `WagmiProvid
The root widget entry is ESM-only because the React wallet stack it composes is ESM-first. CommonJS projects can still load `@usdh-kit/widget/styles.css` and `@usdh-kit/widget/tailwind-content`, but should import the widget from an ESM module or through their app bundler.
```tsx
-import { USDHSwap } from '@usdh-kit/widget'
+import { USDHMigration } from '@usdh-kit/widget'
import '@usdh-kit/widget/styles.css'
export default function Page() {
- return
+ return
}
```
-The full widget manages a short-lived Hyperliquid agent wallet session before swapping. For custom UIs, prefer the SDK primitives (`approveAgent`, `accountAddress`, and `createUsdhKit`) so reads use the master wallet while L1 orders are signed by an approved agent.
+`USDHMigration` is the primary sunset widget. It converts HyperCore USDH back to USDC with wallet-gated writes and never displays a fake receive estimate when the live quote is unavailable. `USDHSwap` remains exported only as a legacy `USDC -> USDH` widget for historical integrations.
-For HyperEVM-funded swaps, users should expect:
+The migration widget manages a short-lived Hyperliquid agent wallet session before submitting an order. For custom UIs, prefer the SDK primitives (`approveAgent`, `accountAddress`, and `createUsdhKit`) so reads use the master wallet while L1 orders are signed by an approved agent.
+
+For legacy HyperEVM-funded `USDHSwap` flows, users should expect:
1. one wallet signature to enable the trading session on first use
2. one USDC approval transaction if allowance is not already sufficient
@@ -67,6 +69,26 @@ import '@usdh-kit/widget/styles.css'
## Props
+```ts
+type USDHMigrationProps = {
+ network: 'mainnet' | 'testnet'
+ hideNetworkToggle?: boolean
+ hideAttribution?: boolean
+ theme?: 'dark' | 'light' | 'auto'
+ defaultSlippageBps?: number
+ defaultAmount?: string
+ onMigrationComplete?: (result: {
+ orderId: string
+ spentUsdh: bigint
+ receivedUsdc: bigint
+ price: bigint
+ slippageBps: number
+ }) => void
+}
+```
+
+Legacy swap widget:
+
```ts
type USDHSwapProps = {
network: 'mainnet' | 'testnet'
@@ -83,7 +105,7 @@ type USDHSwapProps = {
}
```
-`network` is required. Pass `'mainnet'` for production swaps and `'testnet'` for the Hyperliquid testnet.
+`network` is required. Pass `'mainnet'` for production migration flows and `'testnet'` for the Hyperliquid testnet.
## License
diff --git a/packages/widget/package.json b/packages/widget/package.json
index 5cbea13..6ec277a 100644
--- a/packages/widget/package.json
+++ b/packages/widget/package.json
@@ -1,7 +1,7 @@
{
"name": "@usdh-kit/widget",
"version": "0.1.1",
- "description": "Embeddable React widget for swapping stablecoins into USDH on Hyperliquid",
+ "description": "Embeddable React widgets for USDH sunset migration on Hyperliquid",
"license": "MIT",
"author": "sumfxn",
"homepage": "https://github.com/sumfxn/usdh-kit#readme",
diff --git a/packages/widget/src/components/action-button.tsx b/packages/widget/src/components/action-button.tsx
index 84665b8..d58dbd7 100644
--- a/packages/widget/src/components/action-button.tsx
+++ b/packages/widget/src/components/action-button.tsx
@@ -13,6 +13,12 @@ export function ActionButton(props: {
needsTradingSession: boolean
disabled: boolean
onClick: () => void
+ /** Pay-side token ticker shown in balance/minimum labels. Defaults to `'USDC'`. */
+ payTicker?: 'USDC' | 'USDH'
+ actionLabel?: string
+ bridgeLabel?: string
+ connectLabel?: string
+ workingLabel?: string
}) {
const {
phase,
@@ -24,6 +30,11 @@ export function ActionButton(props: {
needsTradingSession,
disabled,
onClick,
+ payTicker = 'USDC',
+ actionLabel = 'Swap',
+ bridgeLabel = 'Bridge and swap',
+ connectLabel = 'Connect wallet to swap',
+ workingLabel = 'Swapping',
} = props
return (
) : phase === 'swapping' ? (
<>
- Swapping
+ {workingLabel}
>
) : insufficient ? (
- `Insufficient ${sourceChain === 'evm' ? 'HyperEVM' : 'HyperCore'} USDC`
+ `Insufficient ${sourceChain === 'evm' ? 'HyperEVM' : 'HyperCore'} ${payTicker}`
) : belowMinOrderValue ? (
- 'Minimum 11 USDC'
+ `Minimum 11 ${payTicker}`
) : !isConnected ? (
- 'Connect wallet to swap'
+ connectLabel
) : needsTradingSession ? (
'Enable trading session'
) : requiresBridge ? (
- 'Bridge and swap'
+ bridgeLabel
) : (
- 'Swap'
+ actionLabel
)}
)
diff --git a/packages/widget/src/components/pay-card.tsx b/packages/widget/src/components/pay-card.tsx
index 278e557..59c585e 100644
--- a/packages/widget/src/components/pay-card.tsx
+++ b/packages/widget/src/components/pay-card.tsx
@@ -1,4 +1,4 @@
-import { UsdcIcon } from '../icons.js'
+import { UsdcIcon, UsdhIcon } from '../icons.js'
import { type SourceChain, SourceChainPill } from './source-chain-pill.js'
import { TokenChip } from './token-chip.js'
@@ -6,11 +6,14 @@ export function PayCard(props: {
amountStr: string
onAmountChange: (next: string) => void
inputDisabled: boolean
- sourceChain: SourceChain
- onSourceToggle: () => void
+ /** Source-chain pill controls. Omit to hide the pill (e.g. HyperCore-only flows). */
+ sourceChain?: SourceChain
+ onSourceToggle?: () => void
payUsdValue: string | null
hasMaxBalance: boolean
onMax: () => void
+ /** Pay-side token ticker. Defaults to `'USDC'` for USDHSwap. */
+ payTicker?: 'USDC' | 'USDH'
}) {
const {
amountStr,
@@ -21,17 +24,20 @@ export function PayCard(props: {
payUsdValue,
hasMaxBalance,
onMax,
+ payTicker = 'USDC',
} = props
return (