Overview
useChipiWallet is a convenience hook that simplifies wallet management by combining multiple operations into one:
- Wallet fetching (replaces
useGetWallet)
- Wallet creation (replaces
useCreateWallet)
- Balance checking (replaces
useGetTokenBalance)
Use this hook when you want a streamlined API. Use the individual hooks (useGetWallet, useCreateWallet, useGetTokenBalance) when you need more granular control.
Quick Start
import { useChipiWallet } from "@chipi-stack/chipi-expo";
function WalletComponent() {
const { userId, getToken } = useYourAuthProvider(); // Clerk, Firebase, etc.
const {
wallet,
hasWallet,
balance,
formattedBalance,
createWallet,
isCreating,
isLoadingWallet,
} = useChipiWallet({
externalUserId: userId,
getBearerToken: getToken,
});
if (isLoadingWallet) return <Text>Loading...</Text>;
if (!hasWallet) {
return (
<Button
title={isCreating ? "Creating..." : "Create Wallet"}
onPress={() => createWallet({ encryptKey: "1234", chain: "STARKNET" })}
disabled={isCreating}
/>
);
}
return (
<View>
<Text>Address: {wallet?.shortAddress}</Text>
<Text>Balance: ${formattedBalance} USDC</Text>
</View>
);
}
Configuration Options
interface UseChipiWalletConfig {
// Required
externalUserId: string | null | undefined;
getBearerToken: () => Promise<string | null | undefined>;
// Optional
defaultToken?: ChainToken; // Default: "USDC"
enabled?: boolean; // Default: true
}
| Option | Type | Default | Description |
|---|
externalUserId | string | null | Required | User ID from your auth provider |
getBearerToken | () => Promise<string> | Required | Function to get the auth token |
defaultToken | ChainToken | "USDC" | Token to fetch balance for |
enabled | boolean | true | Whether to fetch wallet on mount |
Return Values
Wallet Data
| Property | Type | Description |
|---|
wallet | ChipiWalletData | null | undefined | Wallet data with computed properties |
hasWallet | boolean | Whether the user has a wallet |
isLoadingWallet | boolean | Wallet fetch loading state |
walletError | Error | null | Any error from fetching |
Balance Data
| Property | Type | Description |
|---|
balance | GetTokenBalanceResponse | undefined | Raw balance data |
formattedBalance | string | Formatted balance (e.g., “1,234.56”) |
isLoadingBalance | boolean | Balance fetch loading state |
Create Wallet
| Property | Type | Description |
|---|
createWallet | (params) => Promise<CreateWalletResponse> | Create a new wallet |
isCreating | boolean | Creation loading state |
createdWallet | CreateWalletResponse | undefined | Last created wallet data |
Actions
| Method | Description |
|---|
refetchWallet() | Refetch wallet data |
refetchBalance() | Refetch balance data |
refetchAll() | Refetch both wallet and balance |
Computed Wallet Properties
The wallet object includes these computed properties:
interface ChipiWalletData extends GetWalletResponse {
supportsSessionKeys: boolean; // true for CHIPI wallets
shortAddress: string; // Truncated address for display
}
Example with Clerk Authentication
import { useState } from "react";
import { useAuth } from "@clerk/clerk-expo";
import { useChipiWallet } from "@chipi-stack/chipi-expo";
import { View, Text, TextInput, TouchableOpacity, ActivityIndicator } from "react-native";
export function WalletDashboard() {
const { userId, getToken } = useAuth();
const [pin, setPin] = useState("");
const {
wallet,
hasWallet,
formattedBalance,
createWallet,
isCreating,
isLoadingWallet,
refetchAll,
} = useChipiWallet({
externalUserId: userId,
getBearerToken: getToken,
});
const handleCreateWallet = async () => {
if (!pin || pin.length < 4) {
Alert.alert("Error", "Please enter a 4-digit PIN");
return;
}
try {
const result = await createWallet({
encryptKey: pin,
chain: "STARKNET",
walletType: "CHIPI",
});
Alert.alert("Success", `Wallet created! TX: ${result.txHash}`);
} catch (err) {
console.error(err);
Alert.alert("Error", "Failed to create wallet");
}
};
if (isLoadingWallet) {
return <ActivityIndicator size="large" />;
}
if (!hasWallet) {
return (
<View style={{ padding: 20, gap: 16 }}>
<TextInput
secureTextEntry
placeholder="Enter 4-digit PIN"
value={pin}
onChangeText={setPin}
maxLength={4}
keyboardType="numeric"
style={{ borderWidth: 1, padding: 12, borderRadius: 8 }}
/>
<TouchableOpacity
onPress={handleCreateWallet}
disabled={isCreating}
style={{ backgroundColor: '#007AFF', padding: 16, borderRadius: 8 }}
>
<Text style={{ color: 'white', textAlign: 'center' }}>
{isCreating ? "Creating..." : "Create Wallet"}
</Text>
</TouchableOpacity>
</View>
);
}
return (
<View style={{ padding: 20, gap: 16 }}>
<Text>Address: {wallet?.shortAddress}</Text>
<Text style={{ fontSize: 24, fontWeight: 'bold' }}>
${formattedBalance} USDC
</Text>
<Text>Sessions: {wallet?.supportsSessionKeys ? "✓ Supported" : "✗ Not Supported"}</Text>
<TouchableOpacity onPress={() => refetchAll()}>
<Text>Refresh</Text>
</TouchableOpacity>
</View>
);
}
Wallet Types
| Type | Session Keys | Description |
|---|
CHIPI | ✅ Yes | OpenZeppelin account with SNIP-9 session key support |
READY | ❌ No | Argent X compatible wallet |
// Create a CHIPI wallet (supports session keys)
await createWallet({
encryptKey: pin,
chain: "STARKNET",
walletType: "CHIPI"
});
// Create a READY wallet (no session keys)
await createWallet({
encryptKey: pin,
chain: "STARKNET",
walletType: "READY"
});
Migration from Individual Hooks
Before
const { data: wallet, isLoading } = useGetWallet({
params: { externalUserId: userId },
getBearerToken: getToken,
enabled: !!userId,
});
const { createWalletAsync } = useCreateWallet();
const { data: balance } = useGetTokenBalance({
params: { walletPublicKey: wallet?.publicKey, ... },
getBearerToken: getToken,
enabled: !!wallet?.publicKey,
});
After
const {
wallet,
hasWallet,
balance,
formattedBalance,
createWallet,
isLoadingWallet,
} = useChipiWallet({
externalUserId: userId,
getBearerToken: getToken,
});
useChipiWallet automatically handles the dependency chain - it only fetches balance after the wallet is loaded.