From 474a2fd14b0cdec47677e7cf66abaa3c3bc820fd Mon Sep 17 00:00:00 2001 From: Justin Hernandez Date: Thu, 3 Jul 2025 11:18:40 -0700 Subject: [PATCH 1/2] Add extensive proof analytics instrumentation --- app/src/consts/analytics.ts | 42 ++++++++++++++ app/src/screens/misc/LoadingScreen.tsx | 20 +------ app/src/utils/proving/provingMachine.ts | 73 ++++++++++++++++++++++++- 3 files changed, 115 insertions(+), 20 deletions(-) diff --git a/app/src/consts/analytics.ts b/app/src/consts/analytics.ts index 971ac30a5..750eb1fe4 100644 --- a/app/src/consts/analytics.ts +++ b/app/src/consts/analytics.ts @@ -48,6 +48,7 @@ export const PassportEvents = { PASSPORT_PARSE_FAILED: 'Passport: Passport Parse Failed', PASSPORT_PARSED: 'Passport: Passport Parsed', START_PASSPORT_NFC: 'Passport: Start Passport NFC', + PASSPORT_DATA_NOT_FOUND: 'Passport: Passport Data Not Found', UNSUPPORTED_PASSPORT: 'Passport: Passport Not Supported', }; @@ -63,6 +64,47 @@ export const ProofEvents = { PROVING_STATE_CHANGE: 'Proof: Proving State Change', REGISTER_COMPLETED: 'Proof: Register Completed', ALREADY_REGISTERED: 'Proof: Already Registered', + PROVING_INIT: 'Proof: Proving Machine Init', + CLEANUP_STARTED: 'Proof: Connections Cleanup Started', + CLEANUP_COMPLETED: 'Proof: Connections Cleanup Completed', + DOCUMENT_LOAD_STARTED: 'Proof: Load Selected Document Started', + LOAD_SECRET_FAILED: 'Proof: Load Secret Failed', + FETCH_DATA_STARTED: 'Proof: Fetch Data Started', + FETCH_DATA_SUCCESS: 'Proof: Fetch Data Succeeded', + FETCH_DATA_FAILED: 'Proof: Fetch Data Failed', + VALIDATION_STARTED: 'Proof: Validation Started', + VALIDATION_SUCCESS: 'Proof: Validation Succeeded', + VALIDATION_FAILED: 'Proof: Validation Failed', + PASSPORT_NULLIFIER_ONCHAIN: 'Proof: Passport Nullifier Onchain', + DSC_IN_TREE: 'Proof: DSC Already In Tree', + TEE_CONN_STARTED: 'Proof: TEE Connection Started', + TEE_CONN_SUCCESS: 'Proof: TEE Connection Succeeded', + TEE_CONN_FAILED: 'Proof: TEE Connection Failed', + WS_HELLO_SENT: 'Proof: WS Hello Sent', + WS_HELLO_ACK: 'Proof: WS Hello Acknowledged', + ATTESTATION_RECEIVED: 'Proof: Attestation Received', + ATTESTATION_VERIFIED: 'Proof: Attestation Verified', + SHARED_KEY_DERIVED: 'Proof: Shared Key Derived', + TEE_WS_ERROR: 'Proof: TEE WS Error', + TEE_WS_CLOSED: 'Proof: TEE WS Closed', + DEVICE_TOKEN_REG_STARTED: 'Proof: Device Token Registration Started', + DEVICE_TOKEN_REG_SUCCESS: 'Proof: Device Token Registration Succeeded', + DEVICE_TOKEN_REG_FAILED: 'Proof: Device Token Registration Failed', + PAYLOAD_GEN_STARTED: 'Proof: Payload Generation Started', + PAYLOAD_GEN_COMPLETED: 'Proof: Payload Generation Completed', + PAYLOAD_ENCRYPTED: 'Proof: Payload Encrypted', + PAYLOAD_SENT: 'Proof: Payload Sent', + SOCKETIO_CONN_STARTED: 'Proof: Socket.IO Connection Started', + SOCKETIO_SUBSCRIBED: 'Proof: Socket.IO Subscribed', + SOCKETIO_STATUS_RECEIVED: 'Proof: Socket.IO Status Received', + SOCKETIO_PROOF_SUCCESS: 'Proof: Socket.IO Proof Success', + SOCKETIO_PROOF_FAILURE: 'Proof: Socket.IO Proof Failure', + SOCKETIO_DISCONNECT_UNEXPECTED: 'Proof: Socket.IO Disconnected Unexpectedly', + SOCKETIO_CONNECT_ERROR: 'Proof: Socket.IO Connect Error', + POST_PROVING_STARTED: 'Proof: Post Proving Started', + POST_PROVING_CHAIN_STEP: 'Proof: Post Proving Chain Step', + POST_PROVING_COMPLETED: 'Proof: Post Proving Completed', + USER_CONFIRMED: 'Proof: User Confirmed', QR_SCAN_CANCELLED: 'Proof: QR Scan Cancelled', QR_SCAN_FAILED: 'Proof: QR Scan Failed', QR_SCAN_SUCCESS: 'Proof: QR Scan Success', diff --git a/app/src/screens/misc/LoadingScreen.tsx b/app/src/screens/misc/LoadingScreen.tsx index a62a97b7e..947b820a2 100644 --- a/app/src/screens/misc/LoadingScreen.tsx +++ b/app/src/screens/misc/LoadingScreen.tsx @@ -11,14 +11,14 @@ import { Text, YStack } from 'tamagui'; import failAnimation from '../../assets/animations/loading/fail.json'; import proveLoadingAnimation from '../../assets/animations/loading/prove.json'; import successAnimation from '../../assets/animations/loading/success.json'; -import { PassportEvents, ProofEvents } from '../../consts/analytics'; + import useHapticNavigation from '../../hooks/useHapticNavigation'; import CloseWarningIcon from '../../images/icons/close-warning.svg'; import { clearPassportData, loadPassportDataAndSecret, } from '../../providers/passportDataProvider'; -import analytics from '../../utils/analytics'; + import { black, slate400, white, zinc500, zinc900 } from '../../utils/colors'; import { extraYPadding } from '../../utils/constants'; import { advercase, dinot } from '../../utils/fonts'; @@ -31,8 +31,6 @@ import { } from '../../utils/proving/provingMachine'; import { checkPassportSupported } from '../../utils/proving/validateDocument'; -const { trackEvent } = analytics(); - type LoadingScreenProps = StaticScreenProps<{}>; const LoadingScreen: React.FC = ({}) => { @@ -75,11 +73,7 @@ const LoadingScreen: React.FC = ({}) => { const canCloseApp = safeToCloseStates.includes(currentState); const handleUnsupportedPassport = async (_passportData: PassportData) => { - const isSupported = await checkPassportSupported(_passportData); - trackEvent(PassportEvents.UNSUPPORTED_PASSPORT, { - reason: isSupported.status, - details: isSupported.details, - }); + await checkPassportSupported(_passportData); console.log('Passport not supported'); clearPassportData(); goToUnsupportedScreen(); @@ -105,9 +99,6 @@ const LoadingScreen: React.FC = ({}) => { } } catch (error: any) { console.error('Error loading passport data:', error); - trackEvent(PassportEvents.DATA_LOAD_ERROR, { - error: error?.message || 'Unknown error', - }); } } @@ -136,11 +127,6 @@ const LoadingScreen: React.FC = ({}) => { console.log('[LoadingScreen] Current proving state:', currentState); console.log('[LoadingScreen] FCM token available:', !!fcmToken); - trackEvent(ProofEvents.PROVING_STATE_CHANGE, { - state: currentState, - fcmTokenAvailable: !!fcmToken, - passportDataAvailable: !!passportData, - }); // Update UI if passport data is available if (passportData?.passportMetadata) { diff --git a/app/src/utils/proving/provingMachine.ts b/app/src/utils/proving/provingMachine.ts index 7aa298b91..1c3a12f8d 100644 --- a/app/src/utils/proving/provingMachine.ts +++ b/app/src/utils/proving/provingMachine.ts @@ -14,7 +14,7 @@ import { v4 } from 'uuid'; import { AnyActorRef, createActor, createMachine } from 'xstate'; import { create } from 'zustand'; -import { ProofEvents } from '../../consts/analytics'; +import { PassportEvents, ProofEvents } from '../../consts/analytics'; import { navigationRef } from '../../navigation'; import { unsafe_getPrivateKey } from '../../providers/authProvider'; import { @@ -201,6 +201,7 @@ export const useProvingStore = create((set, get) => { function setupActorSubscriptions(newActor: AnyActorRef) { newActor.subscribe((state: any) => { console.log(`State transition: ${state.value}`); + trackEvent(ProofEvents.PROVING_STATE_CHANGE, { state: state.value }); set({ currentState: state.value as ProvingStateType }); if (state.value === 'fetching_data') { @@ -232,6 +233,7 @@ export const useProvingStore = create((set, get) => { }, 3000); } if (state.value === 'completed') { + trackEvent(ProofEvents.PROOF_COMPLETED, { circuitType: get().circuitType }); if (get().circuitType !== 'disclose' && navigationRef.isReady()) { setTimeout(() => { navigationRef.navigate('AccountVerifiedSuccess'); @@ -296,6 +298,7 @@ export const useProvingStore = create((set, get) => { fcmToken: null, setFcmToken: (token: string) => { set({ fcmToken: token }); + trackEvent(ProofEvents.FCM_TOKEN_STORED); }, _handleWebSocketMessage: async (event: MessageEvent) => { if (!actor) { @@ -306,6 +309,7 @@ export const useProvingStore = create((set, get) => { try { const result = JSON.parse(event.data); if (result.result?.attestation) { + trackEvent(ProofEvents.ATTESTATION_RECEIVED); const attestationData = result.result.attestation; set({ attestation: attestationData }); @@ -318,6 +322,8 @@ export const useProvingStore = create((set, get) => { return; } + trackEvent(ProofEvents.ATTESTATION_VERIFIED); + const serverKey = ec.keyFromPublic(serverPubkey as string, 'hex'); const derivedKey = clientKey.derive(serverKey.getPublic()); @@ -325,6 +331,7 @@ export const useProvingStore = create((set, get) => { serverPublicKey: serverPubkey, sharedKey: Buffer.from(derivedKey.toArray('be', 32)), }); + trackEvent(ProofEvents.SHARED_KEY_DERIVED); actor!.send({ type: 'CONNECT_SUCCESS' }); } else if ( @@ -332,6 +339,7 @@ export const useProvingStore = create((set, get) => { typeof result.result === 'string' && !result.error ) { + trackEvent(ProofEvents.WS_HELLO_ACK); console.log('Received message with status:', result.id); const statusUuid = result.result; if (get().uuid !== statusUuid) { @@ -346,12 +354,15 @@ export const useProvingStore = create((set, get) => { console.error( 'Cannot start Socket.IO listener: endpointType not set.', ); + trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); actor!.send({ type: 'PROVE_ERROR' }); return; } get()._startSocketIOStatusListener(statusUuid, endpointType); } else if (result.error) { console.error('Received error from TEE:', result.error); + trackEvent(ProofEvents.TEE_WS_ERROR, { error: result.error }); + trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); actor!.send({ type: 'PROVE_ERROR' }); } else { console.warn('Received unknown message format from TEE:', result); @@ -359,8 +370,11 @@ export const useProvingStore = create((set, get) => { } catch (error) { console.error('Error processing WebSocket message:', error); if (get().currentState === 'init_tee_connexion') { + trackEvent(ProofEvents.TEE_CONN_FAILED, { message: (error as any).message }); actor!.send({ type: 'CONNECT_ERROR' }); } else { + trackEvent(ProofEvents.TEE_WS_ERROR, { error: (error as any).message }); + trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); actor!.send({ type: 'PROVE_ERROR' }); } } @@ -381,21 +395,26 @@ export const useProvingStore = create((set, get) => { transports: ['websocket'], }); set({ socketConnection: socket }); + trackEvent(ProofEvents.SOCKETIO_CONN_STARTED); socket.on('connect', () => { socket?.emit('subscribe', receivedUuid); + trackEvent(ProofEvents.SOCKETIO_SUBSCRIBED); }); socket.on('status', (message: any) => { const data = typeof message === 'string' ? JSON.parse(message) : message; console.log('Received status update with status:', data.status); + trackEvent(ProofEvents.SOCKETIO_STATUS_RECEIVED, { status: data.status }); if (data.status === 3 || data.status === 5) { console.error( 'Proof generation/verification failed (status 3 or 5).', ); console.error(data); set({ error_code: data.error_code, reason: data.reason }); + trackEvent(ProofEvents.SOCKETIO_PROOF_FAILURE, { error_code: data.error_code, reason: data.reason }); + trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: data.error_code ?? 'unknown' }); actor!.send({ type: 'PROVE_FAILURE' }); socket?.disconnect(); set({ socketConnection: null }); @@ -405,6 +424,7 @@ export const useProvingStore = create((set, get) => { if (get().circuitType === 'register') { trackEvent(ProofEvents.REGISTER_COMPLETED); } + trackEvent(ProofEvents.SOCKETIO_PROOF_SUCCESS); actor!.send({ type: 'PROVE_SUCCESS' }); } }); @@ -417,6 +437,8 @@ export const useProvingStore = create((set, get) => { console.error( 'SocketIO disconnected unexpectedly during proof listening.', ); + trackEvent(ProofEvents.SOCKETIO_DISCONNECT_UNEXPECTED); + trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); currentActor.send({ type: 'PROVE_ERROR' }); } set({ socketConnection: null }); @@ -424,6 +446,8 @@ export const useProvingStore = create((set, get) => { socket.on('connect_error', error => { console.error('SocketIO connection error:', error); + trackEvent(ProofEvents.SOCKETIO_CONNECT_ERROR, { message: (error as any).message }); + trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); actor!.send({ type: 'PROVE_ERROR' }); set({ socketConnection: null }); }); @@ -451,6 +475,7 @@ export const useProvingStore = create((set, get) => { uuid: connectionUuid, }, }; + trackEvent(ProofEvents.WS_HELLO_SENT); ws.send(JSON.stringify(helloBody)); }, @@ -470,6 +495,7 @@ export const useProvingStore = create((set, get) => { console.log( `TEE WebSocket closed. Code: ${event.code}, Reason: ${event.reason}`, ); + trackEvent(ProofEvents.TEE_WS_CLOSED, { code: event.code, reason: event.reason }); if (!actor) { return; } @@ -497,6 +523,7 @@ export const useProvingStore = create((set, get) => { circuitType: 'dsc' | 'disclose' | 'register', userConfirmed: boolean = false, ) => { + trackEvent(ProofEvents.PROVING_INIT); get()._closeConnections(); if (actor) { @@ -526,9 +553,11 @@ export const useProvingStore = create((set, get) => { setupActorSubscriptions(actor); actor.start(); + trackEvent(ProofEvents.DOCUMENT_LOAD_STARTED); const selectedDocument = await loadSelectedDocument(); if (!selectedDocument) { console.error('No document found for proving'); + trackEvent(PassportEvents.PASSPORT_DATA_NOT_FOUND, { stage: 'init' }); actor!.send({ type: 'PASSPORT_DATA_NOT_FOUND' }); return; } @@ -538,6 +567,7 @@ export const useProvingStore = create((set, get) => { const secret = await unsafe_getPrivateKey(); if (!secret) { console.error('Could not load secret'); + trackEvent(ProofEvents.LOAD_SECRET_FAILED); actor!.send({ type: 'ERROR' }); return; } @@ -548,10 +578,12 @@ export const useProvingStore = create((set, get) => { set({ passportData, secret, env }); set({ circuitType }); actor.send({ type: 'FETCH_DATA' }); + trackEvent(ProofEvents.FETCH_DATA_STARTED); }, startFetchingData: async () => { _checkActorInitialized(actor); + trackEvent(ProofEvents.FETCH_DATA_STARTED); try { const { passportData, env } = get(); const document: DocumentCategory = passportData.documentCategory; @@ -560,9 +592,11 @@ export const useProvingStore = create((set, get) => { [ document ].fetch_all(env!, (passportData as PassportData).dsc_parsed!.authorityKeyIdentifier); + trackEvent(ProofEvents.FETCH_DATA_SUCCESS); actor!.send({ type: 'FETCH_SUCCESS' }); } catch (error) { console.error('Error fetching data:', error); + trackEvent(ProofEvents.FETCH_DATA_FAILED, { message: (error as any).message }); actor!.send({ type: 'FETCH_ERROR' }); } }, @@ -570,6 +604,7 @@ export const useProvingStore = create((set, get) => { validatingDocument: async () => { _checkActorInitialized(actor); // TODO: for the disclosure, we could check that the selfApp is a valid one. + trackEvent(ProofEvents.VALIDATION_STARTED); try { const { passportData, secret, circuitType } = get(); const isSupported = await checkPassportSupported(passportData); @@ -579,6 +614,10 @@ export const useProvingStore = create((set, get) => { isSupported.status, isSupported.details, ); + trackEvent(PassportEvents.UNSUPPORTED_PASSPORT, { + status: isSupported.status, + details: isSupported.details, + }); await clearPassportData(); actor!.send({ type: 'PASSPORT_NOT_SUPPORTED' }); return; @@ -592,6 +631,7 @@ export const useProvingStore = create((set, get) => { secret as string, ); if (isRegisteredWithLocalCSCA) { + trackEvent(ProofEvents.VALIDATION_SUCCESS); actor!.send({ type: 'VALIDATION_SUCCESS' }); return; } else { @@ -619,6 +659,7 @@ export const useProvingStore = create((set, get) => { console.log( 'Passport is nullified, but not registered with this secret. Navigating to AccountRecoveryChoice', ); + trackEvent(ProofEvents.PASSPORT_NULLIFIER_ONCHAIN); actor!.send({ type: 'ACCOUNT_RECOVERY_CHOICE' }); return; } @@ -629,12 +670,15 @@ export const useProvingStore = create((set, get) => { ); console.log('isDscRegistered: ', isDscRegistered); if (isDscRegistered) { + trackEvent(ProofEvents.DSC_IN_TREE); set({ circuitType: 'register' }); } + trackEvent(ProofEvents.VALIDATION_SUCCESS); actor!.send({ type: 'VALIDATION_SUCCESS' }); } } catch (error) { console.error('Error validating passport:', error); + trackEvent(ProofEvents.VALIDATION_FAILED, { message: (error as any).message }); actor!.send({ type: 'VALIDATION_ERROR' }); } }, @@ -683,13 +727,20 @@ export const useProvingStore = create((set, get) => { } get()._closeConnections(); + trackEvent(ProofEvents.TEE_CONN_STARTED); return new Promise(resolve => { const ws = new WebSocket(wsRpcUrl); set({ wsConnection: ws }); - const handleConnectSuccess = () => resolve(true); - const handleConnectError = () => resolve(false); + const handleConnectSuccess = () => { + trackEvent(ProofEvents.TEE_CONN_SUCCESS); + resolve(true); + }; + const handleConnectError = (msg: string = 'connect_error') => { + trackEvent(ProofEvents.TEE_CONN_FAILED, { message: msg }); + resolve(false); + }; ws.addEventListener('message', get()._handleWebSocketMessage); ws.addEventListener('open', get()._handleWsOpen); @@ -724,6 +775,7 @@ export const useProvingStore = create((set, get) => { console.error( 'Cannot start proving: Missing wsConnection, sharedKey, passportData, secret, or uuid.', ); + trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); actor!.send({ type: 'PROVE_ERROR' }); return; } @@ -736,24 +788,32 @@ export const useProvingStore = create((set, get) => { registerDeviceToken, } = require('../../utils/notifications/notificationService'); const isMockPassport = passportData?.mock; + trackEvent(ProofEvents.DEVICE_TOKEN_REG_STARTED); await registerDeviceToken(uuid, fcmToken, isMockPassport); + trackEvent(ProofEvents.DEVICE_TOKEN_REG_SUCCESS); } catch (error) { console.error('Error registering device token:', error); + trackEvent(ProofEvents.DEVICE_TOKEN_REG_FAILED, { message: (error as any).message }); // Continue with the proving process even if token registration fails } } + trackEvent(ProofEvents.PAYLOAD_GEN_STARTED); const submitBody = await get()._generatePayload(); wsConnection.send(JSON.stringify(submitBody)); + trackEvent(ProofEvents.PAYLOAD_SENT); actor!.send({ type: 'START_PROVING' }); + trackEvent(ProofEvents.PROOF_VERIFICATION_STARTED); } catch (error) { console.error('Error during startProving preparation/send:', error); + trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); actor!.send({ type: 'PROVE_ERROR' }); } }, setUserConfirmed: () => { set({ userConfirmed: true }); + trackEvent(ProofEvents.USER_CONFIRMED); if (get().currentState === 'ready_to_prove') { get().startProving(); } @@ -762,13 +822,17 @@ export const useProvingStore = create((set, get) => { postProving: () => { _checkActorInitialized(actor); const { circuitType } = get(); + trackEvent(ProofEvents.POST_PROVING_STARTED); if (circuitType === 'dsc') { setTimeout(() => { + trackEvent(ProofEvents.POST_PROVING_CHAIN_STEP, { from: 'dsc', to: 'register' }); get().init('register', true); }, 1500); } else if (circuitType === 'register') { + trackEvent(ProofEvents.POST_PROVING_COMPLETED); actor!.send({ type: 'COMPLETED' }); } else if (circuitType === 'disclose') { + trackEvent(ProofEvents.POST_PROVING_COMPLETED); actor!.send({ type: 'COMPLETED' }); } }, @@ -882,6 +946,9 @@ export const useProvingStore = create((set, get) => { forgeKey, ); + trackEvent(ProofEvents.PAYLOAD_GEN_COMPLETED); + trackEvent(ProofEvents.PAYLOAD_ENCRYPTED); + // Persist endpointType for later Socket.IO connection set({ endpointType: endpointType as EndpointType }); return { From 51431b20cfd98f42488415c9d4c07b9514152c5b Mon Sep 17 00:00:00 2001 From: Justin Hernandez Date: Thu, 3 Jul 2025 11:31:10 -0700 Subject: [PATCH 2/2] prettier and sort events by key name --- app/src/consts/analytics.ts | 102 ++++++++++++------------ app/src/screens/misc/LoadingScreen.tsx | 3 - app/src/utils/proving/provingMachine.ts | 87 +++++++++++++++----- 3 files changed, 119 insertions(+), 73 deletions(-) diff --git a/app/src/consts/analytics.ts b/app/src/consts/analytics.ts index 750eb1fe4..bf4290796 100644 --- a/app/src/consts/analytics.ts +++ b/app/src/consts/analytics.ts @@ -33,10 +33,10 @@ export const AuthEvents = { export const PassportEvents = { CAMERA_SCAN_CANCELLED: 'Passport: Camera Scan Cancelled', - CAMERA_SCREEN_CLOSED: 'Passport: Camera View Closed', CAMERA_SCAN_FAILED: 'Passport: Camera Scan Failed', CAMERA_SCAN_STARTED: 'Passport: Camera Scan Started', CAMERA_SCAN_SUCCESS: 'Passport: Camera Scan Success', + CAMERA_SCREEN_CLOSED: 'Passport: Camera View Closed', CANCEL_PASSPORT_NFC: 'Passport: Cancel Passport NFC', DATA_LOAD_ERROR: 'Passport: Passport Data Load Error', DISMISS_UNSUPPORTED_PASSPORT: 'Passport: Dismiss Unsupported Passport', @@ -45,69 +45,69 @@ export const PassportEvents = { NFC_SCAN_SUCCESS: 'Passport: NFC Scan Success', OPEN_NFC_SETTINGS: 'Passport: Open NFC Settings', OWNERSHIP_CONFIRMED: 'Passport: Passport Ownership Confirmed', + PASSPORT_DATA_NOT_FOUND: 'Passport: Passport Data Not Found', PASSPORT_PARSE_FAILED: 'Passport: Passport Parse Failed', PASSPORT_PARSED: 'Passport: Passport Parsed', START_PASSPORT_NFC: 'Passport: Start Passport NFC', - PASSPORT_DATA_NOT_FOUND: 'Passport: Passport Data Not Found', UNSUPPORTED_PASSPORT: 'Passport: Passport Not Supported', }; export const ProofEvents = { + ALREADY_REGISTERED: 'Proof: Already Registered', + ATTESTATION_RECEIVED: 'Proof: Attestation Received', + ATTESTATION_VERIFIED: 'Proof: Attestation Verified', + CLEANUP_COMPLETED: 'Proof: Connections Cleanup Completed', + CLEANUP_STARTED: 'Proof: Connections Cleanup Started', + DEVICE_TOKEN_REG_FAILED: 'Proof: Device Token Registration Failed', + DEVICE_TOKEN_REG_STARTED: 'Proof: Device Token Registration Started', + DEVICE_TOKEN_REG_SUCCESS: 'Proof: Device Token Registration Succeeded', + DOCUMENT_LOAD_STARTED: 'Proof: Load Selected Document Started', + DSC_IN_TREE: 'Proof: DSC Already In Tree', FCM_TOKEN_STORED: 'Proof: FCM Token Stored Successfully', + FETCH_DATA_FAILED: 'Proof: Fetch Data Failed', + FETCH_DATA_STARTED: 'Proof: Fetch Data Started', + FETCH_DATA_SUCCESS: 'Proof: Fetch Data Succeeded', + LOAD_SECRET_FAILED: 'Proof: Load Secret Failed', NOTIFICATION_PERMISSION_REQUESTED: 'Proof: Notification Permission Requested', + PASSPORT_NULLIFIER_ONCHAIN: 'Proof: Passport Nullifier Onchain', + PAYLOAD_ENCRYPTED: 'Proof: Payload Encrypted', + PAYLOAD_GEN_COMPLETED: 'Proof: Payload Generation Completed', + PAYLOAD_GEN_STARTED: 'Proof: Payload Generation Started', + PAYLOAD_SENT: 'Proof: Payload Sent', + POST_PROVING_CHAIN_STEP: 'Proof: Post Proving Chain Step', + POST_PROVING_COMPLETED: 'Proof: Post Proving Completed', + POST_PROVING_STARTED: 'Proof: Post Proving Started', PROOF_COMPLETED: 'Proof: Proof Completed', PROOF_DISCLOSURES_SCROLLED: 'Proof: Proof Disclosures Scrolled', PROOF_FAILED: 'Proof: Proof Failed', PROOF_RESULT_ACKNOWLEDGED: 'Proof: Proof Result Acknowledged', PROOF_VERIFICATION_STARTED: 'Proof: Proof Verification Started', + PROVING_INIT: 'Proof: Proving Machine Init', PROVING_PROCESS_ERROR: 'Proof: Proving Process Error', PROVING_STATE_CHANGE: 'Proof: Proving State Change', + QR_SCAN_CANCELLED: 'Proof: QR Scan Cancelled', + QR_SCAN_FAILED: 'Proof: QR Scan Failed', + QR_SCAN_SUCCESS: 'Proof: QR Scan Success', REGISTER_COMPLETED: 'Proof: Register Completed', - ALREADY_REGISTERED: 'Proof: Already Registered', - PROVING_INIT: 'Proof: Proving Machine Init', - CLEANUP_STARTED: 'Proof: Connections Cleanup Started', - CLEANUP_COMPLETED: 'Proof: Connections Cleanup Completed', - DOCUMENT_LOAD_STARTED: 'Proof: Load Selected Document Started', - LOAD_SECRET_FAILED: 'Proof: Load Secret Failed', - FETCH_DATA_STARTED: 'Proof: Fetch Data Started', - FETCH_DATA_SUCCESS: 'Proof: Fetch Data Succeeded', - FETCH_DATA_FAILED: 'Proof: Fetch Data Failed', - VALIDATION_STARTED: 'Proof: Validation Started', - VALIDATION_SUCCESS: 'Proof: Validation Succeeded', - VALIDATION_FAILED: 'Proof: Validation Failed', - PASSPORT_NULLIFIER_ONCHAIN: 'Proof: Passport Nullifier Onchain', - DSC_IN_TREE: 'Proof: DSC Already In Tree', - TEE_CONN_STARTED: 'Proof: TEE Connection Started', - TEE_CONN_SUCCESS: 'Proof: TEE Connection Succeeded', - TEE_CONN_FAILED: 'Proof: TEE Connection Failed', - WS_HELLO_SENT: 'Proof: WS Hello Sent', - WS_HELLO_ACK: 'Proof: WS Hello Acknowledged', - ATTESTATION_RECEIVED: 'Proof: Attestation Received', - ATTESTATION_VERIFIED: 'Proof: Attestation Verified', SHARED_KEY_DERIVED: 'Proof: Shared Key Derived', - TEE_WS_ERROR: 'Proof: TEE WS Error', - TEE_WS_CLOSED: 'Proof: TEE WS Closed', - DEVICE_TOKEN_REG_STARTED: 'Proof: Device Token Registration Started', - DEVICE_TOKEN_REG_SUCCESS: 'Proof: Device Token Registration Succeeded', - DEVICE_TOKEN_REG_FAILED: 'Proof: Device Token Registration Failed', - PAYLOAD_GEN_STARTED: 'Proof: Payload Generation Started', - PAYLOAD_GEN_COMPLETED: 'Proof: Payload Generation Completed', - PAYLOAD_ENCRYPTED: 'Proof: Payload Encrypted', - PAYLOAD_SENT: 'Proof: Payload Sent', + SOCKETIO_CONNECT_ERROR: 'Proof: Socket.IO Connect Error', SOCKETIO_CONN_STARTED: 'Proof: Socket.IO Connection Started', - SOCKETIO_SUBSCRIBED: 'Proof: Socket.IO Subscribed', - SOCKETIO_STATUS_RECEIVED: 'Proof: Socket.IO Status Received', - SOCKETIO_PROOF_SUCCESS: 'Proof: Socket.IO Proof Success', - SOCKETIO_PROOF_FAILURE: 'Proof: Socket.IO Proof Failure', SOCKETIO_DISCONNECT_UNEXPECTED: 'Proof: Socket.IO Disconnected Unexpectedly', - SOCKETIO_CONNECT_ERROR: 'Proof: Socket.IO Connect Error', - POST_PROVING_STARTED: 'Proof: Post Proving Started', - POST_PROVING_CHAIN_STEP: 'Proof: Post Proving Chain Step', - POST_PROVING_COMPLETED: 'Proof: Post Proving Completed', + SOCKETIO_PROOF_FAILURE: 'Proof: Socket.IO Proof Failure', + SOCKETIO_PROOF_SUCCESS: 'Proof: Socket.IO Proof Success', + SOCKETIO_STATUS_RECEIVED: 'Proof: Socket.IO Status Received', + SOCKETIO_SUBSCRIBED: 'Proof: Socket.IO Subscribed', + TEE_CONN_FAILED: 'Proof: TEE Connection Failed', + TEE_CONN_STARTED: 'Proof: TEE Connection Started', + TEE_CONN_SUCCESS: 'Proof: TEE Connection Succeeded', + TEE_WS_CLOSED: 'Proof: TEE WS Closed', + TEE_WS_ERROR: 'Proof: TEE WS Error', USER_CONFIRMED: 'Proof: User Confirmed', - QR_SCAN_CANCELLED: 'Proof: QR Scan Cancelled', - QR_SCAN_FAILED: 'Proof: QR Scan Failed', - QR_SCAN_SUCCESS: 'Proof: QR Scan Success', + VALIDATION_FAILED: 'Proof: Validation Failed', + VALIDATION_STARTED: 'Proof: Validation Started', + VALIDATION_SUCCESS: 'Proof: Validation Succeeded', + WS_HELLO_ACK: 'Proof: WS Hello Acknowledged', + WS_HELLO_SENT: 'Proof: WS Hello Sent', }; export const SettingsEvents = { @@ -117,16 +117,16 @@ export const SettingsEvents = { }; export const BackupEvents = { - ACCOUNT_RECOVERY_STARTED: 'Backup: Account Recovery Started', ACCOUNT_RECOVERY_COMPLETED: 'Backup: Account Recovery Completed', + ACCOUNT_RECOVERY_STARTED: 'Backup: Account Recovery Started', ACCOUNT_VERIFICATION_COMPLETED: 'Backup: Account Verification Completed', - CLOUD_BACKUP_CONTINUE: 'Backup: Cloud Backup Continue', - CLOUD_BACKUP_STARTED: 'Backup: Cloud Backup Started', CLOUD_BACKUP_CANCELLED: 'Backup: Cloud Backup Cancelled', + CLOUD_BACKUP_CONTINUE: 'Backup: Cloud Backup Continue', CLOUD_BACKUP_DISABLED_DONE: 'Backup: Cloud Backup Disabled Done', CLOUD_BACKUP_DISABLE_STARTED: 'Backup: Cloud Backup Disable Started', CLOUD_BACKUP_ENABLED_DONE: 'Backup: Cloud Backup Enabled Done', CLOUD_BACKUP_ENABLE_STARTED: 'Backup: Cloud Backup Enable Started', + CLOUD_BACKUP_STARTED: 'Backup: Cloud Backup Started', CLOUD_RESTORE_FAILED_PASSPORT_NOT_REGISTERED: 'Backup: Cloud Restore Failed: Passport Not Registered', CLOUD_RESTORE_FAILED_UNKNOWN: 'Backup: Cloud Restore Failed: Unknown Error', @@ -150,13 +150,13 @@ export const MockDataEvents = { }; export const DocumentEvents = { - MANAGE_SCREEN_OPENED: 'Document: Manage Documents Screen Opened', + ADD_NEW_MOCK_SELECTED: 'Document: Add New Document via Mock', + ADD_NEW_SCAN_SELECTED: 'Document: Add New Document via Scan', + DOCUMENT_DELETED: 'Document: Document Deleted', + DOCUMENT_SELECTED: 'Document: Document Selected', DOCUMENTS_FETCHED: 'Document: Documents Fetched', + MANAGE_SCREEN_OPENED: 'Document: Manage Documents Screen Opened', NO_DOCUMENTS_FOUND: 'Document: No Documents Found', - DOCUMENT_SELECTED: 'Document: Document Selected', - DOCUMENT_DELETED: 'Document: Document Deleted', - ADD_NEW_SCAN_SELECTED: 'Document: Add New Document via Scan', - ADD_NEW_MOCK_SELECTED: 'Document: Add New Document via Mock', PASSPORT_INFO_OPENED: 'Document: Passport Info Screen Opened', PASSPORT_METADATA_LOADED: 'Document: Passport Metadata Loaded', }; diff --git a/app/src/screens/misc/LoadingScreen.tsx b/app/src/screens/misc/LoadingScreen.tsx index 947b820a2..66cf7627e 100644 --- a/app/src/screens/misc/LoadingScreen.tsx +++ b/app/src/screens/misc/LoadingScreen.tsx @@ -11,14 +11,12 @@ import { Text, YStack } from 'tamagui'; import failAnimation from '../../assets/animations/loading/fail.json'; import proveLoadingAnimation from '../../assets/animations/loading/prove.json'; import successAnimation from '../../assets/animations/loading/success.json'; - import useHapticNavigation from '../../hooks/useHapticNavigation'; import CloseWarningIcon from '../../images/icons/close-warning.svg'; import { clearPassportData, loadPassportDataAndSecret, } from '../../providers/passportDataProvider'; - import { black, slate400, white, zinc500, zinc900 } from '../../utils/colors'; import { extraYPadding } from '../../utils/constants'; import { advercase, dinot } from '../../utils/fonts'; @@ -127,7 +125,6 @@ const LoadingScreen: React.FC = ({}) => { console.log('[LoadingScreen] Current proving state:', currentState); console.log('[LoadingScreen] FCM token available:', !!fcmToken); - // Update UI if passport data is available if (passportData?.passportMetadata) { // Update loading text based on current state diff --git a/app/src/utils/proving/provingMachine.ts b/app/src/utils/proving/provingMachine.ts index 1c3a12f8d..051499515 100644 --- a/app/src/utils/proving/provingMachine.ts +++ b/app/src/utils/proving/provingMachine.ts @@ -233,7 +233,9 @@ export const useProvingStore = create((set, get) => { }, 3000); } if (state.value === 'completed') { - trackEvent(ProofEvents.PROOF_COMPLETED, { circuitType: get().circuitType }); + trackEvent(ProofEvents.PROOF_COMPLETED, { + circuitType: get().circuitType, + }); if (get().circuitType !== 'disclose' && navigationRef.isReady()) { setTimeout(() => { navigationRef.navigate('AccountVerifiedSuccess'); @@ -354,7 +356,10 @@ export const useProvingStore = create((set, get) => { console.error( 'Cannot start Socket.IO listener: endpointType not set.', ); - trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); + trackEvent(ProofEvents.PROOF_FAILED, { + circuitType: get().circuitType, + error: get().error_code ?? 'unknown', + }); actor!.send({ type: 'PROVE_ERROR' }); return; } @@ -362,7 +367,10 @@ export const useProvingStore = create((set, get) => { } else if (result.error) { console.error('Received error from TEE:', result.error); trackEvent(ProofEvents.TEE_WS_ERROR, { error: result.error }); - trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); + trackEvent(ProofEvents.PROOF_FAILED, { + circuitType: get().circuitType, + error: get().error_code ?? 'unknown', + }); actor!.send({ type: 'PROVE_ERROR' }); } else { console.warn('Received unknown message format from TEE:', result); @@ -370,11 +378,18 @@ export const useProvingStore = create((set, get) => { } catch (error) { console.error('Error processing WebSocket message:', error); if (get().currentState === 'init_tee_connexion') { - trackEvent(ProofEvents.TEE_CONN_FAILED, { message: (error as any).message }); + trackEvent(ProofEvents.TEE_CONN_FAILED, { + message: (error as any).message, + }); actor!.send({ type: 'CONNECT_ERROR' }); } else { - trackEvent(ProofEvents.TEE_WS_ERROR, { error: (error as any).message }); - trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); + trackEvent(ProofEvents.TEE_WS_ERROR, { + error: (error as any).message, + }); + trackEvent(ProofEvents.PROOF_FAILED, { + circuitType: get().circuitType, + error: get().error_code ?? 'unknown', + }); actor!.send({ type: 'PROVE_ERROR' }); } } @@ -406,15 +421,23 @@ export const useProvingStore = create((set, get) => { const data = typeof message === 'string' ? JSON.parse(message) : message; console.log('Received status update with status:', data.status); - trackEvent(ProofEvents.SOCKETIO_STATUS_RECEIVED, { status: data.status }); + trackEvent(ProofEvents.SOCKETIO_STATUS_RECEIVED, { + status: data.status, + }); if (data.status === 3 || data.status === 5) { console.error( 'Proof generation/verification failed (status 3 or 5).', ); console.error(data); set({ error_code: data.error_code, reason: data.reason }); - trackEvent(ProofEvents.SOCKETIO_PROOF_FAILURE, { error_code: data.error_code, reason: data.reason }); - trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: data.error_code ?? 'unknown' }); + trackEvent(ProofEvents.SOCKETIO_PROOF_FAILURE, { + error_code: data.error_code, + reason: data.reason, + }); + trackEvent(ProofEvents.PROOF_FAILED, { + circuitType: get().circuitType, + error: data.error_code ?? 'unknown', + }); actor!.send({ type: 'PROVE_FAILURE' }); socket?.disconnect(); set({ socketConnection: null }); @@ -438,7 +461,10 @@ export const useProvingStore = create((set, get) => { 'SocketIO disconnected unexpectedly during proof listening.', ); trackEvent(ProofEvents.SOCKETIO_DISCONNECT_UNEXPECTED); - trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); + trackEvent(ProofEvents.PROOF_FAILED, { + circuitType: get().circuitType, + error: get().error_code ?? 'unknown', + }); currentActor.send({ type: 'PROVE_ERROR' }); } set({ socketConnection: null }); @@ -446,8 +472,13 @@ export const useProvingStore = create((set, get) => { socket.on('connect_error', error => { console.error('SocketIO connection error:', error); - trackEvent(ProofEvents.SOCKETIO_CONNECT_ERROR, { message: (error as any).message }); - trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); + trackEvent(ProofEvents.SOCKETIO_CONNECT_ERROR, { + message: (error as any).message, + }); + trackEvent(ProofEvents.PROOF_FAILED, { + circuitType: get().circuitType, + error: get().error_code ?? 'unknown', + }); actor!.send({ type: 'PROVE_ERROR' }); set({ socketConnection: null }); }); @@ -495,7 +526,10 @@ export const useProvingStore = create((set, get) => { console.log( `TEE WebSocket closed. Code: ${event.code}, Reason: ${event.reason}`, ); - trackEvent(ProofEvents.TEE_WS_CLOSED, { code: event.code, reason: event.reason }); + trackEvent(ProofEvents.TEE_WS_CLOSED, { + code: event.code, + reason: event.reason, + }); if (!actor) { return; } @@ -596,7 +630,9 @@ export const useProvingStore = create((set, get) => { actor!.send({ type: 'FETCH_SUCCESS' }); } catch (error) { console.error('Error fetching data:', error); - trackEvent(ProofEvents.FETCH_DATA_FAILED, { message: (error as any).message }); + trackEvent(ProofEvents.FETCH_DATA_FAILED, { + message: (error as any).message, + }); actor!.send({ type: 'FETCH_ERROR' }); } }, @@ -678,7 +714,9 @@ export const useProvingStore = create((set, get) => { } } catch (error) { console.error('Error validating passport:', error); - trackEvent(ProofEvents.VALIDATION_FAILED, { message: (error as any).message }); + trackEvent(ProofEvents.VALIDATION_FAILED, { + message: (error as any).message, + }); actor!.send({ type: 'VALIDATION_ERROR' }); } }, @@ -775,7 +813,10 @@ export const useProvingStore = create((set, get) => { console.error( 'Cannot start proving: Missing wsConnection, sharedKey, passportData, secret, or uuid.', ); - trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); + trackEvent(ProofEvents.PROOF_FAILED, { + circuitType: get().circuitType, + error: get().error_code ?? 'unknown', + }); actor!.send({ type: 'PROVE_ERROR' }); return; } @@ -793,7 +834,9 @@ export const useProvingStore = create((set, get) => { trackEvent(ProofEvents.DEVICE_TOKEN_REG_SUCCESS); } catch (error) { console.error('Error registering device token:', error); - trackEvent(ProofEvents.DEVICE_TOKEN_REG_FAILED, { message: (error as any).message }); + trackEvent(ProofEvents.DEVICE_TOKEN_REG_FAILED, { + message: (error as any).message, + }); // Continue with the proving process even if token registration fails } } @@ -806,7 +849,10 @@ export const useProvingStore = create((set, get) => { trackEvent(ProofEvents.PROOF_VERIFICATION_STARTED); } catch (error) { console.error('Error during startProving preparation/send:', error); - trackEvent(ProofEvents.PROOF_FAILED, { circuitType: get().circuitType, error: get().error_code ?? 'unknown' }); + trackEvent(ProofEvents.PROOF_FAILED, { + circuitType: get().circuitType, + error: get().error_code ?? 'unknown', + }); actor!.send({ type: 'PROVE_ERROR' }); } }, @@ -825,7 +871,10 @@ export const useProvingStore = create((set, get) => { trackEvent(ProofEvents.POST_PROVING_STARTED); if (circuitType === 'dsc') { setTimeout(() => { - trackEvent(ProofEvents.POST_PROVING_CHAIN_STEP, { from: 'dsc', to: 'register' }); + trackEvent(ProofEvents.POST_PROVING_CHAIN_STEP, { + from: 'dsc', + to: 'register', + }); get().init('register', true); }, 1500); } else if (circuitType === 'register') {