Skip to content
Back to skills

Skill

ASecurity

Use when building cryptocurrency exchange withdrawal UIs in React or Next.js. Provides hooks (useBluvoFlow, useFlowMachine, useWithdrawMachine, useWalletPreviews) that wrap the @bluvo/sdk-ts state machine. No context providers needed — just call the hook. Works with Next.js App Router (requires 'use client'). Choose this over the TS skill when building React applications.

  • 7 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 26, 2026
developmenttypescriptgobashreactnextjsapibackend

Works with

  • terminal
  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 6 files and shows the line behind each finding

Scanned May 27, 2026

npx -y skills add bluvoinc/sdk --skill skill --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Skill?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Skill
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/bluvoinc-skill/badge)](https://www.skillsdirectory.com/skills/bluvoinc-skill)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: bluvo-react
description: "Use when building cryptocurrency exchange withdrawal UIs in React or Next.js. Provides hooks (useBluvoFlow, useFlowMachine, useWithdrawMachine, useWalletPreviews) that wrap the @bluvo/sdk-ts state machine. No context providers needed — just call the hook. Works with Next.js App Router (requires 'use client'). Choose this over the TS skill when building React applications."
license: MIT
compatibility: "React 16.8+. Next.js 13+ App Router supported. Requires @bluvo/sdk-ts@3.0.0 peer dependency."
metadata:
  version: "3.1.0"
---

# @bluvo/react

## What This Package Does

Wraps `BluvoFlowClient` and `BluvoPreviewManager` from `@bluvo/sdk-ts` in React hooks. No providers or context needed — hooks manage their own state via direct machine subscription. Each hook creates its client instance in a `useState` initializer and subscribes to state changes internally.

## Setup

```bash
pnpm add @bluvo/react @bluvo/sdk-ts
```

No `<Provider>` component is needed. Just import and call the hook:

```typescript
"use client";  // Required in Next.js App Router

import { useBluvoFlow } from "@bluvo/react";
```

## Core Hooks

### useBluvoFlow(options)

The main hook for the complete withdrawal flow. Creates a `BluvoFlowClient` internally and exposes ~80+ return fields covering state, actions, and computed helpers.

```typescript
const flow = useBluvoFlow({
  orgId: process.env.NEXT_PUBLIC_BLUVO_ORG_ID!,
  projectId: process.env.NEXT_PUBLIC_BLUVO_PROJECT_ID!,
  listExchangesFn: serverListExchanges,
  fetchWithdrawableBalanceFn: serverFetchBalances,
  requestQuotationFn: serverRequestQuote,
  executeWithdrawalFn: serverExecuteWithdrawal,
  getWalletByIdFn: serverGetWallet,
  pingWalletByIdFn: serverPingWallet,
  options: { sandbox: false, autoRefreshQuotation: true },
});
```

**When to use**: Building a complete withdrawal UI. This is the primary hook for most use cases.

### useFlowMachine(machine)

Lower-level hook that subscribes to a `Machine<FlowState, FlowActionType>` and re-renders on state changes.

```typescript
const { state, send, isInState, hasError, error, context } = useFlowMachine(machine);
```

**When to use**: When you have a machine instance from `BluvoFlowClient` and want to manage it directly without `useBluvoFlow`'s action wrappers.

### useWithdrawMachine(machine)

Direct subscription to the nested withdrawal machine.

```typescript
const { state, send, requires2FA, requiresSMS, isCompleted, canRetry } = useWithdrawMachine(machine);
```

**When to use**: When you need fine-grained control over the withdrawal subprocess.

### useWalletPreviews(options)

Manages preview states for multiple wallets (dashboard view).

```typescript
const { previews, isLoading, loadPreviews, allReady } = useWalletPreviews({
  wallets: [{ id: 'wallet-1', exchange: 'coinbase' }],
  pingWalletByIdFn: serverPingWallet,
  fetchWithdrawableBalanceFn: serverFetchBalances,
  autoLoad: true,
});
```

**When to use**: Displaying a dashboard of connected wallets with balance previews before entering the withdrawal flow.

## Driving the Flow

Typical usage pattern:

```typescript
// 1. Load exchanges
useEffect(() => { flow.listExchanges('live'); }, []);

// 2. User selects exchange → start flow
await flow.startWithdrawalFlow({ exchange: 'coinbase', walletId: generateId() });

// 3. OAuth/QR code completes → wallet loads automatically

// 4. User fills form → request quote
await flow.requestQuote({
  asset: 'BTC', amount: '0.001',
  destinationAddress: 'bc1q...', network: 'bitcoin',
});

// 5. User confirms → execute withdrawal
await flow.executeWithdrawal(flow.quote!.id);

// 6. Handle challenges
if (flow.requires2FA) await flow.submit2FA(userCode);
if (flow.requires2FAMultiStep) {
  await flow.submit2FAMultiStep('GOOGLE', userCode);  // code-based steps
  // FACE and ROAMING_FIDO steps are polled automatically by the component
}
if (flow.isReadyToConfirm) await flow.confirmWithdrawal();

// 7. Done
if (flow.isWithdrawalComplete) showSuccess(flow.withdrawal);
```

## Loading and Error States

### Loading States
- `flow.isExchangesLoading` — Loading exchange list
- `flow.isWalletLoading` — Loading wallet balances
- `flow.isQuoteLoading` — Requesting quote
- `flow.isWithdrawing` — Withdrawal actively processing (excludes completed/fatal/error)
- `flow.isWithdrawProcessing` — Specifically in `withdraw:processing`

### Challenge States
- `flow.requires2FA` — TOTP 2FA code needed
- `flow.requires2FAMultiStep` — Multi-step 2FA needed (Binance Web)
- `flow.requiresSMS` — SMS code needed
- `flow.requiresKYC` — KYC verification needed
- `flow.isReadyToConfirm` — All 2FA steps verified, ready for final confirmation

### Error Detection
- `flow.hasFatalError` — Non-recoverable error
- `flow.canRetry` — Withdrawal failed but retryable
- `flow.hasInsufficientBalance` — Balance too low
- `flow.hasAmountError` — Quote/fatal error about amount
- `flow.hasAddressError` — Quote/fatal error about address
- `flow.hasNetworkError` — Quote/fatal error about network
- `flow.hasWalletNotFoundError` — Wallet not found
- `flow.hasInvalidCredentialsError` — Invalid wallet credentials

### Terminal States
- `flow.isWithdrawalComplete` — Success. Access `flow.withdrawal.transactionId`.
- `flow.isFlowCancelled` — User cancelled.
- `flow.isWithdrawBlocked` — Withdrawal blocked by exchange.

## Next.js Specifics

### `'use client'` required
Both `useBluvoFlow` and `useWalletPreviews` have `"use client"` directives. Any component using these hooks must also be a client component.

### Server Actions Pattern
Create a `'use server'` file with functions that instantiate `BluvoClient` and wrap returns with `toPlain()`:

```typescript
// actions/flowActions.ts
'use server'
import { createClient } from '@bluvo/sdk-ts';

function toPlain<T extends object>(o: T): T {
  return JSON.parse(JSON.stringify(o)) as T;
}

export async function fetchBalances(walletId: string) {
  return toPlain(await createClient({...}).wallet.withdrawals.getWithdrawableBalance(walletId));
}
```

### Environment Variables
- **Server-only**: `BLUVO_ORG_ID`, `BLUVO_PROJECT_ID`, `BLUVO_API_KEY`
- **Client-visible**: `NEXT_PUBLIC_BLUVO_ORG_ID`, `NEXT_PUBLIC_BLUVO_PROJECT_ID`, `NEXT_PUBLIC_BLUVO_ENV`

### No SSR Support
Hooks are browser-only. They use `useState`, `useEffect`, WebSocket subscriptions, and `localStorage`. They will not produce meaningful output during server-side rendering.

## Gotchas

1. **No context provider needed.** Unlike most React state libraries, there is no `<BluvoProvider>`. Each `useBluvoFlow` call creates its own `BluvoFlowClient` instance internally.

2. **`useBluvoFlow` captures options at mount only.** The client is created in a `useState` initializer: `useState(() => new BluvoFlowClient(options))`. Changing options after mount has no effect. If you need to reinitialize, remount the component.

3. **All action methods are `useCallback`-wrapped.** `startWithdrawalFlow`, `requestQuote`, `executeWithdrawal`, etc. are stable references. Safe to pass as props without memoization.

4. **`exchanges` state has dual source.** `flow.exchanges` checks both machine context (`flow.context?.exchanges`) and local React state. This is for backward compatibility — both sources should agree after `listExchanges()` completes.

5. **`flow.isWithdrawing` excludes completed/fatal/error states.** It means "actively processing right now" — specifically `withdraw:processing`, `withdraw:retrying`, `withdraw:readyToConfirm`. It does NOT include `withdraw:error2FA`, `withdraw:completed`, etc.

6. **`mfaVerified` from context is the PRIMARY truth for multi-step 2FA.** Supported keys: `GOOGLE`, `EMAIL`, `FACE`, `SMS`, `ROAMING_FIDO`. When checking if a step is verified, prefer `flow.mfaVerified?.GOOGLE === true` over `step.status === 'success'`. The `mfa.verified` object is the authoritative source from the backend.

7. **`testWithdrawalComplete()` is TEST-ONLY.** It simulates withdrawal completion without a real transaction. Do not use in production.

8. **Re-renders on every machine state change.** The hook subscribes to the machine and calls `setState` on every transition. For complex UIs, extract smaller components that receive only the data they need as props.

9. **`cancel()` also closes the OAuth popup window.** The hook maintains a ref to the OAuth window cleanup function and calls it on cancel.

## References

- Read `references/hooks-complete.md` for the full signature of every exported hook including all ~80+ return fields from `useBluvoFlow`.
- Read `references/nextjs-patterns.md` for complete Next.js App Router integration patterns including server actions, environment variables, and the `toPlain()` workaround.
- Read `references/components.md` if you're looking for exported React components.
- Read `../ts/skill/SKILL.md` if you need to understand the underlying state machine or need TypeScript-only (non-React) patterns.
- Read `references/qrcode-binance-web.md` for QR code authentication flow implementation — state machine states, QRCodeStatus lifecycle, caching, component rendering patterns, and refresh handling for `binance-web` exchange.
- Read `references/multistep-2fa.md` for multi-step 2FA implementation — handling GOOGLE, EMAIL, FACE, SMS, ROAMING_FIDO verification steps, mfa.verified as primary truth, FACE polling, ROAMING_FIDO polling, dryRun pattern, and confirmation flow.

Files in this skill

  • SKILL.md9.3 KB
  • references/components.md664 B
  • references/hooks-complete.md11.5 KB
  • references/multistep-2fa.md19.9 KB
  • references/nextjs-patterns.md5 KB
  • references/qrcode-binance-web.md13.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.