-
Notifications
You must be signed in to change notification settings - Fork 11
add v1 of freighter mobile best practices skill #810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
leofelix077
wants to merge
4
commits into
main
Choose a base branch
from
lf-add-freighter-mobile-best-practices-skill
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
1ca3f2d
add v1 of freighter mobile best practices skill
leofelix077 808fe43
adjust styling and comments from copilot reviee
leofelix077 8914c2a
Adjust code review and update agentic files best practices
leofelix077 bab7ce4
Unify duplicate agent instruction files
leofelix077 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../../docs/skills/freighter-mobile-best-practices |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| # Freighter Mobile | ||
|
|
||
| > Non-custodial Stellar wallet for iOS and Android. React Native app with | ||
| > Zustand state management (ducks pattern). | ||
|
|
||
| ## Glossary | ||
|
|
||
| Domain terms you will encounter throughout this codebase: | ||
|
|
||
| | Term | Meaning | | ||
| | ----------------- | ---------------------------------------------------------------------------------------- | | ||
| | **Duck** | A Zustand store module in `src/ducks/` managing a single domain of state | | ||
| | **XDR** | Stellar binary serialization format used for transactions and ledger entries | | ||
| | **WalletConnect** | Web3 protocol (v2) for dApp-to-wallet connections via `@reown/walletkit` | | ||
| | **RPC method** | WalletConnect v2 handler (`stellar_signXDR`, `stellar_signAndSubmitXDR`, etc.) | | ||
| | **Metro** | React Native JavaScript bundler (replaces webpack); cache issues are common | | ||
| | **Bundle ID** | App identifier — `org.stellar.freighterdev` (dev) / `org.stellar.freighterwallet` (prod) | | ||
| | **Fastlane** | Ruby automation for iOS/Android builds and App Store/Play Store submissions | | ||
| | **Maestro** | YAML-based mobile e2e test runner; flows live in `e2e/flows/` | | ||
| | **NativeWind** | Tailwind CSS utility classes adapted for React Native (v4) | | ||
| | **rn-nodeify** | Polyfills Node.js APIs (crypto, stream, buffer) required by the Stellar SDK | | ||
| | **jail-monkey** | Jailbreak/root detection library — never bypass in production code | | ||
|
|
||
| ## Documentation | ||
|
|
||
| - [Auth Flow Architecture](./docs/auth_flow_diagram.md) | ||
| - [WalletConnect RPC Methods](./docs/walletconnect-rpc-methods.md) | ||
| - [Release Process](./RELEASE.md) | ||
| - [E2E Testing Guide](./e2e/README.md) | ||
| - [E2E CI & Triggers](./e2e/docs/ci-and-triggers.md) | ||
| - [E2E Local Setup](./e2e/docs/local-setup-and-env.md) | ||
| - [E2E Running Tests](./e2e/docs/running-tests.md) | ||
| - [E2E Debugging](./e2e/docs/artifacts-and-debugging.md) | ||
| - [E2E Creating Tests](./e2e/docs/creating-tests.md) | ||
| - [WalletConnect E2E](./e2e/docs/walletconnect-e2e-testing.md) | ||
| - [Mock dApp for Testing](./mock-dapp/README.md) | ||
| - [Getting Started](./README.md) | ||
| - [Contributing](./CONTRIBUTING.md) | ||
|
|
||
| ## Quick Reference | ||
|
|
||
| | Item | Value | | ||
| | ---------------- | -------------------------------------------------------- | | ||
| | Language | TypeScript, React Native 0.81 | | ||
| | Node | >= 20 (CI: Node 20; locally 22 also works) | | ||
| | Package Manager | Yarn 4.10.0 (Corepack) | | ||
| | State Management | Zustand 5 (ducks pattern) | | ||
| | Navigation | React Navigation 7 (nested stack/tab) | | ||
| | Styling | NativeWind 4 (Tailwind) + Styled Components 6 | | ||
| | Testing | Jest 30 (unit), Maestro (e2e) | | ||
| | Linting | ESLint Airbnb + TS strict + Prettier | | ||
| | iOS Build | Xcode + Fastlane + CocoaPods | | ||
| | Android Build | Gradle + Fastlane (SDK 36, min SDK 24, NDK 28.2, JDK 17) | | ||
| | Default Branch | `main` | | ||
|
|
||
| ## Build & Test Commands | ||
|
|
||
| ```bash | ||
| yarn install # Install deps (runs Husky, polyfills, pods) | ||
| bundle install # Ruby deps (Fastlane, CocoaPods) | ||
| yarn ios # Run on iOS simulator | ||
| yarn android # Run on Android emulator | ||
| yarn start # Metro bundler only | ||
| yarn start-c # Metro with cache reset | ||
| yarn test # Jest unit tests | ||
| yarn check # lint:ts + lint:check + format:check | ||
| yarn fix # Auto-fix lint + format | ||
| yarn lint:translations # Check for missing i18n keys | ||
| yarn test:e2e:ios <flow> # Maestro e2e (iOS) | ||
| yarn test:e2e:android <flow> # Maestro e2e (Android) | ||
| ``` | ||
|
|
||
| ### Cleaning Builds (escalation order) | ||
|
|
||
| ```bash | ||
| yarn start-c # Clear Metro cache (try first) | ||
| yarn pod-install # Reinstall CocoaPods | ||
| yarn node-c-install # Remove node_modules + reinstall | ||
| yarn c-install # Full clean (Gradle + node_modules + reinstall) | ||
| yarn r-install # Nuclear: reset env + rebuild everything | ||
| ``` | ||
|
|
||
| ## Repository Structure | ||
|
|
||
| ``` | ||
| freighter-mobile/ | ||
| ├── src/ | ||
| │ ├── components/ # RN components (screens, templates, primitives, SDS) | ||
| │ ├── ducks/ # Zustand stores (one per domain) | ||
| │ ├── hooks/ # Custom React hooks | ||
| │ ├── helpers/ # Utility functions | ||
| │ ├── services/ # Business logic (analytics, blockaid, storage, backend) | ||
| │ ├── navigators/ # React Navigation (Root, Auth, Tab, + 6 feature navigators) | ||
| │ ├── providers/ # Context providers (AuthCheck, Network, Toast, WalletKit) | ||
| │ ├── config/ # App config (envConfig, constants, theme, routes) | ||
| │ ├── i18n/ # Translations (i18next) | ||
| │ └── polyfills/ # Node.js API polyfills for Stellar SDK | ||
| ├── __tests__/ # Jest unit tests (mirrors src/) | ||
| ├── __mocks__/ # Jest mocks for native modules | ||
| ├── e2e/flows/ # Maestro e2e test flows | ||
| ├── mock-dapp/ # WalletConnect mock dApp for local testing | ||
| ├── ios/ # Native iOS project | ||
| ├── android/ # Native Android project | ||
| ├── fastlane/ # Release automation | ||
| └── .github/workflows/ # CI: test, ios, android, ios-e2e, android-e2e, new-release | ||
| ``` | ||
|
|
||
| ## Architecture | ||
|
|
||
| State lives in isolated Zustand ducks (`src/ducks/`). Key stores: `auth`, | ||
| `balances`, `transactionBuilder`, `swap`, `walletKit`, `preferences`, | ||
| `networkInfo`, `history`. Access via hooks (`useAuthStore`, etc.). | ||
|
|
||
| Navigation uses nested React Navigation 7 navigators. Entry point: | ||
| `RootNavigator` → `AuthNavigator` or `TabNavigator` → feature navigators. Deep | ||
| links: `freighterdev://` (dev) / `freighterwallet://` (prod). | ||
|
|
||
| dApp connectivity via WalletConnect v2 (`src/providers/WalletKitProvider.tsx`). | ||
| 4 RPC methods: `stellar_signXDR`, `stellar_signAndSubmitXDR`, | ||
| `stellar_signMessage`, `stellar_signAuthEntry`. | ||
|
|
||
| ## Security-Sensitive Areas | ||
|
|
||
| Do not modify these without fully understanding the security implications: | ||
|
|
||
| - `src/ducks/auth.ts` — authentication state, key management | ||
| - `src/services/storage/` — secure storage (iOS Keychain / Android Keystore) | ||
| - `src/helpers/` related to signing, encryption, or key derivation | ||
| - `src/navigators/` — deep link handling (injection vector) | ||
| - `src/providers/WalletKitProvider.tsx` — WalletConnect session management | ||
| - `jail-monkey` detection — never bypass in non-test code | ||
| - `SecureClipboardService` — use this for all sensitive clipboard operations | ||
|
|
||
| ## Known Complexity / Gotchas | ||
|
|
||
| - **Auth flow** is a complex state machine (sign-up, sign-in, import, lock, | ||
| biometrics). Read `docs/auth_flow_diagram.md` before touching | ||
| `src/ducks/auth.ts`. | ||
| - **Dual bundle IDs** mean separate signing configs, push tokens, and deep link | ||
| schemes. Don't mix dev/prod identifiers. | ||
| - **Version bumps** require touching 5 files simultaneously. Use | ||
| `yarn set-app-version` — do not edit them manually. | ||
| - **Metro cache** is the first culprit for unexplained build failures; run | ||
| `yarn start-c` before investigating further. | ||
| - **Polyfills** (`rn-nodeify`) must stay in sync with the Stellar SDK version — | ||
| don't remove or update without testing cryptographic operations. | ||
| - **Blockaid** transaction scanning is integrated into sign flows. Don't bypass | ||
| or weaken — it's a security control. | ||
| - **Pre-commit hooks** run the full test suite + TypeScript check. This is | ||
| intentional and slow on large changesets. | ||
|
|
||
| ## Pre-submission Checklist | ||
|
|
||
| ```bash | ||
| yarn check # Lint + format must pass | ||
| yarn test # Unit tests must pass | ||
| # Then test manually on both iOS and Android simulators | ||
| ``` | ||
|
|
||
| ## Best Practices Entry Points | ||
|
|
||
| Read the relevant file when working in that area: | ||
|
|
||
| | Concern | Entry Point | When to Read | | ||
| | -------------------- | -------------------------------------------------------------------------- | --------------------------------------------------- | | ||
| | Code Style | `docs/skills/freighter-mobile-best-practices/references/code-style.md` | Writing or reviewing any code | | ||
| | Architecture | `docs/skills/freighter-mobile-best-practices/references/architecture.md` | Adding features, understanding state/nav structure | | ||
| | Styling | `docs/skills/freighter-mobile-best-practices/references/styling.md` | Creating or modifying UI components | | ||
| | Security | `docs/skills/freighter-mobile-best-practices/references/security.md` | Touching keys, auth, storage, or dApp interactions | | ||
| | Testing | `docs/skills/freighter-mobile-best-practices/references/testing.md` | Writing or fixing tests | | ||
| | Performance | `docs/skills/freighter-mobile-best-practices/references/performance.md` | Optimizing renders, lists, images, or startup | | ||
| | Error Handling | `docs/skills/freighter-mobile-best-practices/references/error-handling.md` | Adding error states, retries, or user-facing errors | | ||
| | Internationalization | `docs/skills/freighter-mobile-best-practices/references/i18n.md` | Adding or modifying user-facing strings | | ||
| | WalletConnect | `docs/skills/freighter-mobile-best-practices/references/walletconnect.md` | Working with dApp connections or RPC methods | | ||
| | Navigation | `docs/skills/freighter-mobile-best-practices/references/navigation.md` | Adding screens, deep links, or navigation flows | | ||
| | Git & PR Workflow | `docs/skills/freighter-mobile-best-practices/references/git-workflow.md` | Branching, committing, opening PRs, CI, releases | | ||
| | Dependencies | `docs/skills/freighter-mobile-best-practices/references/dependencies.md` | Adding, updating, or auditing packages | | ||
| | Anti-Patterns | `docs/skills/freighter-mobile-best-practices/references/anti-patterns.md` | Code review, avoiding common mistakes | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| --- | ||
| name: freighter-mobile-best-practices | ||
| description: | ||
| Comprehensive best practices for the Freighter Mobile React Native app (iOS + | ||
| Android). Covers code style, architecture, security, testing, performance, | ||
| error handling, i18n, styling, WalletConnect, navigation, git workflow, | ||
| dependencies, and anti-patterns. Use when writing new screens, creating | ||
| Zustand stores, adding hooks, working with WalletConnect, handling secure key | ||
| storage, writing navigation flows, building transactions, styling components, | ||
| reviewing mobile PRs, or any development work in the freighter-mobile repo. | ||
| Triggers on any task touching the freighter-mobile codebase. | ||
| --- | ||
|
|
||
| # Freighter Mobile Best Practices | ||
|
|
||
| Freighter Mobile is a non-custodial Stellar wallet built with React Native, | ||
| targeting both iOS and Android. The app uses Zustand for state management, React | ||
| Navigation for routing, NativeWind for styling, and Maestro for end-to-end | ||
| testing. | ||
|
|
||
| ## Reference Index | ||
|
|
||
| | Concern | File | When to Read | | ||
| | -------------------- | ---------------------------- | --------------------------------------------------- | | ||
| | Code Style | references/code-style.md | Writing or reviewing any code | | ||
| | Architecture | references/architecture.md | Adding features, understanding the codebase | | ||
| | Styling | references/styling.md | Creating or modifying UI components | | ||
| | Security | references/security.md | Touching keys, auth, storage, or dApp interactions | | ||
| | Testing | references/testing.md | Writing or fixing tests | | ||
| | Performance | references/performance.md | Optimizing renders, lists, images, or startup | | ||
| | Error Handling | references/error-handling.md | Adding error states, retries, or user-facing errors | | ||
| | Internationalization | references/i18n.md | Adding or modifying user-facing strings | | ||
| | WalletConnect | references/walletconnect.md | Working with dApp connections or RPC methods | | ||
| | Navigation | references/navigation.md | Adding screens, deep links, or navigation flows | | ||
| | Git & PR Workflow | references/git-workflow.md | Branching, committing, opening PRs, CI, releases | | ||
| | Dependencies | references/dependencies.md | Adding, updating, or auditing packages | | ||
| | Anti-Patterns | references/anti-patterns.md | Code review, avoiding common mistakes | | ||
155 changes: 155 additions & 0 deletions
155
docs/skills/freighter-mobile-best-practices/references/anti-patterns.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| # Anti-Patterns | ||
|
|
||
| This document lists common mistakes to avoid in the Freighter Mobile codebase. | ||
|
|
||
| ## Relative Imports | ||
|
|
||
| ESLint enforces absolute imports from the `src/` root. Relative imports will | ||
| fail lint. | ||
|
|
||
| ```tsx | ||
| // Wrong - will fail lint | ||
| import { useAuth } from "../../hooks/useAuth"; | ||
|
|
||
| // Correct | ||
| import { useAuth } from "hooks/useAuth"; | ||
| ``` | ||
|
|
||
| ## Function Declarations for Components | ||
|
|
||
| All components must use arrow function expressions. Function declarations will | ||
| fail lint (`react/function-component-definition`). | ||
|
|
||
| ```tsx | ||
| // Wrong - will fail lint | ||
| export function MyComponent({ title }: Props) { | ||
| return <Text>{title}</Text>; | ||
| } | ||
|
|
||
| // Correct | ||
| export const MyComponent: React.FC<Props> = ({ title }) => { | ||
| return <Text>{title}</Text>; | ||
| }; | ||
| ``` | ||
|
|
||
| ## Class Components | ||
|
|
||
| Class components are not used anywhere in the codebase. Always use functional | ||
| components with hooks. | ||
|
|
||
| ## Magic Strings in Navigation | ||
|
|
||
| Never use raw strings for route names. Always use route enum constants. | ||
|
|
||
| ```tsx | ||
| // Wrong | ||
| navigation.navigate("EnterAmount"); | ||
|
|
||
| // Correct | ||
| navigation.navigate(SEND_PAYMENT_ROUTES.ENTER_AMOUNT); | ||
| ``` | ||
|
|
||
| ## AsyncStorage for Sensitive Data | ||
|
|
||
| Never store keys, seeds, or passwords in AsyncStorage. Use the appropriate tier | ||
| from `storageFactory`: | ||
|
|
||
| - `secureDataStorage` for keys and seeds | ||
| - `biometricDataStorage` for biometric-gated passwords | ||
|
|
||
| ## Untyped navigation.navigate() | ||
|
|
||
| Always type navigation params via the param list types. Untyped navigate calls | ||
| bypass TypeScript safety and can cause runtime crashes. | ||
|
|
||
| ## Missing JSDoc | ||
|
|
||
| The PR template requires JSDoc on new functions and updated JSDoc on modified | ||
| functions. While the codebase currently has few JSDoc comments, all new code | ||
| should include them. Help improve this incrementally. | ||
|
|
||
| ## Floating Promises | ||
|
|
||
| Even though `@typescript-eslint/no-floating-promises` is not currently enforced | ||
| in ESLint, avoid floating promises as a best practice. Every promise should be | ||
| `await`ed or have a `.catch()` handler. | ||
|
|
||
| ```tsx | ||
| // Wrong - unhandled promise | ||
| fetchBalances(publicKey); | ||
|
|
||
| // Correct | ||
| await fetchBalances(publicKey); | ||
|
|
||
| // Also correct | ||
| fetchBalances(publicKey).catch((error) => { | ||
| Sentry.captureException(normalizeError(error)); | ||
| }); | ||
| ``` | ||
|
|
||
| ## Trusting dApp Metadata | ||
|
|
||
| WalletConnect session info (app name, icon, URL) comes from the dApp itself and | ||
| can be spoofed. Never use this metadata for security decisions. Always validate | ||
| the transaction content independently. | ||
|
|
||
| ## Logging Key Material | ||
|
|
||
| Never `console.log` keys, seeds, or passwords, even in `__DEV__` mode. Logs can | ||
| be captured by crash reporting tools or device log viewers. | ||
|
|
||
| ## Skipping Network Validation | ||
|
|
||
| Always verify the WalletConnect request chain matches the active Stellar | ||
| network. A dApp could request signing on `stellar:pubnet` while the user expects | ||
| `stellar:testnet`. | ||
|
|
||
| ## Direct Store Mutations | ||
|
|
||
| Zustand's `set()` creates new state objects. Never mutate existing state | ||
| directly. | ||
|
|
||
| ```tsx | ||
| // Wrong - mutating existing state | ||
| get().balances.push(newBalance); | ||
|
|
||
| // Correct - creating new state | ||
| set({ balances: [...get().balances, newBalance] }); | ||
| ``` | ||
|
|
||
| ## Cross-Store Action Chains | ||
|
|
||
| Do not have store A's action call store B's action which calls store C's action. | ||
| This creates hard-to-debug cascading updates. Keep actions independent and | ||
| compose at the hook or component level instead. | ||
|
|
||
| ## Empty Catch Blocks | ||
|
|
||
| Always handle or log errors. At minimum, use `normalizeError()` + Sentry. | ||
|
|
||
| ```tsx | ||
| // Wrong | ||
| try { | ||
| await riskyOp(); | ||
| } catch {} | ||
|
|
||
| // Correct | ||
| try { | ||
| await riskyOp(); | ||
| } catch (error) { | ||
| Sentry.captureException(normalizeError(error)); | ||
| } | ||
| ``` | ||
|
|
||
| ## Hardcoding Test Data | ||
|
|
||
| Use environment variables for test secrets. Never hardcode recovery phrases, | ||
| private keys, or test passwords in source code. | ||
|
|
||
| ```tsx | ||
| // Wrong | ||
| const testPhrase = "abandon abandon abandon ..."; | ||
|
|
||
| // Correct | ||
| const testPhrase = process.env.E2E_TEST_RECOVERY_PHRASE; | ||
| ``` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The markdown table syntax here uses a leading
||which GitHub renders as an extra empty column. Replace|| ... | ... |rows with standard| ... | ... |table rows so the Reference Index renders correctly.