import { useCreateWallet, Chain } from '@chipi-stack/chipi-expo';
import type { GetWalletResponse } from '@chipi-stack/chipi-expo';
import * as SecureStore from 'expo-secure-store';
import { useAuth } from '@clerk/clerk-expo';
import { useState } from 'react';
import { View, Text, TextInput, TouchableOpacity, Alert, StyleSheet } from 'react-native';
export function CreateWalletWithPasskey() {
const { getToken, userId } = useAuth();
const { createWalletAsync, isLoading, error } = useCreateWallet();
const [pin, setPin] = useState('');
const [wallet, setWallet] = useState<GetWalletResponse | null>(null);
const handleCreate = async () => {
try {
const token = await getToken();
if (!token || !userId) {
Alert.alert('Error', 'No auth token or user ID found.');
return;
}
if (pin.length < 4) {
Alert.alert('Error', 'Please set a PIN (at least 4 digits) as your backup.');
return;
}
// Face ID / Touch ID prompt shown automatically.
// `encryptKey: pin` wires the dual-key flow (biometric primary + PIN backup).
const created = await createWalletAsync({
params: {
usePasskey: true,
externalUserId: userId,
encryptKey: pin,
chain: Chain.STARKNET,
},
bearerToken: token,
});
// `createWalletAsync` returns a flat GetWalletResponse — the wallet
// fields (publicKey, normalizedPublicKey, etc.) live at the top level
// of `created`, not nested under `created.wallet`.
await SecureStore.setItemAsync('wallet', JSON.stringify(created));
setWallet(created);
Alert.alert('Success', 'Wallet created — biometrics primary, PIN backup.');
} catch (err) {
Alert.alert('Error', err instanceof Error ? err.message : String(err));
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Create Wallet</Text>
<Text style={styles.subtitle}>Secured with Face ID / Touch ID + PIN backup</Text>
<TextInput
style={styles.pinInput}
placeholder="Set a PIN (min 4 digits — used as backup if biometrics fail)"
value={pin}
onChangeText={setPin}
keyboardType="number-pad"
secureTextEntry
maxLength={8}
/>
<TouchableOpacity
style={[styles.button, isLoading && styles.buttonDisabled]}
onPress={handleCreate}
disabled={isLoading || pin.length < 4}
>
<Text style={styles.buttonText}>
{isLoading ? 'Creating...' : 'Create Wallet with Biometrics + PIN'}
</Text>
</TouchableOpacity>
{error && <Text style={styles.error}>{error.message}</Text>}
{wallet && (
<Text style={styles.address} numberOfLines={2}>
{wallet.normalizedPublicKey ?? wallet.publicKey}
</Text>
)}
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 20 },
title: { fontSize: 24, fontWeight: 'bold', marginBottom: 8 },
subtitle: { color: '#687076', marginBottom: 24 },
pinInput: { borderWidth: 1, borderColor: '#ccc', borderRadius: 8, padding: 12, fontSize: 16, marginBottom: 16 },
button: { backgroundColor: '#007AFF', borderRadius: 8, padding: 16, alignItems: 'center' },
buttonDisabled: { opacity: 0.5 },
buttonText: { color: '#fff', fontWeight: '600', fontSize: 16 },
error: { color: '#ff3b30', marginTop: 12 },
address: { fontFamily: 'monospace', fontSize: 12, marginTop: 16, color: '#333' },
});