A React Native Expo app that interfaces directly with the Halliday Payments API v2 to perform onramp (fiat-to-crypto), swap (crypto-to-crypto), and deposit operations. Users authenticate via Reown AppKit (WalletConnect) for external wallets or Dynamic for email-based embedded wallets.
The app calls the Halliday Payments API v2 directly — no SDK or WebView wrapper. Screens walk the user through: select assets and amount, fetch and compare quotes from multiple providers, confirm a payment, then track execution in real time. For onramp, the user is redirected to the provider's funding page. For swap, the user signs and sends the funding transaction from their wallet. Failed or expired payments surface stuck token balances that can be withdrawn or retried.
- Node.js (v22+)
- Xcode (iOS) or Android SDK (Android)
- CocoaPods (iOS)
Create .env in the project root:
EXPO_PUBLIC_HALLIDAY_API_KEY=your_halliday_api_key
EXPO_PUBLIC_REOWN_PROJECT_ID=your_reown_project_id
EXPO_PUBLIC_DYNAMIC_ENVIRONMENT_ID=your_dynamic_environment_id
Get credentials from Halliday, Reown Cloud, and Dynamic.
npm install
Runs with Expo Go mobile app. Scan the QR code in the terminal!
npm start
Simulator:
npx expo run:ios
npx expo run:android
On device:
npx expo run:ios --device
npx expo run:android --device
Also building for a connected device without a Metro debug server on iOS:
npx expo run:ios --configuration Release --device --no-bundler
External wallet — Landing → Connect (WalletConnect deep link to MetaMask, Trust, etc.) → Home
Email — Landing → Login (OTP via Dynamic SDK) → embedded wallet created → Home
| Route | Purpose |
|---|---|
/ |
Landing — connect wallet or login with email |
/connect |
WalletConnect pairing with external wallet apps |
/login |
Email OTP login, creates Dynamic embedded wallet |
/home |
Onramp / Swap / Deposit tabs, asset and amount selection |
/confirm |
Fetch quotes, compare providers, select best rate |
/checkout |
Payment execution and real-time step tracking |
/deposit-checkout |
Deposit-specific flow showing OTW deposit address |
/history |
Payment history with stuck-payment indicators |
/recovery |
Withdraw stuck tokens or retry failed payments |
app/
_layout.tsx Root layout, provider stack, SDK noise suppression
index.tsx Landing screen
connect.tsx WalletConnect flow
login.tsx Email OTP flow (Dynamic)
home.tsx Asset selection tabs (onramp/swap/deposit)
confirm.tsx Quote fetching and selection
checkout.tsx Payment execution + progress tracking
deposit-checkout.tsx Deposit execution + OTW address display
history.tsx Payment history list
recovery.tsx Stuck token withdrawal / retry
components/
AmountInput.tsx Debounced amount field
AssetPicker.tsx Modal asset selector with search
Button.tsx Primary/secondary/outline variants
Menu.tsx Hamburger menu (theme, history, disconnect)
QuoteCard.tsx Quote details display
ProviderPicker.tsx Onramp provider selector
BalanceCard.tsx Token balance display
PaymentStatusCard.tsx Payment history card
HallidayLogo.tsx SVG logo
context/
ThemeContext.tsx Light/dark/auto theme
AuthContext.tsx Auth state + wallet sign/send actions
DynamicContext.tsx Lazy Dynamic SDK mount
AssetsContext.tsx Cached assets and chains from API
RecoverableContext.tsx Polls for stuck token balances
lib/
api.ts All Halliday API v2 calls
reown.ts Reown AppKit + WalletConnect setup
dynamic.ts Dynamic SDK client init
types.ts TypeScript types for API responses
constants.ts API base URL, polling intervals, env vars
format.ts Address truncation, amount formatting, chain names
wallet.ts ERC20 transfer encoding, chain ID mapping
theme.ts Color palettes
store.ts In-memory state for cross-screen data
walletIcons.ts Wallet SVG icons
useAppState.ts App foreground/background hook
useDynamicSessionGuard.ts Session validation on app resume
assets/
wallets/ Wallet logos (MetaMask, Trust, OKX, etc.)
providers/ Provider logos (Moonpay, Stripe, Transak, etc.)
- Asset format: crypto assets use
chain:0xaddress(e.g.base:0x833589f...), fiat usesusd - EIP-712 withdrawals: the API returns a
withdraw_authorizationJSON blob — deletetypes.EIP712Domainbefore passing tosignTypedData - Payment retry: pass
parent_payment_idin the quote request to link retries to the original payment - Babel:
unstable_transformImportMeta: trueis required inbabel.config.jsfor Reown/valtio compatibility - iOS deep links: wallet URL schemes (metamask, trust, okex, etc.) are declared in
app.jsonunderLSApplicationQueriesSchemes
Ensure these tools installed and are available in the CLI.
- Android SDK — $ANDROID_HOME set, SDK at ~/Library/Android/sdk
- Build tools — 35.0.0 and 36.0.0
- Platforms — android-35 and android-36
- Java 17 — required by Gradle, installed via Homebrew
- ADB — available for device/emulator communication
- Expo CLI — 55.0.8
- Node.js LTS
Run:
npm install
npm run install:web
npm run build:web
npx expo prebuild --platform android
cd android && ./gradlew assembleRelease
The APK will be at: android/app/build/outputs/apk/release/app-release.apk
Ensure these tools installed and are available in the CLI.
- Xcode — Mac App Store (includes simulators + build toolchain)
- Apple Developer account and code signing configured in Xcode for production or TestFlight builds
- Xcode Command Line Tools — xcode-select --install
- Node.js LTS
Run:
npm install
npx expo prebuild --platform ios
## Open the xcworkspace in ios/ with Xcode and create a release build