Reputation-based, step-by-step credit (BNPL) for students, interns, and small vendors — settled on Stellar.
The official StepFi mobile client, built with Expo + React Native.
Quick Start · Architecture · Features · Testing · Roadmap · StepFi org
StepFi lets learners and interns borrow small amounts against an on-chain reputation score instead of collateral, repay in scheduled installments, and build a credit history — while sponsors fund a shared liquidity pool and vendors get paid directly. All credit logic, repayment, and reputation live in Soroban smart contracts on Stellar; this repo is the mobile app users hold in their hands.
- 🎓 Learners connect a wallet, see their credit limit and APR (both derived from reputation), request a loan, and repay on a schedule.
- 💚 Sponsors back the liquidity pool that funds loans.
- 🏪 Vendors are paid on loan disbursement and tracked in an on-chain registry.
This repo is the learner client. Sponsor and vendor experiences live in StepFi-Web; this app focuses on the learner journey.
StepFi-App is one of six repositories in the StepFi protocol. It talks to StepFi-API over REST (wallet-signature JWT), signs transactions through the user's wallet, and ultimately drives the StepFi-Contracts deployed on Stellar.
| Tool | Version | Notes |
|---|---|---|
| Node.js | ≥ 20 | Matches CI |
| npm | ≥ 10 | Uses --legacy-peer-deps (Expo 54 peer graph) |
| Expo CLI | bundled | Invoked via npx expo |
| Xcode / Android Studio | latest | Only for native simulators/devices |
| A Stellar wallet | — | Freighter (web) or Lobstr (mobile, via WalletConnect) |
git clone https://github.com/StepFi-app/StepFi-App.git
cd StepFi-App
npm install --legacy-peer-deps
# start the dev server (choose a target from the Expo menu)
npm start
npm run android # Android device/emulator
npm run ios # iOS simulator
npm run web # browserCreate a .env (loaded by Expo as EXPO_PUBLIC_* at build time):
| Variable | Purpose |
|---|---|
EXPO_PUBLIC_API_URL |
Base URL of StepFi-API |
EXPO_PUBLIC_WALLETCONNECT_PROJECT_ID |
WalletConnect Cloud project ID (Lobstr / mobile) |
EXPO_PUBLIC_SENTRY_DSN |
Sentry DSN (optional — Sentry is skipped if unset) |
No secrets are bundled.
EXPO_PUBLIC_*values are public by design; never put private keys here.
app/ # expo-router routes (file-based)
├── (auth)/ # onboarding, role-select, sign-in, register
├── (tabs)/ # Home · Loans · Simulate · Calendar · Score · Settings
├── _layout.tsx # root: auth guard, biometric gate, idle-lock, Sentry, netinfo
└── index.tsx # entry redirect
components/ # shared UI (wallet, reputation, cards…)
hooks/ # useWallet, invest/, reputation/ (+ pure, tested utils)
services/ # api, auth, wallet, loans, reputation, notifications, sentry
stores/ # Zustand: auth, user, wallet, loans
src/
├── security/ # biometric.service, security.store, lockout
├── offline/ # queue, sync, TTL cache, connectivity store
├── transactions/ # transaction-signer.service
└── locales/ # i18n (en · fr · pt)
| Layer | Choice |
|---|---|
| Framework | Expo ~54 · React Native 0.81 · React 19 |
| Routing | expo-router (file-based) |
| Language | TypeScript ~5.9 |
| State | Zustand 5 |
| Styling | NativeWind + Tailwind 3.4 |
| Wallets | @stellar/freighter-api · @walletconnect/sign-client |
| Animation | react-native-reanimated 4 · react-native-svg |
| Storage | expo-secure-store (secrets) · AsyncStorage (offline queue) |
| Networking | axios |
| i18n | i18next + react-i18next + expo-localization |
| Observability | @sentry/react-native |
| Feature | Status | Where |
|---|---|---|
| Wallet connect — Freighter (web) + Lobstr (WalletConnect) | ✅ | services/wallet.service.ts, hooks/useWallet.ts |
| Biometric + PIN app lock | ✅ | src/security/biometric.service.ts |
| Persisted lockout & idle auto-lock | ✅ | src/security/security.store.ts, app/_layout.tsx |
| Reputation score + animated ring | ✅ | app/(tabs)/reputation.tsx, components/reputation/ |
| Loans list & repayment | ✅ | app/(tabs)/loans.tsx, services/loans.service.ts |
| Loan simulator | ✅ | app/(tabs)/simulate.tsx |
| Repayment calendar + reminders | ✅ | app/(tabs)/calendar.tsx, services/notifications.service.ts |
| Offline queue, sync & cache | ✅ | src/offline/ |
| Localization (English · Français · Português) | ✅ | src/locales/ |
| Transaction signing | ✅ | src/transactions/transaction-signer.service.ts |
| Real wallet-signature JWT auth | 🚧 | #35 — mock tokens today; blocked on a wallet message-signing primitive |
| Editable profile · notification preferences | 🗺️ | planned |
Two wallets are supported through one interface (services/wallet.service.ts):
- Freighter (
@stellar/freighter-api) for web —requestAccess,signTransaction. - Lobstr over WalletConnect for mobile — the
stellar:pubnetnamespace negotiatesstellar_signXDR/stellar_signAndSubmitTransaction.
Auth note: StepFi-API's
/auth/verifyexpects a signed message; mobile wallets over WalletConnect currently sign XDR only. Until asignMessageprimitive lands, registration issues placeholder tokens — tracked in #35.
- Biometric unlock via
expo-local-authenticationwith a PIN fallback; the PIN is salted and SHA-256 hashed withexpo-crypto— never stored in plaintext. - Failed-attempt lockout and
isLockedare persisted (SecureStore on native,localStorageon web) so relaunching the app cannot bypass the gate; state resets on sign-out. - Idle auto-lock after 5 minutes and on app resume (
app/_layout.tsx).
Business logic is extracted into pure, unit-tested helpers.
npm run typecheck # tsc --noEmit
npm run lint # eslint + prettier --check
npm test # jest| Suite | Tests | File |
|---|---|---|
| Invest math | 6 | hooks/invest/use-invest.test.ts |
| Vouch guard | 5 | hooks/reputation/vouch-utils.test.ts |
| Lockout / backoff | 6 | src/security/lockout.test.ts |
| Transaction signer | 9 | src/transactions/__tests__/transaction-signer.service.test.ts |
| Total | 26 |
Every push and PR runs .github/workflows/ci.yml (Node 20), a required check on main:
- web-build —
npx expo export --platform web(uploads thedist/artifact). - quality —
lint+typecheck+test.
Tagging v* triggers eas-build.yml: an EAS production Android build that is attached as an APK to a GitHub Release.
| Milestone | Status |
|---|---|
| Wallet connect (Freighter + Lobstr) | ✅ |
| Biometric + PIN lock with persisted lockout | ✅ |
| Offline queue & sync, TTL cache | ✅ |
| Localization (en · fr · pt) | ✅ |
| Reputation, loans, simulator, calendar reminders | ✅ |
| Enforced CI gate (web export + lint + typecheck + test) | ✅ |
| Real wallet-signature JWT auth (message signing) | 🚧 |
| Live wiring to StepFi-Contracts on testnet | 🚧 |
| Editable profile · notification preferences | 🗺️ |
- Branch off
main(feat/…,fix/…,docs/…,chore/…). - Keep the gate green locally:
npm run typecheck && npm run lint && npm test && npx expo export --platform web. - Open a PR using the template; PRs into
mainmust pass the required checks.
See docs/contributing.md for the full guide.
| Repo | Role |
|---|---|
| StepFi-App (this repo) | Learner & sponsor mobile client |
| StepFi-Contracts | Soroban smart contracts (credit, reputation, liquidity) |
| StepFi-API | Backend: auth/JWT, orchestration, jobs |
| StepFi-Web | Marketing site & web dashboard |
| StepFi-Docs | Protocol documentation |
Released under the MIT License.