Skip to Content

Transactions

Hooks for sending UserOperations, tracking transaction status, and viewing transaction history.

The useSendTransaction hook builds and submits a UserOperation through the account abstraction bundler. Combine it with useUserOpStatus to track confirmation state.

Import

import { useSendTransaction, useUserOpStatus } from '@embarkai/ui-kit'

Basic Usage

import { useSendTransaction } from '@embarkai/ui-kit' function SendForm() { const { sendTransaction, isLoading, error, userOpHash } = useSendTransaction() const handleSend = async () => { await sendTransaction({ to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', value: '0.1', }) } return ( <div> <button onClick={handleSend} disabled={isLoading}> {isLoading ? 'Sending...' : 'Send 0.1 LUMIA'} </button> {error && <p className="error">{error}</p>} {userOpHash && <p>UserOp: {userOpHash}</p>} </div> ) }

SendTransactionParams

ParameterTypeRequiredDescription
to`0x${string}`YesRecipient address.
valuestringYesAmount to send (human-readable, e.g., '1.5').
data`0x${string}`NoCalldata for contract interactions.
assetType'native' | 'erc20' | 'erc721' | 'erc1155' | 'erc3643'NoToken standard. Defaults to 'native'.
tokenAddress`0x${string}`NoContract address of the token (required for non-native).
tokenIdstringNoToken ID for ERC-721 and ERC-1155 transfers.
decimalsnumberNoToken decimals (required for ERC-20 if not auto-detected).

Return Value

PropertyTypeDescription
sendTransaction(params: SendTransactionParams) => Promise<string | null>Submit a UserOperation. Returns the UserOp hash on success.
isLoadingbooleantrue while the operation is being signed and submitted.
errorstring | nullError message if the operation failed.
userOpHashstring | nullThe hash of the submitted UserOperation.
reset() => voidClear the current error and userOpHash state.

Asset Type Examples

Native Token Transfer

await sendTransaction({ to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', value: '1.0', })

ERC-20 Transfer

await sendTransaction({ to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', value: '100', assetType: 'erc20', tokenAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', decimals: 18, })

ERC-721 (NFT) Transfer

await sendTransaction({ to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', value: '1', assetType: 'erc721', tokenAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', tokenId: '42', })

ERC-1155 Transfer

await sendTransaction({ to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', value: '5', assetType: 'erc1155', tokenAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', tokenId: '7', })

Tracking with useUserOpStatus

After submitting a transaction, use useUserOpStatus to poll for confirmation:

import { useSendTransaction, useUserOpStatus } from '@embarkai/ui-kit' function TrackedSend() { const { sendTransaction, userOpHash, isLoading } = useSendTransaction() const { state, txHash, receipt } = useUserOpStatus({ userOpHash, pollMs: 1000, maxPollTimeMs: 60000, onStateChange: (state) => console.log('State:', state), onTxHash: (hash) => console.log('Tx hash:', hash), onReceipt: (receipt) => console.log('Confirmed:', receipt), }) return ( <div> <button onClick={() => sendTransaction({ to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', value: '0.01' })} disabled={isLoading} > Send </button> {state !== 'waiting' && <p>Status: {state}</p>} {txHash && <p>Transaction: {txHash}</p>} </div> ) }

useUserOpStatus Options

OptionTypeDefaultDescription
userOpHashstring | null—The UserOperation hash to track.
pollMsnumber1000Polling interval in milliseconds.
maxPollTimeMsnumber60000Maximum time to poll before timeout.
enabledbooleantrueSet to false to pause polling.
onStateChange(state: UserOpState) => void—Callback fired on every state transition.
onReceipt(receipt) => void—Callback fired when the operation is included on-chain.
onTxHash(txHash: string) => void—Callback fired when the transaction hash is available.

UserOpState Values

StateDescription
'waiting'No userOpHash provided or polling not started.
'pending'UserOp is in the mempool, waiting for inclusion.
'included'Transaction has been included in a block.
'failed'Transaction reverted on-chain.
'rejected'UserOp was rejected by the bundler.
'timeout'Polling exceeded maxPollTimeMs.

useTransactions

Low-level helpers for reading transactions of the connected account via viem. The hook returns functions, not a list:

import { useEffect, useState } from 'react' import { useTransactions } from '@embarkai/ui-kit' import type { Transaction } from '@embarkai/ui-kit' function TransactionHistory() { const { getTransactionHistory, address, isConnected } = useTransactions() const [history, setHistory] = useState<Transaction[]>([]) useEffect(() => { if (!isConnected) return getTransactionHistory(address, 20).then(setHistory) }, [address, isConnected, getTransactionHistory]) if (!history.length) return <p>No transactions yet.</p> return ( <ul> {history.map((tx, i) => ( <li key={i}> → {tx.to}: {tx.value} wei </li> ))} </ul> ) }

Return Value

PropertyTypeDescription
sendTransaction(params)(params: { to, value, data?, gasLimit? }) => Promise<{ hash, wait() }>Send a raw transaction and get a wait() helper for the receipt.
getTransaction(hash)(hash) => Promise<viem Transaction>Fetch a transaction by hash.
getTransactionReceipt(hash)(hash) => Promise<TransactionReceipt>Fetch a receipt by hash.
getTransactionHistory(address, limit?)(address, limit?) => Promise<Transaction[]>Recent transactions; Transaction is { to, value, data?, gasLimit? }.
address / isConnected`0x${string}` / booleanConnected account.

useSmartAccountTransactions

Reads UserOperations of a smart account from the EntryPoint logs:

import { useEffect, useState } from 'react' import { useAddress, useSmartAccountTransactions } from '@embarkai/ui-kit' import type { UserOperation } from '@embarkai/ui-kit' function SmartAccountHistory() { const address = useAddress() const { getRecentUserOperations } = useSmartAccountTransactions() const [ops, setOps] = useState<UserOperation[]>([]) useEffect(() => { getRecentUserOperations(address, 10).then(setOps) }, [address, getRecentUserOperations]) return ( <div> <h3>Smart Account Activity</h3> {ops.map((op) => ( <div key={op.hash}> <span>{op.success ? 'ok' : 'failed'}</span> <span>{op.transactionHash}</span> <span>{new Date(op.timestamp * 1000).toLocaleString()}</span> </div> ))} </div> ) }

Return Value

PropertyTypeDescription
getUserOperations(address, fromBlock?, toBlock?)=> Promise<UserOperation[]>UserOperations in a block range.
getRecentUserOperations(address, limit?)=> Promise<UserOperation[]>Most recent UserOperations.
getTransactionDetails(txHash)=> Promise<{ transaction, receipt }>The bundle transaction and its receipt.

UserOperation fields: hash, sender, nonce, success, actualGasCost, blockNumber, timestamp, transactionHash.

useErc3643Compliance

Check whether a specific ERC-3643 (regulated security token) transfer is allowed before sending it:

import { useErc3643Compliance } from '@embarkai/ui-kit' function ComplianceCheck({ tokenAddress, to }: { tokenAddress: `0x${string}`; to: `0x${string}` }) { const { canTransfer, isLoading, error, refetch } = useErc3643Compliance({ tokenAddress, to, amount: 1_000_000_000_000_000_000n, // 1 token with 18 decimals }) if (isLoading) return <p>Checking compliance...</p> if (error) return <p className="error">{error} <button onClick={refetch}>Retry</button></p> return ( <p> {canTransfer ? 'This transfer passes the token compliance rules.' : 'This transfer is not allowed for the recipient.'} </p> ) }

Options

OptionTypeRequiredDescription
tokenAddress`0x${string}` | undefinedYesERC-3643 token contract.
to`0x${string}` | undefinedYesRecipient to check.
amountbigint | undefinedYesAmount in token units.
enabledbooleanNoPause the check (defaults to on when all inputs are set).
chainIdnumberNoChain to query; defaults to the active chain.

Return Value

PropertyTypeDescription
canTransferboolean | undefinedWhether the transfer passes compliance. undefined until checked.
isLoadingbooleantrue while the compliance check is in progress.
errorstring | nullError message if the check failed.
refetch() => voidRe-run the check.

Error Handling

Always check for errors and provide a way to retry:

import { useSendTransaction } from '@embarkai/ui-kit' function SendWithRetry() { const { sendTransaction, isLoading, error, reset } = useSendTransaction() const handleSend = async () => { reset() const hash = await sendTransaction({ to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', value: '0.1', }) if (!hash) { console.error('Transaction was not submitted') } } return ( <div> <button onClick={handleSend} disabled={isLoading}>Send</button> {error && ( <div className="error"> <p>{error}</p> <button onClick={reset}>Dismiss</button> </div> )} </div> ) }

Next Steps

  • useBalance — check balances before sending
  • Components — use the UserOpStatus component for a built-in status display
  • useSession — verify the user is connected before sending
Last updated on