Skip to content

Conversation

@remicolin
Copy link
Collaborator

@remicolin remicolin commented Nov 12, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added disclosure event tracking to point history
    • Introduced whitelist-based rewards after proof completion
  • Improvements

    • Enhanced proof history with endpoint information
    • Refined navigation flows for improved screen transitions

…handling

- Updated PointHistoryList to include loading of disclosure events on refresh.
- Enhanced ProveScreen to set user's points address if not already defined.
- Added endpoint field to ProofHistory and database schema for better tracking.
- Introduced utility functions for fetching whitelisted disclosure addresses and managing disclosure events.
- Changed navigation action in PointsNavBar from `goBack` to `navigate('Home')` for a more direct user experience.
- Updated GratificationScreen to navigate to 'Points' instead of going back, enhancing the flow after user interactions.
- Replaced the ArrowLeft icon with a new X icon for better visual consistency.
@remicolin remicolin requested a review from seshanthS November 12, 2025 18:35
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 12, 2025

Walkthrough

The PR extends the points system with whitelist-based disclosure events and endpoint tracking. It adds a new loadDisclosureEvents store method, updates the proof history database schema with an optional endpoint column, implements whitelist-based event filtering, and modifies navigation flows to support conditional routing to a Gratification screen.

Changes

Cohort / File(s) Summary
Navigation & Screen Updates
app/src/components/NavBar/PointsNavBar.tsx, app/src/screens/app/GratificationScreen.tsx, app/src/screens/verification/ProofRequestStatusScreen.tsx
Navigation targets changed from goBack() to explicit routes (Home, Points); ProofRequestStatusScreen added whitelist-aware navigation with conditional routing to Gratification screen when whitelisted points exist; GratificationScreen icon swapped from ArrowLeft to X.
Proof History & Database Schema
app/src/stores/proofTypes.ts, app/src/stores/database.ts, app/src/stores/proofHistoryStore.ts
ProofHistory interface extended with optional endpoint field; database schema migration adds endpoint column with retry logic for missing columns (documentId and endpoint); proof history loading updated to include endpoint in ProofHistory objects.
Points Store & Events Loading
app/src/stores/pointEventStore.ts, app/src/utils/points/getEvents.ts
New loadDisclosureEvents() method added to point event store that fetches and appends disclosure events based on whitelist; getDisclosurePointEvents refactored to filter proof history by whitelisted endpoints instead of delegating to event type lookup.
Points Utilities & Configuration
app/src/utils/points/utils.ts
New WhitelistedContract type introduced; getWhiteListedDisclosureAddresses now returns structured contract data with points and disclosure counts; pointsSelfApp config updated to remove user address computation.
Points & Proof Integration
app/src/screens/verification/ProveScreen.tsx, app/src/components/PointHistoryList.tsx
ProveScreen enriches selected app with user's points address via new effect; endpoint now included in proof history on add; PointHistoryList pull-to-refresh extended to await loadDisclosureEvents in parallel with existing refresh actions.

Sequence Diagram

sequenceDiagram
    participant User
    participant ProveScreen
    participant ProofRequest as ProofRequestStatusScreen
    participant Whitelist as Whitelist Service
    participant GratificationScreen
    participant HomeScreen
    
    User->>ProveScreen: Select app
    ProveScreen->>ProveScreen: Enrich with points address
    
    User->>ProveScreen: Submit proof
    ProveScreen->>ProofRequest: Navigate with proof
    ProofRequest->>ProofRequest: Complete proof
    
    alt Whitelist Endpoint Check
        ProofRequest->>Whitelist: Query whitelisted addresses
        Whitelist-->>ProofRequest: Return contracts & points
        ProofRequest->>ProofRequest: Set whitelistedPoints state
        ProofRequest->>GratificationScreen: Navigate with points
        GratificationScreen-->>User: Show gratification
    else No Whitelist Data
        ProofRequest->>HomeScreen: Navigate
        HomeScreen-->>User: Return to home
    end
    
    ProofRequest->>ProofRequest: Cleanup (2s delay)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35–45 minutes

  • Database migration logic (database.ts): Review retry paths for missing columns (documentId, endpoint) to ensure idempotency and error handling correctness.
  • Whitelist-based filtering (getEvents.ts): Validate endpoint normalization (lowercase comparison), whitelist lookup logic, and error propagation.
  • Navigation conditional branching (ProofRequestStatusScreen.tsx): Confirm whitelist state transitions, dependency arrays, and that navigation paths don't create cycles or leave orphaned states.
  • Type propagation (across proofTypes, database, stores): Verify the optional endpoint field is properly threaded through all layers without runtime null-reference issues.
  • Pull-to-refresh concurrency (PointHistoryList.tsx): Ensure loadDisclosureEvents doesn't block or conflict with existing refresh actions.

Possibly related PRs

Suggested reviewers

  • motemotech
  • shazarre
  • transphorm

Poem

✨ Points now whisper of whitelisted wallets fair,
Endpoints tracked through proof's disclosure layer,
Gratification blooms when disclosure shines—
A dance of data, permission, and design! 🎭

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the primary objective of the changeset: integrating whitelisted addresses into the points system across multiple components and stores.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch app/use-whitelisted-addresses-for-points

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
app/src/stores/database.ts (1)

90-90: Consider adding an index on the endpoint column.

The endpoint column is queried by getDisclosurePointEvents to match against whitelisted addresses. If the proof_history table grows large, an index on endpoint would improve query performance. The existing pattern creates indexes on frequently queried columns (line 103-104).

Add an index after table creation:

   await db.executeSql(`
     CREATE INDEX IF NOT EXISTS idx_proof_history_timestamp ON ${TABLE_NAME} (timestamp)
   `);
+  
+  await db.executeSql(`
+    CREATE INDEX IF NOT EXISTS idx_proof_history_endpoint ON ${TABLE_NAME} (endpoint)
+  `);

Also applies to: 218-221

app/src/utils/points/utils.ts (1)

111-129: Consider adding timeout and caching for whitelist fetch.

The getWhiteListedDisclosureAddresses function lacks:

  1. Fetch timeout - could hang indefinitely on slow/unresponsive network
  2. Caching - the whitelist is fetched multiple times (in ProofRequestStatusScreen and getDisclosurePointEvents) for each proof

Consider adding a timeout and a simple in-memory cache with TTL to reduce network calls and improve reliability.

Example timeout pattern:

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);

try {
  const response = await fetch(
    `${POINTS_API_BASE_URL}/whitelisted-addresses`,
    { signal: controller.signal }
  );
  // ... rest of logic
} finally {
  clearTimeout(timeoutId);
}
app/src/screens/verification/ProofRequestStatusScreen.tsx (1)

68-84: Extract duplicate cleanup logic and clarify timing.

The onOkPress function contains duplicate setTimeout blocks (lines 75-77 and 80-82) that both clean up selfApp state after 2 seconds. This can be simplified. Additionally, the 2-second delay rationale isn't clear—consider documenting why this delay is necessary.

Apply this diff:

   const onOkPress = useCallback(async () => {
     buttonTap();
 
     if (whitelistedPoints !== null) {
       navigation.navigate('Gratification', {
         points: whitelistedPoints,
       });
-      setTimeout(() => {
-        selfClient.getSelfAppState().cleanSelfApp();
-      }, 2000);
     } else {
       goHome();
-      setTimeout(() => {
-        selfClient.getSelfAppState().cleanSelfApp();
-      }, 2000);
     }
+    
+    // Clean up after navigation completes
+    setTimeout(() => {
+      selfClient.getSelfAppState().cleanSelfApp();
+    }, 2000);
   }, [whitelistedPoints, navigation, goHome, selfClient]);
app/src/screens/verification/ProveScreen.tsx (1)

120-141: Remove debug console.log statements from useEffect.

The two console.log statements at lines 122 and 132 should be removed. While the blockchain wallet address is not sensitive PII, production code shouldn't retain debug logging. Apply the provided diff to clean this up.

   useEffect(() => {
-    console.log('useEffect selectedApp', selectedApp);
     if (!selectedApp || selectedApp.selfDefinedData) {
       return;
     }

     const enhanceApp = async () => {
       const address = await getPointsAddress();

       // Only update if still the same session
       if (selectedAppRef.current?.sessionId === selectedApp.sessionId) {
-        console.log('enhancing app with points address', address);
         selfClient.getSelfAppState().setSelfApp({
           ...selectedApp,
           selfDefinedData: address.toLowerCase(),
         });
       }
     };

     enhanceApp();
   }, [selectedApp, selfClient]);

The effect logic itself is sound—the sessionId guard properly prevents race conditions, and dependencies are correct.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2753de3 and 4d95ac7.

📒 Files selected for processing (11)
  • app/src/components/NavBar/PointsNavBar.tsx (1 hunks)
  • app/src/components/PointHistoryList.tsx (2 hunks)
  • app/src/screens/app/GratificationScreen.tsx (3 hunks)
  • app/src/screens/verification/ProofRequestStatusScreen.tsx (7 hunks)
  • app/src/screens/verification/ProveScreen.tsx (3 hunks)
  • app/src/stores/database.ts (4 hunks)
  • app/src/stores/pointEventStore.ts (2 hunks)
  • app/src/stores/proofHistoryStore.ts (1 hunks)
  • app/src/stores/proofTypes.ts (1 hunks)
  • app/src/utils/points/getEvents.ts (2 hunks)
  • app/src/utils/points/utils.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,ts,tsx,jsx,sol,nr}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{js,ts,tsx,jsx,sol,nr}: NEVER log sensitive data including PII (names, DOB, passport numbers, addresses), credentials, tokens, API keys, private keys, or session identifiers.
ALWAYS redact/mask sensitive fields in logs using consistent patterns (e.g., ***-***-1234 for passport numbers, J*** D*** for names).

Files:

  • app/src/stores/proofTypes.ts
  • app/src/screens/app/GratificationScreen.tsx
  • app/src/components/PointHistoryList.tsx
  • app/src/screens/verification/ProveScreen.tsx
  • app/src/components/NavBar/PointsNavBar.tsx
  • app/src/stores/proofHistoryStore.ts
  • app/src/screens/verification/ProofRequestStatusScreen.tsx
  • app/src/utils/points/utils.ts
  • app/src/stores/pointEventStore.ts
  • app/src/stores/database.ts
  • app/src/utils/points/getEvents.ts
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (app/AGENTS.md)

Type checking must pass before PRs (yarn types)

Files:

  • app/src/stores/proofTypes.ts
  • app/src/screens/app/GratificationScreen.tsx
  • app/src/components/PointHistoryList.tsx
  • app/src/screens/verification/ProveScreen.tsx
  • app/src/components/NavBar/PointsNavBar.tsx
  • app/src/stores/proofHistoryStore.ts
  • app/src/screens/verification/ProofRequestStatusScreen.tsx
  • app/src/utils/points/utils.ts
  • app/src/stores/pointEventStore.ts
  • app/src/stores/database.ts
  • app/src/utils/points/getEvents.ts
app/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

app/src/**/*.{ts,tsx,js,jsx}: Review React Native TypeScript code for:

  • Component architecture and reusability
  • State management patterns
  • Performance optimizations
  • TypeScript type safety
  • React hooks usage and dependencies
  • Navigation patterns

Files:

  • app/src/stores/proofTypes.ts
  • app/src/screens/app/GratificationScreen.tsx
  • app/src/components/PointHistoryList.tsx
  • app/src/screens/verification/ProveScreen.tsx
  • app/src/components/NavBar/PointsNavBar.tsx
  • app/src/stores/proofHistoryStore.ts
  • app/src/screens/verification/ProofRequestStatusScreen.tsx
  • app/src/utils/points/utils.ts
  • app/src/stores/pointEventStore.ts
  • app/src/stores/database.ts
  • app/src/utils/points/getEvents.ts
🧠 Learnings (9)
📚 Learning: 2025-09-22T11:10:22.019Z
Learnt from: CR
Repo: selfxyz/self PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-22T11:10:22.019Z
Learning: Applies to src/**/*.{js,ts,tsx,jsx} : Use `react-navigation/native` with `createStaticNavigation` for type-safe navigation in React Native.

Applied to files:

  • app/src/screens/app/GratificationScreen.tsx
  • app/src/components/NavBar/PointsNavBar.tsx
  • app/src/screens/verification/ProofRequestStatusScreen.tsx
📚 Learning: 2025-08-23T02:02:02.556Z
Learnt from: transphorm
Repo: selfxyz/self PR: 942
File: app/vite.config.ts:170-0
Timestamp: 2025-08-23T02:02:02.556Z
Learning: In the selfxyz/self React Native app, devTools from '@/navigation/devTools' are intentionally shipped to production builds for testing purposes, not excluded as is typical in most applications.

Applied to files:

  • app/src/screens/app/GratificationScreen.tsx
  • app/src/screens/verification/ProofRequestStatusScreen.tsx
📚 Learning: 2025-08-26T14:41:41.821Z
Learnt from: shazarre
Repo: selfxyz/self PR: 936
File: app/src/screens/aesop/PassportOnboardingScreen.tsx:0-0
Timestamp: 2025-08-26T14:41:41.821Z
Learning: When verifying provider hierarchies in React Native apps, always check the main App.tsx file at the app root, not just navigation/index.tsx and layout files, as providers are often configured at the top-level App component.

Applied to files:

  • app/src/screens/app/GratificationScreen.tsx
  • app/src/screens/verification/ProofRequestStatusScreen.tsx
📚 Learning: 2025-09-22T11:10:22.019Z
Learnt from: CR
Repo: selfxyz/self PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-22T11:10:22.019Z
Learning: Applies to src/navigation/**/*.{js,ts,tsx,jsx} : Platform-specific initial routes: web uses 'Home', mobile uses 'Splash'.

Applied to files:

  • app/src/screens/app/GratificationScreen.tsx
  • app/src/components/NavBar/PointsNavBar.tsx
  • app/src/screens/verification/ProofRequestStatusScreen.tsx
📚 Learning: 2025-08-26T14:49:11.190Z
Learnt from: shazarre
Repo: selfxyz/self PR: 936
File: app/src/screens/passport/PassportNFCScanScreen.tsx:28-31
Timestamp: 2025-08-26T14:49:11.190Z
Learning: The main App.tsx file is located at app/App.tsx (not in app/src), and it properly wraps the entire app with SelfClientProvider at the top of the provider hierarchy, enabling useSelfClient() hook usage throughout all navigation screens.

Applied to files:

  • app/src/screens/app/GratificationScreen.tsx
  • app/src/screens/verification/ProveScreen.tsx
  • app/src/screens/verification/ProofRequestStatusScreen.tsx
📚 Learning: 2025-08-26T14:49:11.190Z
Learnt from: shazarre
Repo: selfxyz/self PR: 936
File: app/src/screens/passport/PassportNFCScanScreen.tsx:28-31
Timestamp: 2025-08-26T14:49:11.190Z
Learning: SelfClientProvider is wrapped in app/App.tsx, providing context for useSelfClient() hook usage throughout the React Native app navigation stacks.

Applied to files:

  • app/src/screens/app/GratificationScreen.tsx
  • app/src/screens/verification/ProveScreen.tsx
  • app/src/screens/verification/ProofRequestStatusScreen.tsx
📚 Learning: 2025-09-22T11:10:22.019Z
Learnt from: CR
Repo: selfxyz/self PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-22T11:10:22.019Z
Learning: Applies to src/screens/**/*.{js,ts,tsx,jsx} : Lazy load screens using `React.lazy()`, organize screens by feature modules.

Applied to files:

  • app/src/screens/verification/ProofRequestStatusScreen.tsx
📚 Learning: 2025-08-26T14:49:15.210Z
Learnt from: shazarre
Repo: selfxyz/self PR: 936
File: app/src/screens/passport/PassportNFCScanScreen.web.tsx:8-11
Timestamp: 2025-08-26T14:49:15.210Z
Learning: The main App.tsx file is located at app/App.tsx (at the app root), not at app/src/App.tsx, and contains the SelfClientProvider wrapping the entire application.

Applied to files:

  • app/src/screens/verification/ProofRequestStatusScreen.tsx
📚 Learning: 2025-09-11T19:41:16.601Z
Learnt from: aaronmgdr
Repo: selfxyz/self PR: 1055
File: app/src/components/homeScreen/idCard.tsx:6-6
Timestamp: 2025-09-11T19:41:16.601Z
Learning: The React Native app in selfxyz/self does not implement responsive layouts for orientation changes. The codebase consistently uses Dimensions.get('window') rather than useWindowDimensions(), indicating that orientation handling is not a priority or architectural pattern in this project.

Applied to files:

  • app/src/screens/verification/ProofRequestStatusScreen.tsx
🧬 Code graph analysis (7)
app/src/components/PointHistoryList.tsx (1)
app/src/stores/pointEventStore.ts (1)
  • usePointEventStore (53-346)
app/src/screens/verification/ProveScreen.tsx (1)
app/src/utils/points/utils.ts (1)
  • getPointsAddress (90-92)
app/src/screens/verification/ProofRequestStatusScreen.tsx (1)
app/src/navigation/index.tsx (1)
  • RootStackParamList (59-173)
app/src/utils/points/utils.ts (1)
app/src/utils/points/constants.ts (1)
  • POINTS_API_BASE_URL (5-5)
app/src/stores/pointEventStore.ts (2)
app/src/stores/proofHistoryStore.ts (1)
  • useProofHistoryStore (35-217)
app/src/utils/points/getEvents.ts (1)
  • getDisclosurePointEvents (38-82)
app/src/stores/database.ts (1)
app/src/stores/database.web.ts (1)
  • openDatabase (16-47)
app/src/utils/points/getEvents.ts (2)
app/src/utils/points/utils.ts (1)
  • getWhiteListedDisclosureAddresses (111-129)
app/src/stores/proofHistoryStore.ts (1)
  • useProofHistoryStore (35-217)
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: test-common
  • GitHub Check: type-check
  • GitHub Check: analyze-android
  • GitHub Check: analyze-ios
  • GitHub Check: build-deps
  • GitHub Check: android-build-test
  • GitHub Check: e2e-ios
🔇 Additional comments (5)
app/src/screens/verification/ProveScreen.tsx (1)

87-87: LGTM - endpoint field added to proof history.

The addition of the endpoint field to the proof history payload correctly aligns with the database schema changes.

app/src/stores/pointEventStore.ts (2)

123-123: LGTM - disclosure events loaded after regular events.

The placement of loadDisclosureEvents() after loading stored events ensures proper initialization order.


130-145: No state loss issue exists—disclosure events are always completed.

The verification reveals that getDisclosurePointEvents() always creates disclosure events with status: 'completed' (hardcoded at line 73 of app/src/utils/points/getEvents.ts). Since no non-completed disclosure event states exist in AsyncStorage, filtering out and replacing disclosure events poses no risk of losing state. The original concern is invalid.

Likely an incorrect or invalid review comment.

app/src/stores/database.ts (1)

106-194: LGTM - endpoint column migration handled correctly.

The runtime migration pattern for the endpoint column matches the existing documentId migration approach, with proper error handling and retry logic.

app/src/utils/points/utils.ts (1)

13-17: LGTM - WhitelistedContract type added.

The type definition properly captures the structure returned by the whitelist API.

Comment on lines 32 to 35
onPress={() => {
buttonTap();
props.navigation.goBack();
props.navigation.navigate('Home');
}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify navigation change doesn't break existing flows.

Changing from goBack() to navigate('Home') alters the close button behavior—users will always land on Home instead of returning to their previous screen. If the Points screen can be accessed from multiple entry points (e.g., deep links, notifications, or other screens), this could disrupt the expected navigation flow.

Run the following script to verify the Points screen's entry points and confirm the 'Home' route exists:


🏁 Script executed:

#!/bin/bash
# Description: Check Points screen navigation entry points and verify 'Home' route exists

# Find all navigations to Points screen
echo "=== Entry points to Points screen ==="
rg -n "navigate\(['\"]Points['\"]" --type ts --type tsx -A 2 -B 2

# Find navigation configuration and Home route definition
echo -e "\n=== Navigation configuration with Home route ==="
ast-grep --pattern 'createStaticNavigation($_)'

# Check if Home is defined as a screen
echo -e "\n=== Home screen definitions ==="
rg -n "name.*['\"]Home['\"]" --type ts --type tsx -C 3

Length of output: 267



---

🏁 Script executed:

```shell
#!/bin/bash
# Fix file type issues and re-verify navigation structure

# View the navigation configuration
echo "=== Navigation configuration (app/src/navigation/index.tsx) ==="
cat app/src/navigation/index.tsx | head -250

# Find all navigations to Points screen with corrected rg syntax
echo -e "\n=== Navigate to Points calls ==="
rg -n "navigate\(['\"]Points['\"]" -A 2 -B 2

# Check PointsNavBar close button behavior
echo -e "\n=== PointsNavBar close button context ==="
cat app/src/components/NavBar/PointsNavBar.tsx | head -50

Length of output: 1365



🏁 Script executed:

#!/bin/bash
# Find correct file paths and verify navigation structure

# Find PointsNavBar file
echo "=== Finding PointsNavBar.tsx ==="
fd -t f "PointsNavBar" -e tsx

# Find navigation configuration files
echo -e "\n=== Finding navigation configuration files ==="
fd -t f "navigation" -e ts -e tsx | head -20

# Find App.tsx at root
echo -e "\n=== Finding App.tsx ==="
fd -t f "App" -e tsx | grep -E "^[^/]*/App\.(tsx|ts)$"

# View PointsNavBar once located
echo -e "\n=== PointsNavBar.tsx content ==="
find . -name "PointsNavBar.tsx" -exec cat {} \;

# Search for Home route definition
echo -e "\n=== Home screen definition ==="
rg -n "Home.*screen|screen.*Home" --type ts --type jsx -i -C 2 | head -40

Length of output: 2202



🏁 Script executed:

#!/bin/bash
# Check app root navigation setup and verify Home route

# View App.tsx to understand navigation structure
echo "=== app/App.tsx ==="
cat app/App.tsx | head -100

# Find where Home screen is defined
echo -e "\n=== Search for Home screen definition ==="
rg -n "name.*Home|Home.*screen|screenOptions.*Home" -i -C 2 | head -60

# Check GratificationScreen to understand the Points navigation context
echo -e "\n=== GratificationScreen navigation context ==="
cat app/src/screens/app/GratificationScreen.tsx | head -80

Length of output: 10387



🏁 Script executed:

#!/bin/bash
# Find and examine navigation configuration

# List all files in navigation directory
echo "=== Navigation directory contents ==="
find app/src/navigation -type f | head -20

# View main navigation file
echo -e "\n=== Main navigation configuration ==="
cat app/src/navigation/index.ts 2>/dev/null || cat app/src/navigation/index.tsx 2>/dev/null || cat app/src/navigation.ts 2>/dev/null || echo "File not found in common locations"

# Search for RootStackParamList definition to understand navigation structure
echo -e "\n=== RootStackParamList definition ==="
rg -n "RootStackParamList" -C 5 | head -80

# Check if Home is a screen in the navigation
echo -e "\n=== Home in navigation configuration ==="
rg -n "name.*['\"]Home['\"]|Home.*screen" -C 2 | head -40

Length of output: 15720


Revert to goBack() or implement conditional routing to preserve navigation stack.

The change from goBack() to navigate('Home') breaks the user experience when Points screen is accessed from non-Home sources. GratificationScreen navigates to Points via handleExploreRewards (line 41) and handleBackPress (line 49), and users expect the close button to return them to Gratification, not jump to Home.

This creates a fragmented experience:

  • Entry from Earn Points → Points → Close → Home ✓
  • Entry from Gratification → Points → Close → Home ✗ (should return to Gratification)

Use goBack() to preserve the navigation stack, or implement route-aware navigation if a specific behavior is required.

🤖 Prompt for AI Agents
In app/src/components/NavBar/PointsNavBar.tsx around lines 32 to 35, the close
button uses props.navigation.navigate('Home') which breaks expected back
behavior for flows that opened Points from non-Home screens; change this to
props.navigation.goBack() to preserve the navigation stack (or implement
conditional routing: if navigation.canGoBack() then goBack() else
navigate('Home')) so the close action returns users to the originating screen
while still falling back to Home when no back entry exists.

Comment on lines +110 to +129
if (selfApp?.endpoint && whitelistedPoints === null) {
const checkWhitelist = async () => {
try {
const whitelistedContracts =
await getWhiteListedDisclosureAddresses();
const endpoint = selfApp.endpoint.toLowerCase();
const whitelistedContract = whitelistedContracts.find(
c => c.contract_address.toLowerCase() === endpoint,
);

if (whitelistedContract) {
setWhitelistedPoints(whitelistedContract.points_per_disclosure);
}
} catch (error) {
console.error('Error checking whitelist:', error);
}
};

checkWhitelist();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Race condition: whitelist check might not complete before navigation.

The whitelist check in the effect (lines 110-129) is asynchronous and may not complete before the user presses "OK". This could result in navigating to Home instead of Gratification even when the endpoint is whitelisted. Consider:

  1. Adding a loading state that disables the OK button until whitelist check completes
  2. Or moving the whitelist check earlier in the proof flow

Run this script to check if there are other whitelist check patterns in the codebase:


🏁 Script executed:

#!/bin/bash
# Search for whitelist checking patterns
rg -nP --type=ts -C5 "getWhiteListedDisclosureAddresses" -g '!node_modules'

Length of output: 4999


I'll need to examine the broader context of the screen to verify the race condition claim.


---

🏁 Script executed:

```shell
#!/bin/bash
# Get full context around the effect and navigation logic in ProofRequestStatusScreen
cat app/src/screens/verification/ProofRequestStatusScreen.tsx | head -200 | tail -130

Length of output: 3509


🏁 Script executed:

#!/bin/bash
# Search for where whitelistedPoints state is used
rg -nP --type=ts "whitelistedPoints" app/src/screens/verification/ProofRequestStatusScreen.tsx -C3

Length of output: 1269


🏁 Script executed:

#!/bin/bash
# Search for OK button handler and navigation logic
rg -nP --type=ts -A10 "OK\|handlePress\|navigate.*Home\|navigate.*Gratification" app/src/screens/verification/ProofRequestStatusScreen.tsx

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Get the full useEffect hook structure
ast-grep --pattern $'useEffect(() => {
  $$$
}, $_)'  app/src/screens/verification/ProofRequestStatusScreen.tsx

Length of output: 9820


🏁 Script executed:

#!/bin/bash
# Check getWhiteListedDisclosureAddresses implementation for error handling
sed -n '111,140p' app/src/utils/points/utils.ts

Length of output: 817


Address race condition in whitelist check by preventing premature navigation.

The async whitelist fetch (line 114) is fire-and-forget with no guarantee it completes before user presses OK. Since whitelistedPoints starts as null, pressing OK immediately after proof completion navigates to Home instead of Gratification—even if the endpoint is whitelisted.

Recommended fixes:

  1. Disable the OK button until the whitelist check completes (add loading state tied to the async operation)
  2. Or await the whitelist check before allowing user interaction on the success screen

Without one of these safeguards, the navigation destination is determined by timing, not actual whitelist status.

🤖 Prompt for AI Agents
In app/src/screens/verification/ProofRequestStatusScreen.tsx around lines
110-129, the whitelist fetch is started fire-and-forget which allows the OK
button to be pressed while whitelistedPoints is still null, producing a race and
incorrect navigation; fix by introducing a loading flag (or reuse an explicit
pending state) that is set true before calling getWhiteListedDisclosureAddresses
and false in finally, and use that flag to disable the OK button (or show a
spinner) until the check completes, or alternatively make the OK handler await
the whitelist check when pending so navigation only occurs after
whitelistedPoints is resolved; ensure error handling still sets loading false in
the catch/finally so the UI is not permanently blocked.

Comment on lines +45 to +81
if (whitelistedContracts.length === 0) {
return [];
}

const whitelistedMap = new Map(
whitelistedContracts.map(c => [
c.contract_address.toLowerCase(),
c.points_per_disclosure,
]),
);

const proofHistory = useProofHistoryStore.getState().proofHistory;
const disclosureEvents: PointEvent[] = [];

for (const proof of proofHistory) {
if (proof.status !== 'success' || !proof.endpoint) continue;

const endpoint = proof.endpoint.toLowerCase();

if (!whitelistedMap.has(endpoint)) continue;

const points = whitelistedMap.get(endpoint)!;
disclosureEvents.push({
id: proof.sessionId,
title: `${proof.appName} disclosure`,
type: 'disclosure',
timestamp: proof.timestamp,
points,
status: 'completed',
});
}

return disclosureEvents;
} catch (error) {
console.error('Error loading disclosure point events:', error);
return [];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Prevent wiping disclosure history when whitelist fetch fails

If getWhiteListedDisclosureAddresses() fails (offline/API hiccup) it resolves to an empty array, so this function returns []. usePointEventStore.loadDisclosureEvents() then replaces the store with existingNonDisclosureEvents + [], erasing every cached disclosure event we just loaded from AsyncStorage. That means a transient network error permanently hides earned disclosures from the user. Please propagate the failure (throw or return a sentinel) so the caller can skip the state update, or otherwise guard in loadDisclosureEvents() against replacing cached data when no fresh disclosure entries were produced.

@remicolin remicolin merged commit 67eb0d4 into dev Nov 12, 2025
19 of 25 checks passed
@remicolin remicolin deleted the app/use-whitelisted-addresses-for-points branch November 12, 2025 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants