Skip to content
bluvo-react logo

bluvo-react

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 '...

bluvoinc/sdk0installs6stars

SKILL.md

Full skill instructions

@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

pnpm add @bluvo/​react @bluvo/​sdk-ts

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

"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.

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.

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.

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).

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:

// 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():

// 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.