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 '...
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 listflow.isWalletLoading— Loading wallet balancesflow.isQuoteLoading— Requesting quoteflow.isWithdrawing— Withdrawal actively processing (excludes completed/fatal/error)flow.isWithdrawProcessing— Specifically inwithdraw:processing
Challenge States
flow.requires2FA— TOTP 2FA code neededflow.requires2FAMultiStep— Multi-step 2FA needed (Binance Web)flow.requiresSMS— SMS code neededflow.requiresKYC— KYC verification neededflow.isReadyToConfirm— All 2FA steps verified, ready for final confirmation
Error Detection
flow.hasFatalError— Non-recoverable errorflow.canRetry— Withdrawal failed but retryableflow.hasInsufficientBalance— Balance too lowflow.hasAmountError— Quote/fatal error about amountflow.hasAddressError— Quote/fatal error about addressflow.hasNetworkError— Quote/fatal error about networkflow.hasWalletNotFoundError— Wallet not foundflow.hasInvalidCredentialsError— Invalid wallet credentials
Terminal States
flow.isWithdrawalComplete— Success. Accessflow.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
-
No context provider needed. Unlike most React state libraries, there is no
<BluvoProvider>. EachuseBluvoFlowcall creates its ownBluvoFlowClientinstance internally. -
useBluvoFlowcaptures options at mount only. The client is created in auseStateinitializer:useState(() => new BluvoFlowClient(options)). Changing options after mount has no effect. If you need to reinitialize, remount the component. -
All action methods are
useCallback-wrapped.startWithdrawalFlow,requestQuote,executeWithdrawal, etc. are stable references. Safe to pass as props without memoization. -
exchangesstate has dual source.flow.exchangeschecks both machine context (flow.context?.exchanges) and local React state. This is for backward compatibility — both sources should agree afterlistExchanges()completes. -
flow.isWithdrawingexcludes completed/fatal/error states. It means "actively processing right now" — specificallywithdraw:processing,withdraw:retrying,withdraw:readyToConfirm. It does NOT includewithdraw:error2FA,withdraw:completed, etc. -
mfaVerifiedfrom context is the PRIMARY truth for multi-step 2FA. Supported keys:GOOGLE,EMAIL,FACE,SMS,ROAMING_FIDO. When checking if a step is verified, preferflow.mfaVerified?.GOOGLE === trueoverstep.status === 'success'. Themfa.verifiedobject is the authoritative source from the backend. -
testWithdrawalComplete()is TEST-ONLY. It simulates withdrawal completion without a real transaction. Do not use in production. -
Re-renders on every machine state change. The hook subscribes to the machine and calls
setStateon every transition. For complex UIs, extract smaller components that receive only the data they need as props. -
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.mdfor the full signature of every exported hook including all ~80+ return fields fromuseBluvoFlow. - Read
references/nextjs-patterns.mdfor complete Next.js App Router integration patterns including server actions, environment variables, and thetoPlain()workaround. - Read
references/components.mdif you're looking for exported React components. - Read
../ts/skill/SKILL.mdif you need to understand the underlying state machine or need TypeScript-only (non-React) patterns. - Read
references/qrcode-binance-web.mdfor QR code authentication flow implementation — state machine states, QRCodeStatus lifecycle, caching, component rendering patterns, and refresh handling forbinance-webexchange. - Read
references/multistep-2fa.mdfor 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.
