Comprehensive guide to using React hooks from the Abstraxn Wallet SDK
This document provides comprehensive usage examples for all hooks available in the Abstraxn Wallet SDK React library.
Table of Contents
- Connection & Status Hooks
- Authentication Hooks
- Transaction Hooks
- Contract Interaction Hooks
- MFA Hooks
- Typed Signing
- External Wallet Client Hook
- Solana Hooks
- Complete Transaction Flow Example
- Notes
Connection & Status Hooks
useIsConnected()
Check if the wallet is currently connected.
import { useIsConnected } from '@abstraxn/signer-react';
function MyComponent() {
const isConnected = useIsConnected();
return (
<div>
{isConnected ? 'Wallet Connected' : 'Wallet Not Connected'}
</div>
);
}
Returns: boolean - true if wallet is connected, false otherwise.
useAddress()
Get the current wallet address.
import { useAddress } from '@abstraxn/signer-react';
function MyComponent() {
const address = useAddress();
return (
<div>
{address ? `Address: ${address}` : 'No address available'}
</div>
);
}
Returns: string | null - The wallet address or null if not connected.
useChainId()
Get the current chain ID.
import { useChainId } from '@abstraxn/signer-react';
function MyComponent() {
const chainId = useChainId();
return (
<div>
{chainId ? `Chain ID: ${chainId}` : 'No chain ID available'}
</div>
);
}
Returns: number | null - The chain ID or null if not connected.
useError()
Get the current error state.
import { useError } from '@abstraxn/signer-react';
function MyComponent() {
const error = useError();
if (error) {
return <div>Error: {error.message}</div>;
}
return <div>No errors</div>;
}
Returns: Error | null - The current error or null if no error.
useWallet()
Get the wallet instance for advanced usage.
import { useWallet } from '@abstraxn/signer-react';
function MyComponent() {
const wallet = useWallet();
// Use wallet for advanced operations
// Note: Most operations should use dedicated hooks instead
}
Returns: Wallet instance or null if not connected.
useConnectionType()
Get the connection type (how the user connected).
import { useConnectionType } from '@abstraxn/signer-react';
function MyComponent() {
const { connectionType, connectorMeta } = useConnectionType();
if (!connectionType) {
return <div>Not connected</div>;
}
return (
<div>
<p>Connected via: {connectorMeta?.name || connectionType}</p>
{connectionType === 'google' && <div>Welcome Google user!</div>}
{connectionType === 'metamask' && <div>MetaMask wallet connected</div>}
{connectionType === 'email' && <div>Email OTP user</div>}
{connectionType === 'passkey' && <div>Passkey user</div>}
</div>
);
}
Returns:
connectionType: ConnectorType | null - The connection method (‘google’, ‘x’, ‘discord’, ‘metamask’, ‘walletconnect’, ‘email’, ‘passkey’, etc.)
connectorMeta: Connector metadata with name, icon, etc.
Authentication Hooks
useAuthContext()
Get current user and whoami information.
import { useAuthContext } from '@abstraxn/signer-react';
function MyComponent() {
const { user, whoami } = useAuthContext();
return (
<div>
{user && <p>User ID: {user.id}</p>}
{whoami && (
<div>
<p>EVM Address: {whoami.evmAddress}</p>
<p>Solana Address: {whoami.solanaAddress}</p>
</div>
)}
</div>
);
}
Returns:
user: User object
whoami: Whoami response with address information
useWhoami()
Call whoami API with loading state and refresh capability.
import { useWhoami } from '@abstraxn/signer-react';
import { useEffect } from 'react';
function MyComponent() {
const { whoami, loading, error, refreshWhoami, isConnected } = useWhoami();
useEffect(() => {
if (isConnected) {
refreshWhoami();
}
}, [isConnected, refreshWhoami]);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!whoami) return <div>No whoami data</div>;
return (
<div>
<p>EVM Address: {whoami.evmAddress}</p>
<p>Solana Address: {whoami.solanaAddress}</p>
<button onClick={refreshWhoami}>Refresh</button>
</div>
);
}
Returns:
whoami: WhoamiResponse | null - Whoami data
loading: boolean - Loading state
error: Error | null - Error state
refreshWhoami: Function to refresh whoami data
isConnected: boolean - Connection status
useExportWallet()
Export wallet private key.
import { useExportWallet } from '@abstraxn/signer-react';
function MyComponent() {
const { exportWallet, isConnected, address } = useExportWallet();
const handleExport = async () => {
try {
const result = await exportWallet(
'targetPublicKey', // Target public key for encryption
'privateKey', // Your private key for encryption
'evm' // or 'solana'
);
console.log('Export successful:', result);
} catch (error) {
console.error('Export failed:', error);
}
};
if (!isConnected) {
return <div>Please connect your wallet</div>;
}
return (
<button onClick={handleExport}>
Export Wallet
</button>
);
}
Returns:
exportWallet: Function to export wallet
isConnected: boolean - Connection status
address: string | null - Wallet address
Transaction Hooks
usePublicClient(chain, rpcUrl)
Create a publicClient using viem for read operations.
import { usePublicClient } from '@abstraxn/signer-react';
import { polygonAmoy } from 'viem/chains';
function MyComponent() {
const { publicClient } = usePublicClient(
polygonAmoy,
'https://rpc-amoy.polygon.technology'
);
const getBalance = async (address: string) => {
const balance = await publicClient.getBalance({ address: address as `0x${string}` });
return balance;
};
return (
<button onClick={() => getBalance('0x...')}>
Get Balance
</button>
);
}
Parameters:
chain: Viem chain object (from ‘viem/chains’ or custom)
rpcUrl: RPC URL for the chain
Returns:
publicClient: PublicClient instance from viem
useWalletClient(chain, rpcUrl?)
Create a walletClient using viem for broadcasting signed transactions.
import { useWalletClient } from '@abstraxn/signer-react';
import { polygonAmoy } from 'viem/chains';
function MyComponent() {
const { walletClient } = useWalletClient(
polygonAmoy,
'https://rpc-amoy.polygon.technology'
);
const broadcastTransaction = async (signedTx: string) => {
const hash = await walletClient.sendRawTransaction({
serializedTransaction: signedTx as `0x${string}`,
});
return hash;
};
return (
<button onClick={() => broadcastTransaction('0x...')}>
Broadcast Transaction
</button>
);
}
Parameters:
chain: Viem chain object
rpcUrl: Optional RPC URL (uses chain’s default if not provided)
Returns:
walletClient: WalletClient instance from viem
usePrepareRawTxn(provider)
Prepare raw transaction data with encoding support.
import { usePrepareRawTxn, usePublicClient, useAddress } from '@abstraxn/signer-react';
import { polygonAmoy } from 'viem/chains';
function MyComponent() {
const address = useAddress();
const { publicClient } = usePublicClient(polygonAmoy, 'https://rpc-amoy.polygon.technology');
const { prepareRawTxn } = usePrepareRawTxn(publicClient);
// Native transfer
const handleNativeTransfer = async () => {
const nativeTx = await prepareRawTxn({
from: address!,
to: '0x...',
value: '0.001', // ETH amount
});
// Returns: { to: '0x...', value: '0x...', data: '0x' }
console.log(nativeTx);
};
// Contract call with encoding
const handleContractCall = async () => {
const contractTx = await prepareRawTxn({
from: address!,
to: '0x...', // Contract address
abi: erc20Abi,
functionName: 'transfer',
args: ['0x...', 1000000n], // Pass values in the expected on-chain format
value: '0', // Optional ETH value
});
// Returns: { to: '0x...', value: '0x', data: '0xa9059cbb...' }
console.log(contractTx);
};
// Contract call with pre-encoded data
const handlePreEncoded = async () => {
const contractTx = await prepareRawTxn({
from: address!,
to: '0x...',
data: '0xa9059cbb...', // Already encoded
});
console.log(contractTx);
};
return (
<div>
<button onClick={handleNativeTransfer}>Native Transfer</button>
<button onClick={handleContractCall}>Contract Call</button>
</div>
);
}
Parameters:
provider: PublicClient instance
Returns:
prepareRawTxn: Function that accepts:
from: Address
to: Address
value?: Native token value (pass in chain/base units, e.g. wei)
data?: Pre-encoded function data
abi?: Contract ABI (for encoding)
functionName?: Function name (for encoding)
args?: Function arguments (passed through as-is; no implicit amount conversion)
useSignTxn(provider)
Sign transaction using Abstraxn server wallet API.
import { useSignTxn, usePrepareRawTxn, usePublicClient, useAddress } from '@abstraxn/signer-react';
import { polygonAmoy } from 'viem/chains';
function MyComponent() {
const address = useAddress();
const { publicClient } = usePublicClient(polygonAmoy, 'https://rpc-amoy.polygon.technology');
const { prepareRawTxn } = usePrepareRawTxn(publicClient);
const { signTxn, isConnected } = useSignTxn(publicClient);
const handleSign = async () => {
// Prepare transaction
const rawTx = await prepareRawTxn({
from: address!,
to: '0x...',
value: '0.001',
});
// Sign transaction
const signedTx = await signTxn({
from: address!,
...rawTx, // Spread to, value, data from prepareRawTxn
});
console.log('Signed transaction:', signedTx.signedTransaction);
};
if (!isConnected) {
return <div>Please connect your wallet</div>;
}
return <button onClick={handleSign}>Sign Transaction</button>;
}
Parameters:
provider: PublicClient instance
Returns:
signTxn: Function to sign transaction
isConnected: boolean - Connection status
address: string | null - Wallet address
useSignAndSendTxn(provider)
Sign and send transaction using Abstraxn server wallet API.
import { useSignAndSendTxn, usePrepareRawTxn, usePublicClient, useAddress } from '@abstraxn/signer-react';
import { polygonAmoy } from 'viem/chains';
function MyComponent() {
const address = useAddress();
const { publicClient } = usePublicClient(polygonAmoy, 'https://rpc-amoy.polygon.technology');
const { prepareRawTxn } = usePrepareRawTxn(publicClient);
const { signAndSendTxn, isConnected } = useSignAndSendTxn(publicClient);
const handleSend = async () => {
// Prepare transaction
const rawTx = await prepareRawTxn({
from: address!,
to: '0x...',
value: '0.001',
});
// Sign and send transaction
const result = await signAndSendTxn({
from: address!,
...rawTx, // Spread to, value, data from prepareRawTxn
});
console.log('Transaction hash:', result.hash);
};
if (!isConnected) {
return <div>Please connect your wallet</div>;
}
return <button onClick={handleSend}>Send Transaction</button>;
}
Parameters:
provider: PublicClient instance
Returns:
signAndSendTxn: Function to sign and send transaction
isConnected: boolean - Connection status
address: string | null - Wallet address
useWaitForTxnReceipt(provider)
Wait for transaction receipt.
import { useWaitForTxnReceipt, usePublicClient } from '@abstraxn/signer-react';
import { polygonAmoy } from 'viem/chains';
function MyComponent() {
const { publicClient } = usePublicClient(polygonAmoy, 'https://rpc-amoy.polygon.technology');
const { waitForTxnReceipt } = useWaitForTxnReceipt(publicClient);
const handleWait = async (txHash: string) => {
try {
const receipt = await waitForTxnReceipt({
hash: txHash as `0x${string}`,
confirmations: 1, // Optional: number of confirmations
});
console.log('Transaction confirmed:', receipt);
console.log('Status:', receipt.status);
} catch (error) {
console.error('Failed to wait for receipt:', error);
}
};
return (
<button onClick={() => handleWait('0x...')}>
Wait for Receipt
</button>
);
}
Parameters:
provider: PublicClient instance
Returns:
waitForTxnReceipt: Function that accepts:
hash: Transaction hash
confirmations?: Number of confirmations to wait for
timeout?: Timeout in milliseconds
useSwitchChain()
Switch chain for both internal (social) and external wallets.
import { useSwitchChain } from '@abstraxn/signer-react';
function MyComponent() {
const { switchChain } = useSwitchChain();
const handleSwitch = async () => {
try {
await switchChain(137); // Switch to Polygon
console.log('Chain switched successfully');
} catch (error) {
console.error('Failed to switch chain:', error);
}
};
return <button onClick={handleSwitch}>Switch to Polygon</button>;
}
Returns:
switchChain: Function to switch chain (accepts chainId: number)
useSignMessage()
Sign a message (for external wallets only).
import { useSignMessage } from '@abstraxn/signer-react';
function MyComponent() {
const { signMessage } = useSignMessage();
const handleSign = async () => {
try {
const signature = await signMessage('Hello World');
console.log('Signature:', signature);
} catch (error) {
console.error('Failed to sign message:', error);
}
};
return <button onClick={handleSign}>Sign Message</button>;
}
Note: Signing messages is not supported for embedded wallets (Google, email, etc.). Only works with external wallets.
Returns:
signMessage: Function to sign message (accepts message: string)
Contract Interaction Hooks
useContract({ address, abi, provider })
Create a contract instance using viem.
import { useContract, usePublicClient } from '@abstraxn/signer-react';
import { polygonAmoy } from 'viem/chains';
import erc20Abi from './erc20Abi.json';
function MyComponent() {
const { publicClient } = usePublicClient(polygonAmoy, 'https://rpc-amoy.polygon.technology');
const { contract } = useContract({
address: '0x...',
abi: erc20Abi,
provider: publicClient,
});
const readBalance = async (address: string) => {
const balance = await contract.read.balanceOf([address]);
return balance;
};
return (
<button onClick={() => readBalance('0x...')}>
Read Balance
</button>
);
}
Parameters:
address: Contract address
abi: Contract ABI
provider: PublicClient instance
Returns:
contract: Contract instance from viem
useReadContract(provider)
Read from contract using publicClient.
import { useReadContract, usePublicClient } from '@abstraxn/signer-react';
import { polygonAmoy } from 'viem/chains';
import erc20Abi from './erc20Abi.json';
function MyComponent() {
const { publicClient } = usePublicClient(polygonAmoy, 'https://rpc-amoy.polygon.technology');
const { readContract } = useReadContract(publicClient);
const readBalance = async () => {
try {
const balance = await readContract({
address: '0x...',
abi: erc20Abi,
functionName: 'balanceOf',
args: ['0x...'],
});
console.log('Balance:', balance);
} catch (error) {
console.error('Failed to read contract:', error);
}
};
const readName = async () => {
const name = await readContract({
address: '0x...',
abi: erc20Abi,
functionName: 'name',
});
console.log('Name:', name);
};
return (
<div>
<button onClick={readBalance}>Read Balance</button>
<button onClick={readName}>Read Name</button>
</div>
);
}
Parameters:
provider: PublicClient instance
Returns:
readContract: Function that accepts:
address: Contract address
abi: Contract ABI
functionName: Function name
args?: Function arguments
useWriteContract()
Write to contract (for external wallets like MetaMask, WalletConnect, etc.).
import { useWriteContract } from '@abstraxn/signer-react';
import { parseEther } from 'viem';
import erc20Abi from './erc20Abi.json';
function MyComponent() {
const { writeContract } = useWriteContract();
const handleTransfer = async () => {
try {
// Write to contract
const hash = await writeContract({
address: '0x...', // Contract address
abi: erc20Abi,
functionName: 'transfer',
args: ['0x...', '1000000000000000000'], // to, amount in wei
});
console.log('Transaction hash:', hash);
} catch (error) {
console.error('Transaction failed:', error);
}
};
const handleDeposit = async () => {
try {
// With ETH value
const hash = await writeContract({
address: '0x...',
abi: contractAbi,
functionName: 'deposit',
value: parseEther('0.1'), // Send 0.1 ETH with the transaction
});
console.log('Transaction hash:', hash);
} catch (error) {
console.error('Transaction failed:', error);
}
};
return (
<div>
<button onClick={handleTransfer}>Transfer Tokens</button>
<button onClick={handleDeposit}>Deposit</button>
</div>
);
}
Returns:
writeContract: Function that accepts:
address: Contract address
abi: Contract ABI
functionName: Function name
args?: Function arguments
value?: ETH value (bigint)
account?: Account address
gas?: Gas limit
gasPrice?: Gas price
maxFeePerGas?: Max fee per gas
maxPriorityFeePerGas?: Max priority fee per gas
nonce?: Nonce
MFA Hooks
useEnableMfa()
Manage the MFA enable setup flow:
start() initializes setup and returns QR + secret
verifyCode(code) verifies TOTP setup
verifyRecoveryCode(code) validates backup/recovery code
setupState moves through setup -> verify -> complete
import { useEnableMfa } from '@abstraxn/signer-react';
function EnableMfaCard() {
const { setupState, start, verifyCode, isLoading, error } = useEnableMfa();
return (
<div>
<button onClick={() => void start()}>Start MFA setup</button>
{setupState?.step === 'setup' && <img src={setupState.qrCode} alt="MFA QR" />}
{setupState?.step === 'verify' && (
<button onClick={() => void verifyCode('123456')}>Verify code</button>
)}
{isLoading && <p>Loading...</p>}
{error && <p>Error: {error}</p>}
</div>
);
}
useDisableMfa()
Manage MFA disable flow:
start() begins auth step
switchMethod('otp' | 'recovery') selects auth mode
verifyCode(code) verifies OTP or backup code
confirmDisable() disables MFA after verification
import { useDisableMfa } from '@abstraxn/signer-react';
function DisableMfaCard() {
const { start, verifyCode, confirmDisable, disableState } = useDisableMfa();
return (
<div>
{!disableState && <button onClick={start}>Disable MFA</button>}
{disableState?.step === 'auth' && (
<button onClick={() => void verifyCode('123456')}>Verify</button>
)}
{disableState?.step === 'confirm' && (
<button onClick={() => void confirmDisable()}>Confirm disable</button>
)}
</div>
);
}
useEmailForOtp()
Pre-fill the onboarding email field for OTP login.
import { useEmailForOtp } from '@abstraxn/signer-react';
function PrefillEmailButton() {
const { emailForOtp, setEmailForOtp } = useEmailForOtp();
return (
<button onClick={() => setEmailForOtp('[email protected]')}>
Current email: {emailForOtp || 'not set'}
</button>
);
}
Typed Signing
useSignTypedTx()
Sign EIP-712 payloads with embedded wallets.
import { useAddress, useSignTypedTx } from '@abstraxn/signer-react';
function SignTypedDataExample() {
const address = useAddress();
const { signTypedTx } = useSignTypedTx();
const sign = async () => {
if (!address) return;
const result = await signTypedTx({
from: address as `0x${string}`,
domain: { name: 'Demo', version: '1', chainId: 80002 },
primaryType: 'Mail',
types: {
Mail: [
{ name: 'to', type: 'address' },
{ name: 'contents', type: 'string' },
],
},
message: {
to: address,
contents: 'hello',
},
encoding: 'PAYLOAD_ENCODING_EIP712',
hashFunction: 'HASH_FUNCTION_KECCAK256',
});
console.log(result.signature);
};
return <button onClick={() => void sign()}>Sign typed payload</button>;
}
External Wallet Client Hook
useExternalWalletClient()
Access the underlying external wallet client (wagmi connector client) and connection state.
import { useExternalWalletClient } from '@abstraxn/signer-react';
function ExternalWalletClientState() {
const { walletClient, isConnected, isPending, isError, error } =
useExternalWalletClient();
return (
<div>
<p>Connected: {String(isConnected)}</p>
<p>Pending: {String(isPending)}</p>
<p>Error: {isError ? error?.message : 'none'}</p>
<p>Client ready: {String(!!walletClient)}</p>
</div>
);
}
Solana Hooks
useSolanaConnection(rpcUrl, commitment?)
Create a Solana RPC connection.
useSolanaPublicKey()
Get the current Solana address from authenticated user context.
useSolanaBalance()
Load Solana balance (lamports, formattedBalance, loading/error).
usePrepareSolanaTxn(connection)
Prepare transfer or instruction-based transactions.
useSignSolanaTxn(connection)
Sign prepared Solana transaction through SDK signing API.
useSignAndSendSolanaTxn(connection)
Sign and send prepared Solana transaction in one call.
useWaitForSolanaConfirmation(connection)
Wait for signature confirmation on Solana.
usePrepareSolanaProgramTxn(connection) and useSolanaProgramTransaction(connection)
Prepare and send program transactions with programId, accounts, and encoded instruction data.
useSolanaExternalWallet()
Interact with connected external Solana wallets (sign message, sign tx, send tx).
import {
useSolanaConnection,
usePrepareSolanaTxn,
useSignAndSendSolanaTxn,
useWaitForSolanaConfirmation,
useSolanaPublicKey,
} from '@abstraxn/signer-react';
function SolanaSendExample() {
const { solanaAddress } = useSolanaPublicKey();
const { connection } = useSolanaConnection('https://api.devnet.solana.com');
const { prepareSolanaTransfer } = usePrepareSolanaTxn(connection);
const { signAndSendSolanaTxn } = useSignAndSendSolanaTxn(connection);
const { waitForSolanaConfirmation } = useWaitForSolanaConfirmation(connection);
const send = async () => {
if (!solanaAddress) return;
const { transaction } = await prepareSolanaTransfer({
fromPubkey: solanaAddress,
toPubkey: '9xQeWvG816bUx9EPfEZ9PzWQw4j6wVx6U6z9ER6Q9Y2Z',
amountInSol: 0.01,
});
const sent = await signAndSendSolanaTxn({ transaction, fromPubkey: solanaAddress });
await waitForSolanaConfirmation({ signature: sent.signature });
};
return <button onClick={() => void send()}>Send SOL</button>;
}
Complete Transaction Flow Example
Here’s a complete example showing how to use multiple hooks together for a full transaction flow:
import {
useAddress,
usePublicClient,
usePrepareRawTxn,
useSignAndSendTxn,
useWaitForTxnReceipt
} from '@abstraxn/signer-react';
import { polygonAmoy } from 'viem/chains';
import { useState } from 'react';
function SendTransactionComponent() {
const address = useAddress();
const { publicClient } = usePublicClient(
polygonAmoy,
'https://rpc-amoy.polygon.technology'
);
const { prepareRawTxn } = usePrepareRawTxn(publicClient);
const { signAndSendTxn, isConnected } = useSignAndSendTxn(publicClient);
const { waitForTxnReceipt } = useWaitForTxnReceipt(publicClient);
const [loading, setLoading] = useState(false);
const [txHash, setTxHash] = useState<string | null>(null);
const [receipt, setReceipt] = useState<any>(null);
const handleSendTransaction = async () => {
if (!address || !isConnected) {
alert('Please connect your wallet');
return;
}
setLoading(true);
try {
// Step 1: Prepare transaction
const rawTx = await prepareRawTxn({
from: address,
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', // Example recipient
value: '0.001', // Send 0.001 ETH
});
// Step 2: Sign and send transaction
const result = await signAndSendTxn({
from: address,
...rawTx,
});
setTxHash(result.hash);
// Step 3: Wait for receipt
const txReceipt = await waitForTxnReceipt({
hash: result.hash,
confirmations: 1,
});
setReceipt(txReceipt);
console.log('Transaction confirmed:', txReceipt);
} catch (error) {
console.error('Transaction failed:', error);
alert(`Transaction failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
} finally {
setLoading(false);
}
};
if (!isConnected) {
return <div>Please connect your wallet</div>;
}
return (
<div>
<button onClick={handleSendTransaction} disabled={loading}>
{loading ? 'Processing...' : 'Send 0.001 ETH'}
</button>
{txHash && (
<div>
<p>Transaction Hash: {txHash}</p>
<a
href={`https://amoy.polygonscan.com/tx/${txHash}`}
target="_blank"
rel="noopener noreferrer"
>
View on PolygonScan
</a>
</div>
)}
{receipt && (
<div>
<p>Status: {receipt.status === 'success' ? 'Success' : 'Failed'}</p>
<p>Block Number: {receipt.blockNumber.toString()}</p>
</div>
)}
</div>
);
}
Notes
-
Provider Setup: Most hooks require a
PublicClient instance. Create it using usePublicClient(chain, rpcUrl).
-
Connection Types:
- Social logins (Google, email, X, Discord, passkey) use embedded wallets
- External wallets (MetaMask, WalletConnect) use the connected wallet directly
-
Transaction Flow:
- For embedded wallets: Use
usePrepareRawTxn → useSignAndSendTxn → useWaitForTxnReceipt
- For external wallets: Use
useWriteContract or useExternalWalletInfo().walletClient
-
Error Handling: Always wrap hook calls in try-catch blocks for proper error handling.
-
Loading States: Many hooks provide loading states. Use them to show loading indicators in your UI.
-
Chain Switching: Use
useSwitchChain() to switch chains. It works for both embedded and external wallets.
-
MFA Step-Up: Signing hooks may require an MFA step-up verification code when enhanced security is enabled.
Next Steps