Skip to content

Conversation

@ignaciosantise
Copy link
Collaborator

@ignaciosantise ignaciosantise commented Oct 9, 2025

This pull request introduces several improvements and additions to the project, focusing on workflow enhancements, code formatting consistency, and expanded testing for the Expo Multichain example app. The most significant changes include enhancements to the GitHub Actions workflows for snapshot releases, the addition of Maestro end-to-end tests and documentation for the Expo Multichain example, and minor code cleanups for better readability and maintainability.

GitHub Actions Workflow Improvements:

  • Enhanced the snapshot release workflow (.github/workflows/snapshot.yml) to support custom snapshot tags, output the published tag, and skip publishing if no changesets are found. Also, improved branch/tag handling and outputs for better CI integration. [1] [2] [3]
  • Improved the changeset workflow (.github/workflows/changesets.yml) to more reliably find and comment on pull requests associated with the current commit, with better handling for direct pushes to main.

End-to-End Testing and Example App Enhancements:

  • Added Maestro E2E test flows (.maestro/basic-smoke-test.yaml), documentation (.maestro/README.md), and updated .gitignore for the examples/expo-multichain app, enabling automated UI testing and improving local development and CI reliability. [1] [2] [3]
  • Introduced an .env.example file for the Expo Multichain example to clarify required environment variables.

Code Formatting and Minor Cleanups:

  • Updated ESLint configuration to ignore the examples/ directory, reducing unnecessary linting noise.
  • Applied consistent code formatting and minor refactors across several files in the apps/native directory for improved readability and maintainability (e.g., splitting imports, fixing trailing semicolons, and formatting JSX). [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16]

Prettier Ignore Update:

  • Minor update to .prettierignore to ensure proper formatting exclusions.

Note

Introduces a new Expo Multichain example app (Expo Router) with Maestro test flows and minor native tweaks, including conditional gas estimation in Wagmi actions.

  • Examples:
    • Expo Multichain App: Adds examples/expo-multichain with Expo Router setup, UI components, storage, theming, and multichain AppKit (Ethereum/Wagmi, Solana, Bitcoin) integration.
    • Includes app config (app.json), TypeScript config, Babel/ESLint configs, assets, and environment template (.env.example).
  • Testing:
    • Maestro E2E: Adds .maestro test flows (smoke, QR load, connect-wallet), docs, and a run-tests.sh script; updates .gitignore for artifacts.
  • Native:
    • apps/native/src/views/WagmiActionsView.tsx: Adds useAccount and enables useEstimateGas only when isConnected.
    • Minor JSX/formatting cleanups in views and tests.

Written by Cursor Bugbot for commit c9694a3. This will update automatically on new commits. Configure here.

Copilot AI review requested due to automatic review settings October 9, 2025 18:07
@changeset-bot
Copy link

changeset-bot bot commented Oct 9, 2025

⚠️ No Changeset found

Latest commit: c9694a3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@claude
Copy link

claude bot commented Oct 9, 2025

Claude finished @ignaciosantise's task —— View job


🔍 Code Review Complete

I've reviewed this PR focusing on code quality, security, and best practices. Here are my findings:


Critical Issues

1. Security: Project ID Validation Logic Differs Between Apps

Location: examples/expo-multichain/app/_layout.tsx:31-35

The new example uses 'undefined' as a string literal fallback:

const projectId = process.env.EXPO_PUBLIC_PROJECT_ID ?? 'undefined';

if (projectId === 'undefined') {
  Alert.alert('Project ID is not set');
}

However, the apps/native app uses an empty string:

const projectId = process.env.EXPO_PUBLIC_PROJECT_ID ?? '';

Issue: The expo-multichain example will pass 'undefined' as a string to createAppKit() if the check fails, which could cause runtime errors. The alert doesn't prevent execution.

Recommendation: Use consistent validation across examples and throw an error or return early instead of just showing an alert:

const projectId = process.env.EXPO_PUBLIC_PROJECT_ID;

if (!projectId || projectId === 'undefined') {
  throw new Error('EXPO_PUBLIC_PROJECT_ID must be set in .env file');
}

High Priority Issues

2. GitHub Actions: Unsafe Branch Name Transformation

Location: .github/workflows/snapshot.yml:59

snapshot=$(git branch --show-current | tr -cs '[:alnum:]-' '-' | tr '[:upper:]' '[:lower:]' | sed 's/-$//')

Issue: This transformation can create invalid npm tags or collisions:

  • Branch feature/my_branchfeature-my-branch
  • Branch feature/my-branchfeature-my-branch (collision!)
  • Branch test@123test-123

Recommendation: Add validation to ensure the snapshot tag is a valid npm tag and consider using a hash to prevent collisions:

snapshot=$(git branch --show-current | tr -cs '[:alnum:]-' '-' | tr '[:upper:]' '[:lower:]' | sed 's/-$//' | sed 's/^-//')
# Validate it's not empty
if [ -z "$snapshot" ]; then
  echo "::error::Invalid branch name for snapshot tag"
  exit 1
fi

3. GitHub Actions: Missing Error Handling in PR Comment Step

Location: .github/workflows/changesets.yml:88-97

PR_NUMBER=$(gh api repos/${{ github.repository }}/commits/${{ github.sha }}/pulls \
  --jq '.[0].number')

if [ -n "$PR_NUMBER" ] && [ "$PR_NUMBER" != "null" ]; then

Issue: If the API call fails, PR_NUMBER could contain an error message, not just be empty or "null". This could cause unexpected behavior.

Recommendation: Add explicit error handling:

PR_NUMBER=$(gh api repos/${{ github.repository }}/commits/${{ github.sha }}/pulls \
  --jq '.[0].number' 2>/dev/null || echo "")

if [ -n "$PR_NUMBER" ] && [ "$PR_NUMBER" != "null" ] && [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then

4. React Native Reanimated Dependency Violation

Location: examples/expo-multichain/package.json:57

The new example includes react-native-reanimated as a dependency, but according to the project-specific context provided, the architecture requires:

Animation Strategy: React Native's Animated API exclusively, no react-native-reanimated

Impact: This contradicts the established architecture principles and could lead to:

  • Bundle size increase
  • Inconsistent animation patterns across the codebase
  • Maintenance overhead

Recommendation: Remove react-native-reanimated unless there's a specific reason documented for this example to deviate from the standard architecture.


Medium Priority Issues

5. Maestro Test: Hardcoded Wallet ID

Location: .maestro/connect-wallet.yaml:42-46

- assertVisible:
    id: "wallet-search-item-6880782cf8ff712bf8772b585960346290fd2499c1f1c51df9fe713d9d2e9384"

Issue: This hardcoded ID appears to be a hash. If the wallet registry updates or IDs change, this test will break silently.

Recommendation:

  • Add a comment explaining what wallet this ID represents
  • Consider using more stable selectors if available
  • Document the wallet version/registry this test expects

6. Maestro Test: Flaky Double Tap

Location: .maestro/connect-wallet.yaml:45-47

- doubleTapOn:
    id: "wallet-search-item-6880782cf8ff712bf8772b585960346290fd2499c1f1c51df9fe713d9d2e9384"
    delay: 200

Issue: Using doubleTapOn with a short delay can be flaky across different devices/simulators. This is a common source of test instability.

Recommendation: Use a single tapOn if possible, or increase the delay. Document why double tap is required if it's intentional.

7. Missing .env File in .gitignore

Location: examples/expo-multichain/.gitignore:40

✅ Good: .env is properly ignored

However, the pattern .env*.local on line 33 doesn't cover the main .env file. This is correct, but worth noting that .env.example should never contain actual secrets.

Verification needed: Ensure .env.example truly contains only placeholder values (currently has '...' which is good).

8. Inconsistent Storage Implementation Pattern

Location: examples/expo-multichain/config/storage.ts

The storage implementation uses safeJsonParse/safeJsonStringify from @walletconnect/safe-json, but there's no error handling for AsyncStorage failures.

Recommendation: Add try-catch blocks for AsyncStorage operations:

getItem: async <T = any>(key: string): Promise<T | undefined> => {
  try {
    const item = await AsyncStorage.getItem(key);
    if (typeof item === 'undefined' || item === null) {
      return undefined;
    }
    return safeJsonParse(item) as T;
  } catch (error) {
    console.warn(`Failed to get item ${key}:`, error);
    return undefined;
  }
}

9. Type Safety: Unsafe Type Assertion

Location: examples/expo-multichain/app/_layout.tsx:52

const wagmiAdapter = new WagmiAdapter({
  projectId,
  networks: networks as any
});

Issue: Using as any bypasses TypeScript's type safety. This could hide type mismatches.

Recommendation: Either fix the type mismatch properly or add a comment explaining why the type assertion is necessary.


Low Priority / Suggestions

10. ESLint Configuration: Overly Broad Ignore Pattern

Location: .eslintrc.json:12

"ignorePatterns": [
  "examples/"
]

Issue: Ignoring the entire examples/ directory means example code won't benefit from linting. Example code quality matters for developers learning from examples.

Recommendation: Consider linting example apps but with a separate, more relaxed config. Examples should demonstrate best practices.

11. Maestro README: Inconsistent Test File Reference

Location: .maestro/README.md:8

- `connect-wallet-detailed.yaml` - Detailed wallet connection flow test

But the actual file is named connect-wallet.yaml (without "detailed").

Fix: Update the README to match the actual filename.

12. Missing Test Script in Example Package.json

The example has "maestro:test": ".maestro/run-tests.sh" but the script needs executable permissions. Consider documenting this or using bash explicitly:

"maestro:test": "bash .maestro/run-tests.sh"

13. Code Formatting: Unnecessary Changes

Many of the formatting changes in apps/native/ files appear to be auto-formatter fixes (adding/removing semicolons, splitting imports). These are fine but inflate the PR size.

Suggestion: Consider running formatters separately from feature work in future PRs to keep diffs focused.


Positive Observations

Good: Comprehensive Maestro test setup with screenshots and video recording
Good: Proper .gitignore for Maestro artifacts
Good: Environment variable example file provided
Good: Workflow improvements for snapshot tags and changeset detection
Good: Storage implementation follows project patterns
Good: README documentation for Maestro tests is thorough


Summary

Critical: 1 issue (project ID validation)
High Priority: 4 issues (workflow safety, dependency violation)
Medium Priority: 5 issues (test stability, error handling)
Low Priority: 4 suggestions (documentation, configuration)

The PR introduces valuable E2E testing infrastructure and a new example app, but needs attention to security validation logic and workflow safety before merging. The react-native-reanimated dependency should be reviewed against project architecture guidelines.


Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request introduces a comprehensive new Expo Multichain example application along with improvements to GitHub Actions workflows and code formatting enhancements. The PR focuses on expanding the project's testing capabilities, workflow automation, and maintaining code quality through consistent formatting.

  • Introduces a complete Expo Multichain example app with Maestro E2E testing infrastructure
  • Enhances GitHub Actions workflows for better snapshot release management and changeset handling
  • Applies consistent code formatting and style improvements across the native app codebase

Reviewed Changes

Copilot reviewed 51 out of 64 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
examples/expo-multichain/* New complete Expo multichain example app with UI components, configuration, and app structure
.maestro/* Maestro E2E test flows and documentation for automated UI testing
.github/workflows/* Enhanced snapshot release workflow with custom tags and improved changeset PR detection
apps/native/src/views/* Code formatting improvements and JSX restructuring for better readability
.eslintrc.json Updated to ignore examples directory from linting
Comments suppressed due to low confidence (1)

examples/expo-multichain/run-tests.sh:1

  • The script references 'maestro-qr-load.yaml' but the actual file is named 'wallet-qr-load.yaml'. This will cause the test to fail.
#!/bin/bash

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@socket-security
Copy link

socket-security bot commented Oct 9, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​storybook/​theming@​8.6.141001005193100
Added@​babel/​plugin-transform-react-jsx-development@​7.27.11001006089100
Added@​babel/​plugin-transform-dotall-regex@​7.27.11001006389100
Added@​babel/​plugin-transform-regexp-modifiers@​7.27.11001006389100
Added@​babel/​plugin-syntax-unicode-sets-regex@​7.18.61001006482100
Added@​storybook/​react-webpack5@​8.6.1410010064100100
Added@​babel/​plugin-transform-unicode-sets-regex@​7.27.11001006589100
Added@​babel/​plugin-transform-reserved-words@​7.27.11001006589100
Added@​babel/​plugin-transform-duplicate-named-capturing-groups-regex@​7.27.11001006689100
Added@​babel/​plugin-transform-unicode-property-regex@​7.27.11001006689100
Added@​babel/​plugin-transform-property-literals@​7.27.11001006689100
Added@​babel/​plugin-transform-member-expression-literals@​7.27.11001006689100
Added@​babel/​plugin-syntax-import-assertions@​7.27.11001006689100
Added@​storybook/​addon-webpack5-compiler-babel@​3.0.61001006789100
Added@​babel/​plugin-transform-json-strings@​7.27.11001006789100
Added@​tanstack/​query-async-storage-persister@​5.40.01001006796100
Added@​types/​gh-pages@​6.1.0941006876100
Added@​babel/​plugin-transform-dynamic-import@​7.27.11001006889100
Added@​tanstack/​react-query-persist-client@​5.56.21001006897100
Added@​babel/​plugin-proposal-private-property-in-object@​7.21.0-placeholder-for-preset-env.21001006882100
Added@​babel/​plugin-bugfix-safari-id-destructuring-collision-in-function-expression@​7.27.11001006989100
Added@​babel/​plugin-transform-block-scoped-functions@​7.27.11001006989100
Added@​babel/​plugin-transform-react-pure-annotations@​7.27.11001006989100
Added@​babel/​plugin-transform-export-namespace-from@​7.27.11001006989100
Added@​babel/​plugin-transform-duplicate-keys@​7.27.11001007189100
Added@​babel/​plugin-transform-typeof-symbol@​7.27.11001007190100
Added@​babel/​plugin-bugfix-v8-spread-parameters-in-optional-chaining@​7.27.11001007189100
Added@​babel/​plugin-transform-class-static-block@​7.27.11001007191100
Added@​babel/​plugin-transform-object-super@​7.27.11001007189100
Added@​ark/​util@​0.46.01001007192100
Added@​babel/​plugin-bugfix-safari-class-field-initializer-scope@​7.27.11001007189100
Added@​babel/​plugin-transform-new-target@​7.27.11001007189100
See 55 more rows in the dashboard

View full report

@sonarqubecloud
Copy link

@ignaciosantise
Copy link
Collaborator Author

@claude review

@claude
Copy link

claude bot commented Oct 15, 2025

Claude finished @ignaciosantise's task —— View job


🔄 Incremental Code Review Complete

I've analyzed the latest code against the previous review from October 9th. Here are my findings on issue status and new concerns:


✅ Issues Resolved Since Last Review

1. Project ID Validation - RESOLVED

Previous Location: examples/expo-multichain/app/_layout.tsx:31-35

The critical security issue has been fixed. The code now properly validates the project ID:

const projectId = process.env.EXPO_PUBLIC_PROJECT_ID ?? '';

if (projectId === '') {
  Alert.alert('Project ID is not set');
}

The previous issue where it would pass 'undefined' as a string has been resolved. The code now uses an empty string fallback and properly checks for it.

2. Workflow Branch Transformation - IMPROVED

Location: .github/workflows/snapshot.yml:59-66

The unsafe branch name transformation has been improved with validation:

snapshot=$(git branch --show-current | tr -cs '[:alnum:]-' '-' | tr '[:upper:]' '[:lower:]' | sed 's/-$//' | sed 's/^-//')
# Validate it's not empty
if [ -z "$snapshot" ]; then
  echo "::error::Invalid branch name for snapshot tag"
  exit 1
fi

This addresses the previous concern about invalid npm tags.

3. Changeset Workflow Error Handling - IMPROVED

Location: .github/workflows/changesets.yml:88-97

Better error handling has been added:

PR_NUMBER=$(gh api repos/${{ github.repository }}/commits/${{ github.sha }}/pulls \
  --jq '.[0].number' 2>/dev/null || echo "")

if [ -n "$PR_NUMBER" ] && [ "$PR_NUMBER" != "null" ]; then

The 2>/dev/null || echo "" pattern now properly handles API failures.


⚠️ Issues Still Present

4. React Native Reanimated Architecture Violation - CONFIRMED STILL PRESENT

Location: examples/expo-multichain/package.json:57

"react-native-reanimated": "~4.1.1",

Used in: examples/expo-multichain/components/MobileWave.tsx:3-9, components/ParallaxScrollView.tsx

Issue: The project architecture explicitly states:

Animation Strategy: React Native's Animated API exclusively, no react-native-reanimated

This example app violates the established architecture by using react-native-reanimated for decorative animations (wave effect, parallax scrolling). While these are Expo template components, they should be refactored to use React Native's Animated API for consistency.

Impact:

  • Inconsistent animation patterns across the codebase
  • Increased bundle size (~300KB for reanimated)
  • Maintenance overhead and confusion for developers

Recommendation: Refactor MobileWave.tsx and ParallaxScrollView.tsx to use React Native's Animated API, or remove these decorative components if they're not essential to the example.

5. Maestro Test Hardcoded Wallet ID - CONFIRMED STILL PRESENT

Location: .maestro/connect-wallet.yaml:42-46

- assertVisible:
    id: "wallet-search-item-6880782cf8ff712bf8772b585960346290fd2499c1f1c51df9fe713d9d2e9384"
- doubleTapOn:
    id: "wallet-search-item-6880782cf8ff712bf8772b585960346290fd2499c1f1c51df9fe713d9d2e9384"
    delay: 500

Issue: This hardcoded wallet ID (appears to be a hash) will break if the wallet registry changes. No documentation explains what wallet this represents.

Recommendation: Add a comment explaining this is the "React Native Wallet Example" ID and document the expected wallet version.

6. Maestro Test Flaky Double Tap - CONFIRMED STILL PRESENT

Location: .maestro/connect-wallet.yaml:45-47

- doubleTapOn:
    id: "wallet-search-item-6880782cf8ff712bf8772b585960346290fd2499c1f1c51df9fe713d9d2e9384"
    delay: 500

Issue: Using doubleTapOn with a 500ms delay can be flaky across different devices. The delay was increased from 200ms (mentioned in previous review) but double-tap is inherently unreliable for E2E tests.

Recommendation: Use single tapOn if possible, or document why double-tap is specifically required for this interaction.


🆕 New Issues Found

7. Missing Error Handling in Storage Implementation

Location: examples/expo-multichain/config/storage.ts:6-30

The storage implementation lacks try-catch blocks for AsyncStorage operations:

getItem: async <T = any>(key: string): Promise<T | undefined> => {
  const item = await AsyncStorage.getItem(key);
  if (typeof item === 'undefined' || item === null) {
    return undefined;
  }
  return safeJsonParse(item) as T;
}

Issue: AsyncStorage operations can fail (permissions, quota, corruption), but there's no error handling. This could crash the app during storage operations.

Recommendation: Add try-catch blocks:

getItem: async <T = any>(key: string): Promise<T | undefined> => {
  try {
    const item = await AsyncStorage.getItem(key);
    if (typeof item === 'undefined' || item === null) {
      return undefined;
    }
    return safeJsonParse(item) as T;
  } catch (error) {
    console.warn(`Failed to get item ${key}:`, error);
    return undefined;
  }
}

8. ESLint Configuration May Hide Issues in Examples

Location: .eslintrc.json:12

"ignorePatterns": [
  "examples/"
]

Issue: Completely ignoring the examples/ directory means example code won't benefit from linting. Since examples are often copied by developers, they should demonstrate best practices.

Recommendation: Consider linting examples with a separate, more relaxed config, or at minimum don't ignore them entirely. Example code quality matters for developer education.

9. Inconsistent Project ID Validation Between Apps

Comparison: apps/native/App.tsx:38 vs examples/expo-multichain/app/_layout.tsx:31-35

apps/native approach:

const projectId = process.env.EXPO_PUBLIC_PROJECT_ID ?? '';
// No validation, just uses empty string

expo-multichain approach:

const projectId = process.env.EXPO_PUBLIC_PROJECT_ID ?? '';

if (projectId === '') {
  Alert.alert('Project ID is not set');
}

Issue: The validation approaches differ. The apps/native app doesn't validate at all, while the new example shows an alert but continues execution. Both will fail at runtime when trying to use AppKit with an invalid project ID.

Recommendation: Establish a consistent validation pattern. Either:

  1. Both apps should throw/error early if projectId is missing
  2. Both apps should handle it gracefully with user feedback
  3. Document why they differ (e.g., native is for internal testing, expo-multichain is for public examples)

10. WagmiActionsView Improvement in Native App

Location: apps/native/src/views/WagmiActionsView.tsx:39-42

const { data: gas, isError: isGasError } = useEstimateGas({
  ...TX,
  query: { enabled: isConnected }
});

Good: The addition of query: { enabled: isConnected } properly prevents gas estimation when not connected. This is a positive change that avoids unnecessary errors.


📊 Summary

Previously Identified Issues:

  • ✅ 3 resolved (project ID validation, workflow validation, error handling)
  • ⚠️ 3 still present (reanimated dependency, maestro test issues)

New Issues: 4 identified (storage error handling, ESLint config, inconsistent validation, but also 1 positive improvement noted)

Priority Breakdown:

  • High: 1 (reanimated architecture violation)
  • Medium: 3 (storage error handling, inconsistent validation, ESLint config)
  • Low: 2 (maestro test hardcoded ID, double-tap flakiness)

Recommendation: The PR shows good progress on addressing security and workflow concerns. The main remaining issue is the architectural violation with react-native-reanimated. Consider either:

  1. Refactoring decorative components to use React Native Animated API
  2. Removing non-essential decorative components
  3. Documenting an exception for example apps (not recommended as it sets a precedent)

@ignaciosantise ignaciosantise merged commit dc60610 into develop Oct 15, 2025
11 of 12 checks passed
@ignaciosantise ignaciosantise deleted the chore/examples branch October 15, 2025 14:22
@github-actions github-actions bot locked and limited conversation to collaborators Oct 15, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants