π€ Download Android APK/AAB Β Β·Β π Web Dashboard Β Β·Β π Docs Β Β·Β π Report Bug Β Β·Β β¨ Request Feature
π Preview Build (ANDROID ONLY): Download Android App (AAB) Note: This build artifact is valid for 29 days from compilation. iOS preview builds are currently unsupported as they require a paid Apple Developer account.
Rayos is a seedless, self-custodial smart wallet on the Stellar network. There are no seed phrases β your keys live in your device's Secure Enclave (iOS) or StrongBox (Android), protected by Face ID, Touch ID, or biometrics. The on-chain wallet is a Soroban smart contract that verifies WebAuthn signatures directly, meaning you get the security of passkeys with the programmability of smart contracts.
This repository is the native mobile app β the most polished way to experience the passkey UX. It is feature-equivalent to the web-dashboard but passkeys on a real phone, unlocked by your face, are where the "no seed phrase" pitch really lands.
This app is one piece of a larger open-source system. Here's how the repos connect:
| Repo | Role | How mobile uses it |
|---|---|---|
mobile-app β you are here |
Native iOS & Android app | β |
wallet-sdk |
Shared TypeScript SDK | Vendored tarball in vendor/ (pnpm sdk:vendor to refresh) β WalletSdk class, PasskeyProvider interface, all types |
relay-backend |
NestJS gasless relay API | All HTTP calls: WebAuthn, relay, sessions, recovery, .well-known files |
wallet-contracts |
Soroban smart contracts (Rust) | Indirect β JS bindings consumed through wallet-sdk |
web-dashboard |
Next.js web app | Design token parity; same conceptual API contract |
infra |
GitHub Actions, Docker, env specs | EAS build workflow reused; env variable naming convention |
| Feature | Details |
|---|---|
| π Passkey Wallet Creation | Register with Face ID / Touch ID β no seed phrase, no password. Deploys a Soroban smart contract on Stellar automatically. |
| π Native Biometric Signing | Every transaction is approved by your biometric. The passkey never leaves the device Secure Enclave. |
| πΈ Send & Receive XLM | Send Stellar assets with a biometric confirmation. Transaction history pulled live from Horizon. |
| π‘οΈ Spend Limits | Set rolling per-token spend limits enforced on-chain by the Policy contract. |
| π Session Keys | Create scoped, time-limited session keys for specific dapps or automations. |
| π₯ Social Recovery | Add guardian addresses. If you lose your device, 2-of-N guardians can approve a new passkey β with a 48-hour timelock. |
| π² Deep Link Recovery Approval | Guardians receive an email link; tapping it on mobile opens the app directly on the approval screen. |
| π System / Light / Dark Theme | Follows OS by default; user can override in Settings. Choice is persisted securely. |
| π‘ Offline-first | TanStack Query with networkMode: offlineFirst β pending state is clear, retries happen automatically. |
mobile-app/
β
βββ app/ β expo-router file-based routes
β βββ _layout.tsx β Root: QueryClient, deep-link handler, auth gate
β βββ +not-found.tsx
β βββ (onboarding)/ β Unauthenticated group (Stack)
β β βββ index.tsx β Welcome / landing screen
β β βββ create.tsx β Passkey registration β wallet deployment
β β βββ login.tsx β Passkey assertion β wallet lookup
β β βββ recover.tsx β Initiate guardian recovery
β βββ (dashboard)/ β Authenticated group (Tabs)
β β βββ wallet.tsx β Balance Β· send Β· receive Β· activity
β β βββ policies.tsx β Spend limit Β· session keys Β· allow-list
β β βββ guardians.tsx β Guardians Β· threshold Β· active recovery
β β βββ settings.tsx β Theme Β· app info Β· sign out
β βββ recovery/[proposalId].tsx β Guardian approval (deep-link target)
β
βββ components/
β βββ ui/ β Design system: Button, Card, Input, Sheet, Toastβ¦
β βββ layout/ β TabBar, ThemeSwitch, OnboardingHeader, StepDots
β βββ wallet/ β BalanceCard, TransactionList, SendSheet, SignerList
β βββ policies/ β SpendLimitCard, SessionKeysCard, AllowListCard
β βββ guardians/ β GuardianList, RecoveryBanner, RecoveryStatusCard
β
βββ native/
β βββ passkey-adapter.ts β β
ONLY platform-specific seam
β Implements PasskeyProvider (react-native-passkeys)
β
βββ hooks/
β βββ useTheme.tsx β Color-scheme resolution + SecureStore override
β βββ useWallet.ts β Balance, signers, send mutation
β βββ usePolicies.ts β Session keys CRUD
β βββ useRecovery.ts β Recovery proposal lifecycle (10s polling)
β
βββ lib/
β βββ config.ts β Zod-validated EXPO_PUBLIC_* env vars
β βββ sdk-client.ts β WalletSdk singleton (native passkeyProvider injected)
β βββ storage-adapter.ts β StorageAdapter β expo-secure-store
β βββ query-client.ts β TanStack Query (offline-first defaults)
β βββ api.ts β Typed fetch helpers for relay-backend
β βββ format.ts β XLM, address, date formatting
β
βββ store/auth.ts β Zustand (walletAddress + credentialId, SecureStore-persisted)
βββ assets/ β Icons, splash, logo β light & dark variants
βββ e2e/flows/ β Maestro YAML E2E flows
β
βββ docs/ β π Extended documentation
β βββ ARCHITECTURE.md β Deep-dive: design decisions, flows, CI/CD
β βββ SETUP.md β Step-by-step local dev + real-device setup
β βββ CONTRIBUTING.md β How to contribute, code standards, commit convention
β βββ SECURITY.md β Security model + vulnerability reporting
β
βββ .github/
β βββ workflows/ β ci Β· eas-preview Β· eas-release Β· eas-update
β βββ ISSUE_TEMPLATE/ β Bug report Β· Feature request (GitHub Forms)
β βββ PULL_REQUEST_TEMPLATE.md
β
βββ app.config.ts β Expo config (env-driven, no secrets)
βββ eas.json β development / preview / production EAS profiles
βββ .env.example β All EXPO_PUBLIC_* vars β copy to .env
flowchart TD
A([Open App]) --> B{Has Session?}
B -- No --> C[Welcome Screen]
B -- Yes --> DASH
C --> D{New or Returning?}
D -- New User --> E[Enter Display Name]
D -- Returning --> F[Login with Passkey]
E --> G["Face ID / Touch ID Prompt<br/>create passkey"]
G --> H["Relay: /webauthn/register/options<br/>+ /webauthn/register/verify"]
H --> I["Deploy Wallet Contract<br/>on Stellar Testnet"]
I --> DASH
F --> J["Face ID / Touch ID Prompt<br/>assert passkey"]
J --> K["Relay: GET /wallets/:credentialId<br/>lookup wallet address"]
K --> DASH
DASH([Dashboard]) --> TAB1["π° Wallet Tab"]
DASH --> TAB2["π‘οΈ Policies Tab"]
DASH --> TAB3["π₯ Guardians Tab"]
TAB1 --> L["View XLM Balance<br/>+ Transaction History"]
TAB1 --> M["Send XLM<br/>Biometric sign β relay submit"]
TAB2 --> N[View Session Keys]
TAB2 --> O["Revoke Session Key<br/>DELETE /api/sessions/:id"]
TAB3 --> P{Active Recovery?}
P -- Yes --> Q["View Status<br/>+ Approve Recovery<br/>POST /api/recovery/approve"]
P -- No --> R["Initiate Recovery<br/>POST /api/recovery/propose"]
Z(["Deep Link<br/>rayos://recovery/:id"]) --> Q
graph TB
subgraph "Mobile App (this repo)"
APP["expo-router screens"]
HOOKS["hooks/<br/>useWallet Β· usePolicies Β· useRecovery"]
ADAPTER["native/passkey-adapter.ts<br/>PasskeyProvider impl"]
SDK_CLIENT["lib/sdk-client.ts<br/>WalletSdk singleton"]
STORE["store/auth.ts<br/>Zustand + SecureStore"]
APP --> HOOKS
HOOKS --> SDK_CLIENT
SDK_CLIENT --> ADAPTER
HOOKS --> STORE
end
subgraph "wallet-sdk (file dep)"
WSDK[WalletSdk]
WCLIENT["WalletClient<br/>Soroban contract calls"]
PCLIENT["PolicyClient<br/>Sessions Β· Recovery"]
RCLIENT["RelayClient<br/>HTTP relay calls"]
WSDK --> WCLIENT
WSDK --> PCLIENT
WSDK --> RCLIENT
end
subgraph "relay-backend (NestJS)"
WA["/webauthn/*<br/>Challenge + verify"]
REL["/relay/submit<br/>+ /relay/status"]
SES["/sessions<br/>Session key CRUD"]
REC["/recovery/*<br/>Propose + approve"]
IDX["/wallets/:credentialId<br/>Address lookup"]
WK["/.well-known/*<br/>AASA + assetlinks"]
end
subgraph "Stellar Network"
SRPC[Soroban RPC]
HRZ["Horizon API<br/>Transaction history"]
FACTORY[FactoryContract]
WALLET_C[WalletContract]
POLICY_C[PolicyContract]
end
subgraph "Device"
ENCLAVE["Secure Enclave / StrongBox<br/>Passkey never leaves here"]
end
SDK_CLIENT --> WSDK
ADAPTER --> ENCLAVE
RCLIENT --> REL
RCLIENT --> WA
WCLIENT --> SRPC
SRPC --> FACTORY
SRPC --> WALLET_C
SRPC --> POLICY_C
HOOKS -->|Horizon fetch| HRZ
HOOKS --> IDX
HOOKS --> SES
HOOKS --> REC
# 1. Clone wallet-sdk alongside (required β file: dependency)
git clone https://github.com/Rayos-Org/wallet-sdk.git
cd wallet-sdk && pnpm install && pnpm build && cd ..
# 2. Clone and install this app
git clone https://github.com/Rayos-Org/mobile-app.git
cd mobile-app
pnpm install
# 3. Configure environment
cp .env.example .env
# 4. Start dev server
pnpm ios # Xcode simulator
pnpm android # Android emulator
pnpm start # Metro only (for use with Expo Dev Client)
β οΈ Expo Go will not work. Passkeys require the native module fromreact-native-passkeys. Use a development build:pnpm build:dev(EAS) orpnpm ios/pnpm androidlocally.
β Full setup guide (real device, passkeys, EAS): docs/SETUP.md
pnpm typecheck # TypeScript strict check
pnpm lint # ESLint (eslint-config-expo)
pnpm format:check # Prettier
pnpm test # Jest unit + component tests
pnpm test:ci # Jest with coverage report
pnpm e2e # Maestro E2E flows (device/simulator must be running)| Layer | Coverage |
|---|---|
lib/format.ts |
XLM formatting, address truncation, date helpers |
lib/api.ts |
Error normalisation, typed responses |
lib/theme.ts |
Token resolution in both color schemes |
native/passkey-adapter.ts |
Output shape matches PasskeyCredential / PasskeyAssertion types |
store/auth.ts |
Zustand store mutations and persistence |
components/ |
Render in light + dark theme; interaction snapshots |
e2e/flows/onboarding.yml |
Full onboarding flow to wallet screen |
e2e/flows/send.yml |
Send flow up to biometric gate |
Biometric ceremonies themselves are exercised in manual device-lab testing before every release.
| Workflow | Trigger | What it does |
|---|---|---|
ci.yml |
Every PR + main push |
typecheck β lint β prettier β jest β expo-doctor β expo export |
eas-preview.yml |
Every PR + main push |
eas build --profile preview Β· posts QR code comment on PR |
eas-release.yml |
Push tag v*.*.* |
quality gates β production build β βΈ manual approval β eas submit |
eas-update.yml |
main push or manual dispatch |
eas update OTA to preview or production channel |
PR βββΆ ci.yml βββΆ eas-preview.yml (installable QR build)
main βββΆ eas-update.yml (OTA to preview channel)
tag v1.x.x βββΆ eas-release.yml βββΆ βΈ manual approval βββΆ eas submit
| Document | Description |
|---|---|
| docs/ARCHITECTURE.md | Deep-dive: tech stack, directory structure, design decisions, all key flows |
| docs/SETUP.md | Step-by-step: local dev, real device setup, passkey configuration, EAS first-time setup |
| docs/CONTRIBUTING.md | How to contribute: commit convention, PR process, code standards, testing requirements |
| docs/SECURITY.md | Security model, responsible disclosure process |
We welcome contributions of all kinds β bug reports, feature ideas, code, tests, documentation, design feedback.
Quick start:
- Read docs/CONTRIBUTING.md
- Check open issues for
good first issuelabels - Fork β branch β PR against
main
Found a security issue? Please use GitHub Security Advisories instead of a public issue. See docs/SECURITY.md.
MIT Β© 2026 Rayos Org contributors.
Built with β€οΈ by the Rayos community.
β Star this repo if you find it useful β it helps others discover the project.