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: '0x1234567890abcdef1234567890abcdef12345678',
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
| Parameter | Type | Required | Description |
|---|---|---|---|
to | `0x${string}` | Yes | Recipient address. |
value | string | Yes | Amount to send (human-readable, e.g., '1.5'). |
data | `0x${string}` | No | Calldata for contract interactions. |
assetType | 'native' | 'erc20' | 'erc721' | 'erc1155' | 'erc3643' | No | Token standard. Defaults to 'native'. |
tokenAddress | `0x${string}` | No | Contract address of the token (required for non-native). |
tokenId | string | No | Token ID for ERC-721 and ERC-1155 transfers. |
decimals | number | No | Token decimals (required for ERC-20 if not auto-detected). |
Return Value
| Property | Type | Description |
|---|---|---|
sendTransaction | (params: SendTransactionParams) => Promise<string | null> | Submit a UserOperation. Returns the UserOp hash on success. |
isLoading | boolean | true while the operation is being signed and submitted. |
error | string | null | Error message if the operation failed. |
userOpHash | string | null | The hash of the submitted UserOperation. |
reset | () => void | Clear the current error and userOpHash state. |
Asset Type Examples
Native Token Transfer
await sendTransaction({
to: '0xRecipientAddress...',
value: '1.0',
})ERC-20 Transfer
await sendTransaction({
to: '0xRecipientAddress...',
value: '100',
assetType: 'erc20',
tokenAddress: '0xTokenContractAddress...',
decimals: 18,
})ERC-721 (NFT) Transfer
await sendTransaction({
to: '0xRecipientAddress...',
value: '1',
assetType: 'erc721',
tokenAddress: '0xNFTContractAddress...',
tokenId: '42',
})ERC-1155 Transfer
await sendTransaction({
to: '0xRecipientAddress...',
value: '5',
assetType: 'erc1155',
tokenAddress: '0xMultiTokenAddress...',
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: '0x...', value: '0.01' })}
disabled={isLoading}
>
Send
</button>
{state !== 'waiting' && <p>Status: {state}</p>}
{txHash && <p>Transaction: {txHash}</p>}
</div>
)
}useUserOpStatus Options
| Option | Type | Default | Description |
|---|---|---|---|
userOpHash | string | null | — | The UserOperation hash to track. |
pollMs | number | 1000 | Polling interval in milliseconds. |
maxPollTimeMs | number | 60000 | Maximum time to poll before timeout. |
enabled | boolean | true | Set 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
| State | Description |
|---|---|
'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
Returns the recent transaction history for the connected account, including both UserOperations and direct transactions.
import { useTransactions } from '@embarkai/ui-kit'
function TransactionHistory() {
const transactions = useTransactions()
if (!transactions?.length) return <p>No transactions yet.</p>
return (
<ul>
{transactions.map((tx) => (
<li key={tx.hash}>
{tx.type} — {tx.status} — {tx.value} {tx.symbol}
</li>
))}
</ul>
)
}Transaction Object
| Property | Type | Description |
|---|---|---|
hash | string | Transaction or UserOp hash. |
type | 'send' | 'receive' | 'contract' | Transaction type. |
status | 'pending' | 'confirmed' | 'failed' | Current status. |
value | string | Transfer amount (human-readable). |
symbol | string | Token symbol. |
to | string | Recipient address. |
from | string | Sender address. |
timestamp | number | Unix timestamp. |
useSmartAccountTransactions
Similar to useTransactions, but scoped exclusively to the smart account. Excludes direct wallet transactions when in linked mode.
import { useSmartAccountTransactions } from '@embarkai/ui-kit'
function SmartAccountHistory() {
const transactions = useSmartAccountTransactions()
return (
<div>
<h3>Smart Account Activity</h3>
{transactions?.map((tx) => (
<div key={tx.hash}>
<span>{tx.type}</span>
<span>{tx.value} {tx.symbol}</span>
</div>
))}
</div>
)
}useErc3643Compliance
Check ERC-3643 compliance status for regulated (security) tokens. Returns whether the connected wallet is eligible to hold and transfer a given token.
import { useErc3643Compliance } from '@embarkai/ui-kit'
function ComplianceCheck({ tokenAddress }: { tokenAddress: `0x${string}` }) {
const { isCompliant, isLoading, error } = useErc3643Compliance(tokenAddress)
if (isLoading) return <p>Checking compliance...</p>
if (error) return <p className="error">{error}</p>
return (
<p>
{isCompliant
? 'Your wallet is eligible to hold this token.'
: 'Your wallet is not eligible for this regulated token.'}
</p>
)
}Return Value
| Property | Type | Description |
|---|---|---|
isCompliant | boolean | null | Whether the wallet passes compliance checks. null while loading. |
isLoading | boolean | true while the compliance check is in progress. |
error | string | null | Error message if the check failed. |
Error Handling
Always check for errors and provide a way to retry:
function SendWithRetry() {
const { sendTransaction, isLoading, error, reset } = useSendTransaction()
const handleSend = async () => {
reset()
const hash = await sendTransaction({
to: '0xRecipientAddress...',
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
UserOpStatuscomponent for a built-in status display - useSession — verify the user is connected before sending