// Create Wallet Screen with biometric authentication
import { useCreateWallet, Chain } from '@chipi-stack/chipi-expo';
import { useAuth, useUser } from '@clerk/clerk-expo';
import * as SecureStore from 'expo-secure-store';
import { useState } from 'react';
import { StyleSheet, Text, View, Alert, Linking } from 'react-native';
import { PrimaryButton } from '@/components/ui/PrimaryButton';
import { SimpleInput } from '@/components/ui/SimpleInput';
export const CreateWalletView = () => {
const { getToken } = useAuth();
const { user } = useUser();
const [pin, setPin] = useState<string>('');
const [error, setError] = useState('');
const { createWalletAsync, isLoading } = useCreateWallet();
const [walletData, setWalletData] = useState<any>(null);
const handleCreateWallet = async () => {
try {
setError('');
const token = await getToken();
if (!token) {
setError('No bearer token found');
return;
}
const result = await createWalletAsync({
params: {
encryptKey: pin,
externalUserId: user?.id || '',
chain: Chain.STARKNET,
},
bearerToken: token,
});
// `createWalletAsync` returns a flat GetWalletResponse. Wallet fields
// (publicKey, normalizedPublicKey, etc.) live at the top level of
// `result` — see types/src/wallet.ts: `CreateWalletResponse = GetWalletResponse`.
await SecureStore.setItemAsync('wallet', JSON.stringify(result));
await SecureStore.setItemAsync('wallet_pin', pin, {
requireAuthentication: true,
});
setWalletData(result);
Alert.alert('Success', 'Wallet successfully created!');
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
setError('Error creating wallet: ' + errorMessage);
}
};
const openStarkscan = (address: string) => {
const url = `https://starkscan.co/contract/${address}`;
Linking.openURL(url);
};
return (
<View style={styles.container}>
<Text style={styles.title}>Create New Wallet</Text>
<Text style={styles.subtitle}>Set a PIN to secure your wallet</Text>
<SimpleInput
placeholder="Enter your PIN (min 4 digits)"
value={pin}
onChangeText={setPin}
keyboardType="numeric"
maxLength={6}
/>
{error ? <Text style={styles.errorText}>{error}</Text> : null}
<PrimaryButton
title={isLoading ? 'Creating...' : 'Create Wallet'}
active={pin.length >= 4 && !isLoading}
onPress={handleCreateWallet}
/>
{walletData && (
<View style={styles.walletDetails}>
<View style={styles.detailHeader}>
<Text style={styles.detailTitle}>Wallet Details</Text>
<Text
style={styles.viewContract}
onPress={() => openStarkscan(walletData.publicKey)}>
View Contract →
</Text>
</View>
<View style={styles.detailItem}>
<Text style={styles.detailLabel}>Address:</Text>
<Text style={styles.detailValue} numberOfLines={2}>
{walletData.publicKey}
</Text>
</View>
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#fff',
},
title: {
fontSize: 28,
fontWeight: 'bold',
marginBottom: 8,
color: '#11181C',
},
subtitle: {
fontSize: 16,
color: '#687076',
marginBottom: 24,
},
errorText: {
color: '#ff6b6b',
fontSize: 14,
marginTop: 8,
},
walletDetails: {
marginTop: 32,
padding: 16,
backgroundColor: '#f5f5f5',
borderRadius: 8,
},
detailHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
detailTitle: {
fontSize: 18,
fontWeight: '600',
color: '#11181C',
},
viewContract: {
fontSize: 14,
color: '#0a7ea4',
fontWeight: '600',
},
detailItem: {
marginBottom: 12,
},
detailLabel: {
fontSize: 14,
fontWeight: '600',
color: '#687076',
marginBottom: 4,
},
detailValue: {
fontSize: 14,
color: '#11181C',
fontFamily: 'monospace',
},
});