@onflow/react-sdk
@onflow/react-sdk
is a lightweight React utility library that simplifies interacting with the Flow blockchain. It provides a collection of hooks and components designed to make authentication, script execution, transactions, event subscriptions, and network configuration seamless in React apps.
What's Included
Cadence Hooks
Hooks for interacting with native Flow Cadence runtime:
useFlowCurrentUser
– Authenticate and manage the current Flow useruseFlowAccount
– Fetch Flow account details by addressuseFlowBlock
– Query latest or specific Flow blocksuseFlowChainId
– Retrieve the current Flow chain IDuseFlowConfig
– Access the current Flow configurationuseFlowEvents
– Subscribe to Flow events in real-timeuseFlowQuery
– Execute Cadence scripts with optional argumentsuseFlowQueryRaw
– Execute Cadence scripts with optional arguments returning non-decoded datauseFlowMutate
– Send transactions to the Flow blockchainuseFlowRevertibleRandom
– Generate pseudorandom values tied to block heightuseFlowTransaction
– Fetch a Flow transaction by IDuseFlowTransactionStatus
– Track transaction status updatesuseDarkMode
– Get current dark mode state
Cross-VM (Flow EVM ↔ Cadence) Hooks
useCrossVmBatchTransaction
– Execute mutliple EVM transactions in a single atomic Cadence transactionuseCrossVmTokenBalance
– Query fungible token balances across Cadence and Flow EVMuseCrossVmSpendNft
– Bridge NFTs from Cadence to Flow EVM and execute arbitrary EVM transactions to atomically spend themuseCrossVmSpendToken
– Bridge fungible tokens from Cadence to Flow EVM and execute arbitrary EVM transactionsuseCrossVmTransactionStatus
– Track Cross-VM transaction status and EVM call results
Components
Reusable UI components:
<Connect />
- A wallet authentication button<TransactionButton />
- Context-aware button for executing Flow transactions<TransactionDialog />
- A dialog modal that tracks a Flow transaction's lifecycle<TransactionLink />
- A button that links to the block explorer based on network
Installation
_10npm install @onflow/react-sdk
Usage
Wrapping Your App With FlowProvider
Begin by wrapping your application with the FlowProvider
to initialize FCL configuration. This sets up FCL and maps its configuration keys to a strictly typed format for your hooks.
_25import React from "react"_25import App from "./App"_25import { FlowProvider } from "@onflow/react-sdk"_25import flowJSON from "../flow.json"_25_25function Root() {_25 return (_25 <FlowProvider_25 config={{_25 accessNodeUrl: "https://access-mainnet.onflow.org",_25 flowNetwork: "mainnet",_25 appDetailTitle: "My On Chain App",_25 appDetailIcon: "https://example.com/icon.png",_25 appDetailDescription: "A decentralized app on Flow",_25 appDetailUrl: "https://myonchainapp.com",_25 }}_25 flowJson={flowJSON}_25 darkMode={false}_25 >_25 <App />_25 </FlowProvider>_25 )_25}_25_25export default Root
If you're using Next.js, place the FlowProvider
inside your layout.tsx
. Since React hooks must run on the client, you may need to wrap the provider in a separate file that begins with 'use client'
to avoid issues with server-side rendering. Adjust this setup as needed for other frontend frameworks.
👉 Learn more about configuring flow.json
in the Configuration Guide.
🎨 Theming
How Theming Works
All UI components in @onflow/react-sdk
are styled using Tailwind CSS utility classes. The kit supports both light and dark themes out of the box, using Tailwind's dark:
variant for dark mode styling.
You can customize the look and feel of the kit by providing a custom theme to the FlowProvider
via the theme
prop. This allows you to override default colors and styles to better match your app's branding.
_17import { FlowProvider } from "@onflow/react-sdk"_17_17<FlowProvider_17 config={...}_17 theme={{_17 colors: {_17 primary: {_17 background: "bg-blue-600 dark:bg-blue-400",_17 text: "text-white dark:text-blue-900",_17 hover: "hover:bg-blue-700 dark:hover:bg-blue-300",_17 },_17 // ...other color overrides_17 }_17 }}_17>_17 <App />_17</FlowProvider>
🌙 Dark Mode
How Dark Mode Works
Dark mode is fully controlled by the parent app using the darkMode
prop on FlowProvider
. The kit does not manage dark mode state internally—this gives you full control and ensures the kit always matches your app's theme.
darkMode={false}
(default): Forces all kit components to use light mode styles.darkMode={true}
: Forces all kit components to use dark mode styles.- You can dynamically change the
darkMode
prop to switch themes at runtime.
Example:
_10function App() {_10 // Parent app manages dark mode state_10 const [isDark, setIsDark] = useState(false)_10_10 return (_10 <FlowProvider config={...} darkMode={isDark}>_10 <MyFlowComponents />_10 </FlowProvider>_10 )_10}
Accessing Dark Mode State in Components:
You can use the useDarkMode
hook to check the current mode inside your components:
_10import { useDarkMode } from "@onflow/react-sdk"_10_10function MyComponent() {_10 // useDarkMode only returns the current state, no setter_10 const { isDark } = useDarkMode()_10 return <div>{isDark ? "Dark mode" : "Light mode"}</div>_10}
Notes
- The kit does not automatically follow system preferences or save user choices. You are responsible for managing and passing the correct
darkMode
value. - All kit components will automatically apply the correct Tailwind
dark:
classes based on thedarkMode
prop. - For best results, ensure your app's global theme and the kit's
darkMode
prop are always in sync.
Components
Connect
A drop-in wallet connection component with UI for copy address, logout, and balance display.
Props:
variant?: ButtonProps["variant"]
– Optional button style variant (default:"primary"
)onConnect?: () => void
– Callback triggered after successful authenticationonDisconnect?: () => void
– Callback triggered after logoutbalanceType?: "cadence" | "evm" | "combined"
– Specifies which balance to display (default:"cadence"
). Options:"cadence"
: Shows the FLOW token balance from the Cadence side"evm"
: Shows the FLOW token balance from the Flow EVM side"combined"
: Shows the total combined FLOW token balance from both sides
_10import { Connect } from "@onflow/react-sdk"_10_10<Connect_10 onConnect={() => console.log("Connected!")}_10 onDisconnect={() => console.log("Logged out")}_10/>
Live Demo
TransactionButton
Button component for executing Flow transactions with built-in loading states and global transaction management.
Props:
transaction: Parameters<typeof mutate>[0]
– Flow transaction object to execute when clickedlabel?: string
– Optional custom button label (default:"Execute Transaction"
)mutation?: UseMutationOptions<string, Error, Parameters<typeof mutate>[0]>
– Optional TanStack React Query mutation options...buttonProps
– All otherButtonProps
exceptonClick
andchildren
(includesvariant
,disabled
,className
, etc.)
_23import { TransactionButton } from "@onflow/react-sdk"_23_23const myTransaction = {_23 cadence: `_23 transaction() {_23 prepare(acct: &Account) {_23 log("Hello from ", acct.address)_23 }_23 }_23 `,_23 args: (arg, t) => [],_23 limit: 100,_23}_23_23<TransactionButton_23 transaction={myTransaction}_23 label="Say Hello"_23 variant="primary"_23 mutation={{_23 onSuccess: (txId) => console.log("Transaction sent:", txId),_23 onError: (error) => console.error("Transaction failed:", error),_23 }}_23/>
Live Demo
TransactionDialog
Dialog component for real-time transaction status updates.
Props:
open: boolean
– Whether the dialog is openonOpenChange: (open: boolean) => void
– Callback to open/close dialogtxId?: string
– Optional Flow transaction ID to trackonSuccess?: () => void
– Optional callback when transaction is successfulpendingTitle?: string
– Optional custom pending state titlependingDescription?: string
– Optional custom pending state descriptionsuccessTitle?: string
– Optional custom success state titlesuccessDescription?: string
– Optional custom success state descriptioncloseOnSuccess?: boolean
– Iftrue
, closes the dialog automatically after success
_11import { TransactionDialog } from "@onflow/react-sdk"_11_11_11<TransactionDialog_11 open={isOpen}_11 onOpenChange={setIsOpen}_11 txId="6afa38b7bd1a23c6cc01a4ea2e51ed376f16761f9d06eca0577f674a9edc0716"_11 pendingTitle="Sending..."_11 successTitle="All done!"_11 closeOnSuccess_11/>
Live Demo
TransactionLink
Link to the block explorer with the appropriate network scoped to transaction ID.
Props:
txId: string
– The transaction ID to link tovariant?: ButtonProps["variant"]
– Optional button variant (defaults to"link"
)
_10import { TransactionLink } from "@onflow/react-sdk"_10_10<TransactionLink txId="your-tx-id" />
Live Demo
Hooks
Many of these hooks are built using @tanstack/react-query
, which provides powerful caching, revalidation, and background refetching features. As a result, you’ll see return types like UseQueryResult
and UseMutationResult
throughout this section. Other types—such as Account
, Block
, and CurrentUser
—are from the Flow Client Library (FCL) TypeDefs. Refer to their respective documentation for full type definitions and usage patterns.
useFlowCurrentUser
_10import { useFlowCurrentUser } from "@onflow/react-sdk"
Parameters
flowClient?: FlowClient
- OptionalFlowClient
instance
Returns:
user: CurrentUser
– The current user object from FCLauthenticate: () => Promise<CurrentUser>
– Triggers wallet authenticationunauthenticate: () => void
– Logs the user out
_16function AuthComponent() {_16 const { user, authenticate, unauthenticate } = useFlowCurrentUser()_16_16 return (_16 <div>_16 {user?.loggedIn ? (_16 <>_16 <p>Logged in as {user?.addr}</p>_16 <button onClick={unauthenticate}>Logout</button>_16 </>_16 ) : (_16 <button onClick={authenticate}>Login</button>_16 )}_16 </div>_16 )_16}
useFlowAccount
_10import { useFlowAccount } from "@onflow/react-sdk"
Parameters:
address?: string
– Flow address (with or without0x
prefix)query?: UseQueryOptions<Account | null, Error>
– Optional TanStackQuery optionsflowClient?: FlowClient
- OptionalFlowClient
instance
Returns: UseQueryResult<Account | null, Error>
_19function AccountDetails() {_19 const { data: account, isLoading, error, refetch } = useFlowAccount({_19 address: "0x1cf0e2f2f715450",_19 query: { staleTime: 5000 },_19 })_19_19 if (isLoading) return <p>Loading account...</p>_19 if (error) return <p>Error fetching account: {error.message}</p>_19 if (!account) return <p>No account data</p>_19_19 return (_19 <div>_19 <h2>Account: {account.address}</h2>_19 <p>Balance: {account.balance}</p>_19 <pre>{account.code}</pre>_19 <button onClick={refetch}>Refetch</button>_19 </div>_19 )_19}
useFlowBlock
_10import { useFlowBlock } from "@onflow/react-sdk"
Parameters:
sealed?: boolean
– Iftrue
, fetch latest sealed blockid?: string
– Block by IDheight?: number
– Block by heightquery?: UseQueryOptions<Block | null, Error>
– Optional TanStackQuery optionsflowClient?: FlowClient
- OptionalFlowClient
instance
Only one of sealed
, id
, or height
should be provided.
Returns: UseQueryResult<Block | null, Error>
_14function LatestBlock() {_14 const { data: block, isLoading, error } = useFlowBlock({ query: { staleTime: 10000 } })_14_14 if (isLoading) return <p>Loading...</p>_14 if (error) return <p>Error: {error.message}</p>_14 if (!block) return <p>No block data.</p>_14_14 return (_14 <div>_14 <h2>Block {block.height}</h2>_14 <p>ID: {block.id}</p>_14 </div>_14 )_14}
useFlowChainId
_10import { useFlowChainId } from "@onflow/react-sdk"
This hook retrieves the Flow chain ID, which is useful for identifying the current network.
Parameters:
query?: Omit<UseQueryOptions<string | null>, "queryKey" | "queryFn">
– Optional TanStack Query options likestaleTime
,enabled
, etc.flowClient?: FlowClient
- OptionalFlowClient
instance
Returns: UseQueryResult<string | null, Error>
Valid chain IDs include: testnet
(Flow Testnet), mainnet
(Flow Mainnet), and emulator
(Flow Emulator). The flow-
prefix will be stripped from the chain ID returned by the access node (e.g. flow-testnet
will return testnet
).
_10function ChainIdExample() {_10 const { data: chainId, isLoading, error } = useFlowChainId({_10 query: { staleTime: 10000 },_10 })_10_10 if (isLoading) return <p>Loading chain ID...</p>_10 if (error) return <p>Error fetching chain ID: {error.message}</p>_10_10 return <div>Current Flow Chain ID: {chainId}</div>_10}
useFlowClient
This hook returns the FlowClient
for the current <FlowProvider />
context.
Parameters:
flowClient?: FlowClient
- OptionalFlowClient
instance to override the result
useFlowConfig
_10import { useFlowConfig } from "@onflow/react-sdk"
Returns: FlowConfig
_10function MyComponent() {_10 const config = useFlowConfig()_10_10 return (_10 <div>_10 <p>Current network: {config.flowNetwork}</p>_10 <p>Current access node: {config.accessNodeUrl}</p>_10 </div>_10 )_10}
useFlowEvents
_10import { useFlowEvents } from "@onflow/react-sdk"
Parameters:
startBlockId?: string
– Optional ID of the block to start listening fromstartHeight?: number
– Optional block height to start listening fromeventTypes?: string[]
– Array of event type strings (e.g.,A.0xDeaDBeef.Contract.EventName
)addresses?: string[]
– Filter by Flow addressescontracts?: string[]
– Filter by contract identifiersopts?: { heartbeatInterval?: number }
– Options for subscription heartbeatonEvent: (event: Event) => void
– Callback for each event receivedonError?: (error: Error) => void
– Optional error handlerflowClient?: FlowClient
- OptionalFlowClient
instance
Example:
_10function EventListener() {_10 useFlowEvents({_10 eventTypes: ["A.0xDeaDBeef.SomeContract.SomeEvent"],_10 onEvent: (event) => console.log("New event:", event),_10 onError: (error) => console.error("Error:", error),_10 })_10_10 return <div>Listening for events...</div>_10}
useFlowQuery
_10import { useFlowQuery } from "@onflow/react-sdk"
Parameters:
cadence: string
– Cadence script to runargs?: (arg, t) => unknown[]
– Function returning FCL argumentsquery?: UseQueryOptions<unknown, Error>
– Optional TanStackQuery optionsflowClient?: FlowClient
- OptionalFlowClient
instance
Returns: UseQueryResult<unknown, Error>
_22function QueryExample() {_22 const { data, isLoading, error, refetch } = useFlowQuery({_22 cadence: `_22 access(all)_22 fun main(a: Int, b: Int): Int {_22 return a + b_22 }_22 `,_22 args: (arg, t) => [arg(1, t.Int), arg(2, t.Int)],_22 query: { staleTime: 10000 },_22 })_22_22 if (isLoading) return <p>Loading query...</p>_22 if (error) return <p>Error: {error.message}</p>_22_22 return (_22 <div>_22 <p>Result: {data}</p>_22 <button onClick={refetch}>Refetch</button>_22 </div>_22 )_22}
useFlowQueryRaw
_10import { useFlowQueryRaw } from "@onflow/react-sdk"
This hook is identical to useFlowQuery
but returns the raw, non-decoded response data from the Flow blockchain. This is useful when you need access to the original response structure or want to handle decoding manually.
Parameters:
cadence: string
– Cadence script to runargs?: (arg, t) => unknown[]
– Function returning FCL argumentsquery?: UseQueryOptions<unknown, Error>
– Optional TanStackQuery optionsflowClient?: FlowClient
- OptionalFlowClient
instance
Returns: UseQueryResult<unknown, Error>
The returned data will be in its raw, non-decoded format as received from the Flow access node.
_22function QueryRawExample() {_22 const { data: rawData, isLoading, error, refetch } = useFlowQueryRaw({_22 cadence: `_22 access(all)_22 fun main(a: Int, b: Int): Int {_22 return a + b_22 }_22 `,_22 args: (arg, t) => [arg(1, t.Int), arg(2, t.Int)],_22 query: { staleTime: 10000 },_22 })_22_22 if (isLoading) return <p>Loading query...</p>_22 if (error) return <p>Error: {error.message}</p>_22_22 return (_22 <div>_22 <p>Raw Result: {JSON.stringify(rawData, null, 2)}</p>_22 <button onClick={refetch}>Refetch</button>_22 </div>_22 )_22}
useFlowMutate
_10import { useFlowMutate } from "@onflow/react-sdk"
Parameters:
mutation?: UseMutationOptions<string, Error, FCLMutateParams>
– Optional TanStackQuery mutation optionsflowClient?: FlowClient
- OptionalFlowClient
instance
Returns: UseMutationResult<string, Error, FCLMutateParams>
_33function CreatePage() {_33 const { mutate, isPending, error, data: txId } = useFlowMutate({_33 mutation: {_33 onSuccess: (txId) => console.log("TX ID:", txId),_33 },_33 })_33_33 const sendTransaction = () => {_33 mutate({_33 cadence: `transaction() {_33 prepare(acct: &Account) {_33 log(acct.address)_33 }_33 }`,_33 args: (arg, t) => [],_33 proposer: fcl.currentUser,_33 payer: fcl.currentUser,_33 authorizations: [],_33 limit: 100,_33 })_33 }_33_33 return (_33 <div>_33 <button onClick={sendTransaction} disabled={isPending}>_33 Send Transaction_33 </button>_33 {isPending && <p>Sending transaction...</p>}_33 {error && <p>Error: {error.message}</p>}_33 {txId && <p>Transaction ID: {txId}</p>}_33 </div>_33 )_33}
useFlowRevertibleRandom
_10import { useFlowRevertibleRandom } from "@onflow/react-sdk"
Parameters:
min?: string
– Minimum random value (inclusive), as a UInt256 decimal string. Defaults to"0"
.max: string
– Maximum random value (inclusive), as a UInt256 decimal string. Required.count?: number
– Number of random values to fetch (must be at least 1). Defaults to1
.query?: Omit<UseQueryOptions<any, Error>, "queryKey" | "queryFn">
– Optional TanStack Query settings likestaleTime
,enabled
,retry
, etc.flowClient?: FlowClient
- OptionalFlowClient
instance
Returns: UseQueryResult<RevertibleRandomResult[], Error>
Each RevertibleRandomResult
includes:
blockHeight: string
— The block height from which the random value was generated.value: string
— The random UInt256 value, returned as a decimal string.
_26function RandomValues() {_26 const { data: randoms, isLoading, error, refetch } = useFlowRevertibleRandom({_26 min: "0",_26 max: "1000000000000000000000000", // Example large max_26 count: 3,_26 query: { staleTime: 10000 },_26 })_26_26 if (isLoading) return <p>Loading random numbers...</p>_26 if (error) return <p>Error fetching random numbers: {error.message}</p>_26 if (!randoms) return <p>No random values generated.</p>_26_26 return (_26 <div>_26 <h2>Generated Random Numbers</h2>_26 <ul>_26 {randoms.map((rand, idx) => (_26 <li key={idx}>_26 Block {rand.blockHeight}: {rand.value}_26 </li>_26 ))}_26 </ul>_26 <button onClick={refetch}>Regenerate</button>_26 </div>_26 )_26}
Notes:
- Randomness is generated using the on-chain
revertibleRandom
function on Flow, producing pseudorandom values tied to block and script execution. - Values are deterministic: The values returned for identical calls within the same block will be identical.
- If
count
is larger than one, the returned values are distinct. - This hook is designed for simple use cases that don't require unpredictability, such as randomized UIs. Since the hook uses script executions on existing blocks, the random source is already public and the randoms are predictable.
- For more advanced use cases that do require on-chain randomness logic via transactions, Flow provides built-in support using Cadence's
revertibleRandom
and commit-reveal scheme.
useFlowTransaction
_10import { useFlowTransaction } from "@onflow/react-sdk"
Fetches a Flow transaction by ID and returns the decoded transaction object.
Parameters:
txId?: string
– The Flow transaction ID to fetch.query?: Omit<UseQueryOptions<Transaction | null, Error>, "queryKey" | "queryFn">
– Optional TanStack Query options likestaleTime
,enabled
, etc.flowClient?: FlowClient
- OptionalFlowClient
instance
Returns: UseQueryResult<Transaction | null, Error>
_19function TransactionDetails({ txId }: { txId: string }) {_19 const { data: transaction, isLoading, error, refetch } = useFlowTransaction({_19 txId,_19 query: { staleTime: 10000 },_19 })_19_19 if (isLoading) return <p>Loading transaction...</p>_19 if (error) return <p>Error fetching transaction: {error.message}</p>_19 if (!transaction) return <p>No transaction data.</p>_19_19 return (_19 <div>_19 <h2>Transaction ID: {transaction.id}</h2>_19 <p>Gas Limit: {transaction.gasLimit}</p>_19 <pre>Arguments: {JSON.stringify(transaction.arguments, null, 2)}</pre>_19 <button onClick={refetch}>Refetch</button>_19 </div>_19 )_19}
useFlowTransactionStatus
_10import { useFlowTransactionStatus } from "@onflow/react-sdk"
Parameters:
id: string
– Transaction ID to subscribe toflowClient?: FlowClient
- OptionalFlowClient
instance
Returns:
transactionStatus: TransactionStatus | null
error: Error | null
_10function TransactionStatusComponent() {_10 const txId = "your-transaction-id-here"_10 const { transactionStatus, error } = useFlowTransactionStatus({ id: txId })_10_10 if (error) return <div>Error: {error.message}</div>;_10_10 return <div>Status: {transactionStatus?.statusString}</div>;_10}
useDarkMode
_10import { useDarkMode } from "@onflow/react-sdk"
This hook provides access to the current dark mode state from the FlowProvider
. It's useful for conditionally rendering content or applying custom styling based on the current theme.
Returns:
isDark: boolean
– Whether dark mode is currently enabled
_10function ThemeAwareComponent() {_10 const { isDark } = useDarkMode()_10_10 return (_10 <div className={isDark ? "bg-gray-900 text-white" : "bg-white text-black"}>_10 <h2>Current Theme: {isDark ? "Dark" : "Light"}</h2>_10 <p>This component adapts to the current theme!</p>_10 </div>_10 )_10}
Cross-VM Hooks
useCrossVmBatchTransaction
_10import { useCrossVmBatchTransaction } from "@onflow/react-sdk"
This hook allows you to execute multiple EVM transactions in a single atomic Cadence transaction. It is useful for batch processing EVM calls while ensuring they are executed together, either all succeeding or allowing for some to fail without affecting the others.
Parameters:
mutation?: UseMutationOptions<string, Error, UseCrossVmBatchTransactionMutateArgs>
– Optional TanStackQuery mutation optionsflowClient?: FlowClient
- OptionalFlowClient
instance
Returns: UseCrossVmBatchTransactionResult
Where UseCrossVmBatchTransactionResult
is defined as:
_10interface UseCrossVmBatchTransactionResult extends Omit<_10 UseMutationResult<string, Error, UseCrossVmBatchTransactionMutateArgs>,_10 "mutate" | "mutateAsync"_10> {_10 mutate: (calls: UseCrossVmBatchTransactionMutateArgs) => void_10 mutateAsync: (calls: UseCrossVmBatchTransactionMutateArgs) => Promise<string>_10}
Where UseCrossVmBatchTransactionMutateArgs
is defined as:
_10interface UseCrossVmBatchTransactionMutateArgs {_10 calls: EvmBatchCall[]_10 mustPass?: boolean_10}
Where EvmBatchCall
is defined as:
_14interface EvmBatchCall {_14 // The target EVM contract address (as a string)_14 address: string_14 // The contract ABI fragment_14 abi: Abi_14 // The name of the function to call_14 functionName: string_14 // The function arguments_14 args?: readonly unknown[]_14 // The gas limit for the call_14 gasLimit?: bigint_14 // The value to send with the call_14 value?: bigint_14}
_35function CrossVmBatchTransactionExample() {_35 const { sendBatchTransaction, isPending, error, data: txId } = useCrossVmBatchTransaction({_35 mutation: {_35 onSuccess: (txId) => console.log("TX ID:", txId),_35 },_35 })_35_35 const sendTransaction = () => {_35 const calls = [_35 {_35 address: "0x1234567890abcdef",_35 abi: {_35 // ABI definition for the contract_35 },_35 functionName: "transfer",_35 args: ["0xabcdef1234567890", 100n], // Example arguments_35 gasLimit: 21000n, // Example gas limit_35 },_35 // Add more calls as needed_35 ]_35_35 sendBatchTransaction({calls})_35 }_35_35 return (_35 <div>_35 <button onClick={sendTransaction} disabled={isPending}>_35 Send Cross-VM Transaction_35 </button>_35 {isPending && <p>Sending transaction...</p>}_35 {error && <p>Error: {error.message}</p>}_35 {txId && <p>Transaction ID: {txId}</p>}_35 </div>_35 )_35}
useCrossVmTokenBalance
_10import { useCrossVmTokenBalance } from "@onflow/react-sdk"
Fetch the balance of a token balance for a given user across both Cadence and EVM environments.
Parameters:
owner: string
– Cadence address of the account whose token balances you want.vaultIdentifier?: string
– Optional Cadence resource identifier (e.g. "0x1cf0e2f2f715450.FlowToken.Vault") for on-chain balanceerc20AddressHexArg?: string
– Optional bridged ERC-20 contract address (hex) for EVM/COA balancequery?: Omit<UseQueryOptions<unknown, Error>, "queryKey" | "queryFn">
– Optional TanStack Query config (e.g. staleTime, enabled)flowClient?: FlowClient
- OptionalFlowClient
instance
Note: You must pass
owner
, and one ofvaultIdentifier
orerc20AddressHexArg
.
Returns: UseQueryResult<UseCrossVmTokenBalanceData | null, Error>
Where UseCrossVmTokenBalanceData
is defined as:
_10interface UseCrossVmTokenBalanceData {_10 cadence: TokenBalance // Token balance of Cadence vault_10 evm: TokenBalance // Token balance of EVM (COA stored in /storage/coa)_10 combined: TokenBalance // Combined balance of both Cadence and EVM_10}
Where TokenBalance
is defined as:
_10interface TokenBalance {_10 value: bigint // Balance value in smallest unit_10 formatted: string // Formatted balance string (e.g. "123.45")_10 precision: number // Number of decimal places for the token_10}
_20function UseCrossVmTokenBalanceExample() {_20 const { data, isLoading, error, refetch } = useCrossVmTokenBalance({_20 owner: '0x1e4aa0b87d10b141',_20 vaultIdentifier: 'A.1654653399040a61.FlowToken.Vault',_20 query: { staleTime: 10000 },_20 });_20_20 if (isLoading) return <p>Loading token balance...</p>;_20 if (error) return <p>Error fetching token balance: {error.message}</p>;_20_20 return (_20 <div>_20 <h2>Token Balances</h2>_20 <p>Cadence Balance: {data.cadence.formatted} (Value: {data.cadence.value})</p>_20 <p>EVM Balance: {data.evm.formatted} (Value: {data.evm.value})</p>_20 <p>Combined Balance: {data.combined.formatted} (Value: {data.combined.value})</p>_20 <button onClick={refetch}>Refetch</button>_20 </div>_20 )_20}
useCrossVmSpendNft
_10import { useCrossVmSpendNft } from "@onflow/react-sdk"
Bridge NFTs from Cadence to Flow EVM and execute arbitrary EVM transactions to atomically spend them.
Parameters:
mutation?: UseMutationOptions<string, Error, UseCrossVmSpendFtMutateArgs>
– Optional TanStackQuery mutation optionsflowClient?: FlowClient
- OptionalFlowClient
instance
Where UseCrossVmSpendFtMutateArgs
is defined as:
_10interface UseCrossVmSpendFtMutateArgs {_10 nftIdentifier: string // Cadence NFT identifier (e.g. "0x1cf0e2f2f715450.FlowNFT")_10 nftIds: string[] // Array of NFT IDs to bridge_10 calls: EVMBatchCall[] // Array of EVM calls to execute atomically_10}
Returns: UseCrossVmSpendNftResult
Where UseCrossVmSpendNftResult
is defined as:
_10interface UseCrossVmSpendNftResult extends Omit<_10 UseMutationResult<string, Error, CrossVmSpendNftParams>,_10 "mutate" | "mutateAsync"_10> {_10 spendNft: (params: CrossVmSpendNftParams) => Promise<string>_10 spendNftAsync: (params: CrossVmSpendNftParams) => Promise<string>_10}
_31function CrossVmSpendNftExample() {_31 const { spendNft, isPending, error, data: txId } = useCrossVmSpendNft()_31_31 const handleSpendNft = () => {_31 spendNft({_31 nftIdentifier: "0x1cf0e2f2f715450.FlowNFT", // Cadence NFT identifier_31 nftIds: ["1"], // Array of NFT IDs to bridge_31 calls: [_31 {_31 abi: contractAbi, // ABI of the EVM contract_31 contractAddress: "0x1234567890abcdef1234567890abcdef12345678", // EVM contract address_31 functionName: "transferNFT",_31 args: ["123"], // Example args_31 value: "1000000000000000000", // Amount in wei (if applicable)_31 gasLimit: "21000", // Gas limit for the EVM call_31 },_31 ],_31 })_31 }_31_31 return (_31 <div>_31 <button onClick={handleSpendNft} disabled={isPending}>_31 Bridge and Spend NFT_31 </button>_31 {isPending && <p>Sending transaction...</p>}_31 {error && <p>Error: {error.message}</p>}_31 {txId && <p>Transaction ID: {txId}</p>}_31 </div>_31 )_31}
useCrossVmSpendToken
_10import { useCrossVmSpendToken } from "@onflow/react-sdk"
Bridge FTs from Cadence to Flow EVM and execute arbitrary EVM transactions to atomically spend them.
Parameters:
mutation?: UseMutationOptions<string, Error, UseCrossVmSpendTokenMutateArgs>
– Optional TanStackQuery mutation optionsflowClient?: FlowClient
- OptionalFlowClient
instance
Where UseCrossVmSpendTokenMutateArgs
is defined as:
_10interface UseCrossVmSpendTokenMutateArgs {_10 vaultIdentifier: string; // Cadence vault identifier (e.g. "0x1cf0e2f2f715450.ExampleToken.Vault")_10 amount: string; // Amount of tokens to bridge, as a decimal string (e.g. "1.23")_10 calls: EVMBatchCall[]; // Array of EVM calls to execute after bridging_10}
Returns: UseCrossVmSpendTokenResult
Where UseCrossVmSpendTokenResult
is defined as:
_10interface UseCrossVmSpendTokenResult extends Omit<_10 UseMutationResult<string, Error, UseCrossVmSpendTokenMutateArgs>,_10 "mutate" | "mutateAsync"_10> {_10 spendToken: (args: UseCrossVmSpendTokenMutateArgs) => void; // Function to trigger the FT bridging and EVM calls_10 spendTokenAsync: (args: UseCrossVmSpendTokenMutateArgs) => Promise<string>; // Async version of spendToken_10}
_31function CrossVmSpendTokenExample() {_31 const { spendToken, isPending, error, data: txId } = useCrossVmSpendToken()_31_31 const handleSpendToken = () => {_31 spendToken({_31 vaultIdentifier: "0x1cf0e2f2f715450.ExampleToken.Vault", // Cadence vault identifier_31 amount: "1.23", // Amount of tokens to bridge to EVM_31 calls: [_31 {_31 abi: myEvmContractAbi, // EVM contract ABI_31 address: "0x01234567890abcdef01234567890abcdef", // EVM contract address_31 function: "transfer", // EVM function to call_31 args: [_31 "0xabcdef01234567890abcdef01234567890abcdef", // Recipient address_31 ],_31 },_31 ],_31 })_31 }_31_31 return (_31 <div>_31 <button onClick={handleSpendToken} disabled={isPending}>_31 Bridge and Spend FTs_31 </button>_31 {isPending && <p>Sending transaction...</p>}_31 {error && <p>Error: {error.message}</p>}_31 {txId && <p>Cadence Transaction ID: {txId}</p>}_31 </div>_31 )_31}
useCrossVmTransactionStatus
_10import { useCrossVmTransactionStatus } from "@onflow/react-sdk"
Subscribes to status updates for a given Cross-VM Flow transaction ID that executes EVM calls. This hook monitors the transaction status and extracts EVM call results if available.
Parameters:
id?: string
– Optional Flow transaction ID to monitorflowClient?: FlowClient
- OptionalFlowClient
instance
Returns: UseCrossVmTransactionStatusResult
Where UseCrossVmTransactionStatusResult
is defined as:
_10interface UseCrossVmTransactionStatusResult {_10 transactionStatus: TransactionStatus | null // Latest transaction status, or null before any update_10 evmResults?: CallOutcome[] // EVM transaction results, if available_10 error: Error | null // Any error encountered during status updates_10}
Where CallOutcome
is defined as:
_10interface CallOutcome {_10 status: "passed" | "failed" | "skipped" // Status of the EVM call_10 hash?: string // EVM transaction hash if available_10 errorMessage?: string // Error message if the call failed_10}
_26function CrossVmTransactionStatusComponent() {_26 const txId = "your-cross-vm-transaction-id-here"_26 const { transactionStatus, evmResults, error } = useCrossVmTransactionStatus({ id: txId })_26_26 if (error) return <div>Error: {error.message}</div>_26_26 return (_26 <div>_26 <div>Flow Status: {transactionStatus?.statusString}</div>_26 {evmResults && evmResults.length > 0 && (_26 <div>_26 <h3>EVM Call Results:</h3>_26 <ul>_26 {evmResults.map((result, idx) => (_26 <li key={idx}>_26 Status: {result.status}_26 {result.hash && <span> | Hash: {result.hash}</span>}_26 {result.errorMessage && <span> | Error: {result.errorMessage}</span>}_26 </li>_26 ))}_26 </ul>_26 </div>_26 )}_26 </div>_26 )_26}