chore: initial commit for v0.0.1
DChain single-node blockchain + React Native messenger client. Core: - PBFT consensus with multi-sig validator admission + equivocation slashing - BadgerDB + schema migration scaffold (CurrentSchemaVersion=0) - libp2p gossipsub (tx/v1, blocks/v1, relay/v1, version/v1) - Native Go contracts (username_registry) alongside WASM (wazero) - WebSocket gateway with topic-based fanout + Ed25519-nonce auth - Relay mailbox with NaCl envelope encryption (X25519 + Ed25519) - Prometheus /metrics, per-IP rate limit, body-size cap Deployment: - Single-node compose (deploy/single/) with Caddy TLS + optional Prometheus - 3-node dev compose (docker-compose.yml) with mocked internet topology - 3-validator prod compose (deploy/prod/) for federation - Auto-update from Gitea via /api/update-check + systemd timer - Build-time version injection (ldflags → node --version) - UI / Swagger toggle flags (DCHAIN_DISABLE_UI, DCHAIN_DISABLE_SWAGGER) Client (client-app/): - Expo / React Native / NativeWind - E2E NaCl encryption, typing indicator, contact requests - Auto-discovery of canonical contracts, chain_id aware, WS reconnect on node switch Documentation: - README.md, CHANGELOG.md, CONTEXT.md - deploy/single/README.md with 6 operator scenarios - deploy/UPDATE_STRATEGY.md with 4-layer forward-compat design - docs/contracts/*.md per contract
This commit is contained in:
118
client-app/app/(auth)/created.tsx
Normal file
118
client-app/app/(auth)/created.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Account Created confirmation screen.
|
||||
* Shows address, pubkeys, and export options.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { View, Text, ScrollView, Alert, Share } from 'react-native';
|
||||
import { router } from 'expo-router';
|
||||
import * as Clipboard from 'expo-clipboard';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import * as Sharing from 'expo-sharing';
|
||||
import { useStore } from '@/lib/store';
|
||||
import { shortAddr } from '@/lib/crypto';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Card } from '@/components/ui/Card';
|
||||
import { Separator } from '@/components/ui/Separator';
|
||||
|
||||
export default function AccountCreatedScreen() {
|
||||
const keyFile = useStore(s => s.keyFile);
|
||||
const [copied, setCopied] = useState<string | null>(null);
|
||||
|
||||
if (!keyFile) {
|
||||
router.replace('/');
|
||||
return null;
|
||||
}
|
||||
|
||||
async function copy(value: string, label: string) {
|
||||
await Clipboard.setStringAsync(value);
|
||||
setCopied(label);
|
||||
setTimeout(() => setCopied(null), 2000);
|
||||
}
|
||||
|
||||
async function exportKey() {
|
||||
try {
|
||||
const json = JSON.stringify(keyFile, null, 2);
|
||||
const path = FileSystem.cacheDirectory + 'dchain_key.json';
|
||||
await FileSystem.writeAsStringAsync(path, json);
|
||||
if (await Sharing.isAvailableAsync()) {
|
||||
await Sharing.shareAsync(path, {
|
||||
mimeType: 'application/json',
|
||||
dialogTitle: 'Save your DChain key file',
|
||||
});
|
||||
} else {
|
||||
Alert.alert('Export', 'Sharing not available on this device.');
|
||||
}
|
||||
} catch (e: any) {
|
||||
Alert.alert('Export failed', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
className="flex-1 bg-background"
|
||||
contentContainerClassName="px-6 pt-16 pb-10"
|
||||
>
|
||||
{/* Success header */}
|
||||
<View className="items-center mb-8">
|
||||
<View className="w-20 h-20 rounded-full bg-success/20 items-center justify-center mb-4">
|
||||
<Text className="text-4xl">✓</Text>
|
||||
</View>
|
||||
<Text className="text-white text-2xl font-bold">Account Created!</Text>
|
||||
<Text className="text-muted text-sm mt-2 text-center">
|
||||
Your keys have been generated and stored securely.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Address card */}
|
||||
<Card className="mb-4">
|
||||
<Text className="text-muted text-xs uppercase tracking-widest mb-3 font-semibold">
|
||||
Your Address (Ed25519)
|
||||
</Text>
|
||||
<Text className="text-white font-mono text-xs leading-5 mb-3">
|
||||
{keyFile.pub_key}
|
||||
</Text>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onPress={() => copy(keyFile.pub_key, 'address')}
|
||||
>
|
||||
{copied === 'address' ? '✓ Copied' : 'Copy Address'}
|
||||
</Button>
|
||||
</Card>
|
||||
|
||||
{/* X25519 key */}
|
||||
<Card className="mb-4">
|
||||
<Text className="text-muted text-xs uppercase tracking-widest mb-3 font-semibold">
|
||||
Encryption Key (X25519)
|
||||
</Text>
|
||||
<Text className="text-white font-mono text-xs leading-5 mb-3">
|
||||
{keyFile.x25519_pub}
|
||||
</Text>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onPress={() => copy(keyFile.x25519_pub, 'x25519')}
|
||||
>
|
||||
{copied === 'x25519' ? '✓ Copied' : 'Copy Encryption Key'}
|
||||
</Button>
|
||||
</Card>
|
||||
|
||||
{/* Export warning */}
|
||||
<Card className="mb-8 border-yellow-500/30 bg-yellow-500/10">
|
||||
<Text className="text-yellow-400 text-sm font-semibold mb-2">🔐 Backup your key file</Text>
|
||||
<Text className="text-muted text-xs leading-5 mb-3">
|
||||
Export <Text className="text-white font-mono">dchain_key.json</Text> and store it safely.
|
||||
This file contains your private keys — keep it secret.
|
||||
</Text>
|
||||
<Button variant="outline" onPress={exportKey}>
|
||||
Export key.json
|
||||
</Button>
|
||||
</Card>
|
||||
|
||||
<Button size="lg" onPress={() => router.replace('/(app)/chats')}>
|
||||
Open Messenger
|
||||
</Button>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user