Click to expand
- Overview
- Download APK
- Feedback Responses
- App Screenshots
- Current Testnet Values
- Vision
- Key Features
- Architecture
- Project Structure
- Quick Start
- CI/CD
- Runbook
- Environment Reference
- Components
- Tech Stack
- How It Works
- Cost Breakdown
- Security
- Implementation Proof
- Useful Commands
- Troubleshooting
- Production Notes
- Roadmap
- Contributing
C-Pay transforms Stellar payments into a UPI-like experience. Users do not need to understand trustlines, fee bumps, sponsored reserves, contract IDs, or Stellar secret seeds. They verify an email address with Supabase OTP, create a PIN, create an encrypted cloud wallet backup, optionally enable biometrics, use a C-Pay ID, scan QR codes, and pay with CPINR.
| Traditional Crypto Wallets | C-Pay |
|---|---|
|
β Manual wallet address handling |
β
Email OTP onboarding now, phone OTP ready for a future SMS provider |
C-Pay is intentionally running as a closed testnet pilot today. The current app proves the wallet, QR payment, merchant, recovery, and relayer flows with pilot credits. The production direction adds stronger identity, fiat rails, and withdrawal support before any real-money rollout.
| Area | Current Pilot | Planned Production Direction |
|---|---|---|
| User verification | Email OTP through Supabase for onboarding and account recovery | Phone OTP verification through a production SMS provider, with email as an additional recovery/contact channel |
| User KYC | Not required for pilot credits because they have no cash value | User KYC before real fiat add-money, withdrawals, higher limits, or regulated payment features |
| Merchant checks | Merchant profile and contract registration for QR payment acceptance | Merchant KYS/KYB review before accepting real customer payments, including business identity, settlement details, and risk checks |
| Receive money | Users and merchants can receive pilot credits through wallet address, C-Pay ID, and QR flows | Receive from all approved sources supported by C-Pay, including app-to-app payments, merchant QR, and future fiat/on-ramp sources |
| Add Money | Closed-pilot claim flow adds test credits for demo and testing | Fiat bridge flow where users pay INR or another supported fiat source, then C-Pay processes the requested value into the app after verification |
| Withdrawals | Not enabled in the pilot app | Withdrawal flow for eligible users and merchants after KYC/KYS checks, balance validation, risk review, and supported settlement rail availability |
| Limits and risk | Basic app-side limits for pilot payments | Compliance-aware limits based on KYC/KYS status, transaction history, source of funds, and operational risk rules |
The guiding rule is simple: pilot credits are for testing the experience; real-money features require verified users, verified merchants, compliant fiat processing, and clear settlement controls.
Support the journey: C-Pay is still evolving toward stronger compliance, better payment rails, and real market fit. Feedback, technical help, product guidance, partnerships, and pilot testing support are welcome to improve the app and shape it into something people can trust and use every day.
π Network: Stellar testnet πͺ Asset: CPINR
π± Mobile: Expo React Native π Wallet: Stellar keypair, encrypted locally
π§Ύ Backend: Express relayer ποΈ Data: Supabase
π¦ Contract: Soroban Rust βοΈ Runtime relayer port: 3000
π§ Auth: Supabase email OTP βοΈ Recovery: encrypted wallet backup
The mobile app is configured for a closed pilot first: users see C-Pay pilot credits, not real INR balances. Production builds should keep EXPO_PUBLIC_DEV_MODE=false for real Supabase email OTP while keeping EXPO_PUBLIC_PILOT_MODE=true until legal, payment, and operational requirements are ready for public real-money use.
This README does not keep an outdated APK link. Build the current Stellar/CPINR app from App/ so the APK uses the latest relayer URL, CPINR issuer, and UI changes.
cd App
npm run build:android:production-apkFor both Android and iOS production builds, run:
cd App
npm run build:production:allThe production Android profile creates a release APK. iOS builds are separate artifacts for Apple devices; APK files are Android-only.
Note: This is a closed-pilot testnet app. Use Stellar testnet accounts, testnet XLM, and C-Pay pilot credits only.
Want to try C-Pay and share feedback? Fill out the C-Pay feedback form.
Live response sheet: C-Pay feedback responses
| User Name | User Email | User Wallet Address |
|---|---|---|
| SHAMPA DAS | dasshampa2022@gmail.com | GCXPJ4SJDOSM6IGJPSFUWC4QQMA33S6M456TC32RU2LZ65OJHKD7YWVC |
| soumen mandal | soumenmandal1080@gmail.com | GBGJS2UIEF2DYN3L67P2A7X62M4WK72JGTF7ABCOQL75UYHMWYLFRI4S |
| SUMAN PRADHAN | prasuman01@gamil.com | GCIVVA5M5WCBTWZ4AXBX6W4THTXAHHCUP27VFQIIVTGU7HLLLODZ6AXH |
| sam mandal | kinemaster1444@gmail.com | GBGJS2UIEF2DYN3L67P2A7X62M4WK72JGTF7ABCOQL75UYHMWYLFRI4S |
| Arka Dash | dasharka05@gmail.com | GAD3FPRJ7K2FFX7JBRIITVJP2A4OLIO4M3AKABEF4HFG732RESVFYV6K |
| Souvik Mandal | souvikmandals10@gmail.com | GAKUELFFUKSAJMTECN2SVXDRJOUJXDE27OPTD57SA65KJ6AU32SXKF27 |
| User Name | User Email | User Wallet Address | User Feedback | Commit ID |
|---|---|---|---|---|
| SHAMPA DAS | dasshampa2022@gmail.com | GCXPJ4SJDOSM6IGJPSFUWC4QQMA33S6M456TC32RU2LZ65OJHKD7YWVC |
There is no withdrawal option. | b701f6f |
| soumen mandal | soumenmandal1080@gmail.com | GBGJS2UIEF2DYN3L67P2A7X62M4WK72JGTF7ABCOQL75UYHMWYLFRI4S |
create a StartUp use this | N/A |
| SUMAN PRADHAN | prasuman01@gamil.com | GCIVVA5M5WCBTWZ4AXBX6W4THTXAHHCUP27VFQIIVTGU7HLLLODZ6AXH |
No change requested. | N/A |
| sam mandal | kinemaster1444@gmail.com | GBGJS2UIEF2DYN3L67P2A7X62M4WK72JGTF7ABCOQL75UYHMWYLFRI4S |
No written feedback provided. | N/A |
| Arka Dash | dasharka05@gmail.com | GAD3FPRJ7K2FFX7JBRIITVJP2A4OLIO4M3AKABEF4HFG732RESVFYV6K |
Make the dark theme default and make the wallet address more obvious. Otherwise it was a great experience. | a192c5f |
| Souvik Mandal | souvikmandals10@gmail.com | GAKUELFFUKSAJMTECN2SVXDRJOUJXDE27OPTD57SA65KJ6AU32SXKF27 |
Overall app experience is good. But suggestions will be more on UI perspective. | 3e1b812 |
Withdrawal note: Withdrawal is planned as a future implementation because it requires real-money interaction, banking/payment authority approval, compliance review, and proper mentoring before production rollout. The current C-Pay app is a closed-pilot Stellar testnet app, so pilot credits have no real cash value.
| # | Timestamp | Full Name | Form Email | Provided Email | Wallet Address | Overall Satisfaction | UI | Speed | Security | Transaction Reliability | Support | Most Used Features | Bug Reported | Issue Details | Recommend Rating | Suggestions |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 28/04/2026 10:44:06 | SHAMPA DAS | dasshampa2022@gmail.com | dasshampa2022@gmail.com | GCXPJ4SJDOSM6IGJPSFUWC4QQMA33S6M456TC32RU2LZ65OJHKD7YWVC |
10 | Good (3) | Fair (2) | Excellent (4) | Excellent (4) | Fair (2) | Sending Funds, In-App Crypto Exchange/Swap | No | 4 | There is no withdrawal option | |
| 2 | 28/04/2026 12:38:54 | soumen mandal | soumenmandal1080@gmail.com | soumenmandal1080@gmail.com | GBGJS2UIEF2DYN3L67P2A7X62M4WK72JGTF7ABCOQL75UYHMWYLFRI4S |
10 | Excellent (4) | Excellent (4) | Excellent (4) | Excellent (4) | Excellent (4) | Sending Funds, Receiving Funds, Checking Balance/History, Staking/Yield Programs, In-App Crypto Exchange/Swap, Other (Please specify below) | No | NaN | 5 | create a StartUp use this |
| 3 | 28/04/2026 18:24:02 | SUMAN PRADHAN | pradhan.1.7.2006@gmail.com | prasuman01@gamil.com | GCIVVA5M5WCBTWZ4AXBX6W4THTXAHHCUP27VFQIIVTGU7HLLLODZ6AXH |
10 | Excellent (4) | Excellent (4) | Excellent (4) | Excellent (4) | Excellent (4) | Sending Funds, Receiving Funds, Checking Balance/History, Staking/Yield Programs, In-App Crypto Exchange/Swap, Other (Please specify below) | No | 5 | No | |
| 4 | 28/04/2026 19:25:57 | sam mandal | kinemaster1444@gmail.com | kinemaster1444@gmail.com | GBGJS2UIEF2DYN3L67P2A7X62M4WK72JGTF7ABCOQL75UYHMWYLFRI4S |
10 | Excellent (4) | Excellent (4) | Excellent (4) | Excellent (4) | Excellent (4) | Sending Funds, Receiving Funds, Checking Balance/History, Staking/Yield Programs, In-App Crypto Exchange/Swap, Other (Please specify below) | No | NaN | 5 | |
| 5 | 28/04/2026 21:39:04 | Arka Dash | dasharka05@gmail.com | dasharka05@gmail.com | GAD3FPRJ7K2FFX7JBRIITVJP2A4OLIO4M3AKABEF4HFG732RESVFYV6K |
10 | Excellent (4) | Excellent (4) | Excellent (4) | Excellent (4) | Excellent (4) | Sending Funds, Receiving Funds, Checking Balance/History, Staking/Yield Programs, In-App Crypto Exchange/Swap | No | 5 | Make the dark theme default & Make the wallet address more obvious Otherwise it was a great experience!! |
|
| 6 | 29/04/2026 10:14:24 | Souvik Mandal | souvikmandals10@gmail.com | souvikmandals10@gmail.com | GAKUELFFUKSAJMTECN2SVXDRJOUJXDE27OPTD57SA65KJ6AU32SXKF27 |
8 | Fair (2) | Good (3) | Good (3) | Good (3) | Good (3) | Sending Funds, Receiving Funds, Checking Balance/History | Yes | 5 | Overall app experience is good. But suggestions will be more on UI perspective. |
![]() Get Started |
![]() Email OTP |
![]() Create PIN |
![]() Restore Backup |
![]() Loading |
![]() Home |
![]() Send |
![]() Send Money |
![]() User QR |
![]() Merchant QR |
![]() Merchant Dashboard |
![]() Profile |
![]() Profile Details |
![]() Transaction Details |
![]() Payment Successful |
![]() Failed Payment |
These values are public and come from Blockchain/contract-ids.json.
| Item | Current Value |
|---|---|
| Stellar network | testnet |
| Network passphrase | Test SDF Network ; September 2015 |
| Horizon URL | https://horizon-testnet.stellar.org |
| Soroban RPC URL | https://soroban-testnet.stellar.org |
| Explorer | https://stellar.expert/explorer/testnet |
| Asset | CPINR:GA2SFZ4GJVMLPULSJMTY7RMIOPQD5W5JGTDSD3N7I2PR5KZRFGPQF5BJ |
| CPINR issuer public key | GA2SFZ4GJVMLPULSJMTY7RMIOPQD5W5JGTDSD3N7I2PR5KZRFGPQF5BJ |
| Stellar Asset Contract ID | CDR6RDWPZAHOARJKV5YF57VEOE2PJQP6KTE5FGQSJVKLPN5M3KCFE3SN |
| Stellar Asset Contract Explorer | Open on Stellar Expert |
| C-Pay payments contract ID | CBHYSB5W6TRDTGGYSZUYJBXPPIO7XJS2SLNHJVKWEINOKQC7MKU4N6CR |
| C-Pay payments contract Explorer | Open on Stellar Expert |
| C-Pay payments Wasm hash | 24522af6d53859f9c453cea65912c4b13000baec04301598b12edc905f084fb9 |
| Contract record updated | 2026-04-27T03:33:54.623Z |
Important: Public keys and contract IDs are safe to document. Stellar secret seeds beginning with
Smust never be added to the mobile app or committed to source control.
Users should not need to know that a Stellar account, trustline, XDR, fee bump, or Horizon request is involved. Like UPI hides bank routing complexity, C-Pay hides blockchain complexity behind familiar payment patterns.
| Banking Abstraction (UPI) | Stellar Abstraction (C-Pay) |
|---|---|
|
π¦ Bank account β VPA |
π Stellar secret β encrypted local wallet |
Authentication & Wallet Security
- π§ Email OTP Verification - Active login/onboarding path through Supabase email OTP.
- π’ 8-Digit Verification Code - The verification UI expects the current 8-digit Supabase email code format.
- π 6-Digit PIN - Used to encrypt and unlock the local Stellar wallet.
- π Biometric Unlock - Optional device biometric backup/unlock through the dedicated biometric setup screen.
- π Stellar Wallet - Device-generated Stellar keypair for each user.
- π‘οΈ Encrypted Storage - Stellar secret is encrypted before storage in Expo SecureStore.
- βοΈ Encrypted Cloud Backup - User creates a recovery password so the Stellar wallet can be restored after app data loss.
- π§© Recovery Password Rules - Minimum 12 characters with at least 1 uppercase letter, 1 number, and 1 special character.
- π C-Pay ID - UPI-like identifier based on the verified email handle and wallet fingerprint, such as
user@cpayk8f3qz. - ποΈ Wallet Address Reveal - Full Stellar address is available in profile when needed.
- π Key Export - Profile includes private key and Stellar secret export actions.
- π΅ Phone OTP Paused - Phone-number columns and helper functions remain for the future, but the current UI does not offer phone OTP because Twilio/SMS is not enabled for the MVP.
Payments
- πΈ QR Code Scanning - Scan user or merchant QR codes.
- πΈ Send Money - Send CPINR to Stellar accounts through a signed app transaction.
- π Add Money - Relayer distributes configured CPINR amount from the distribution account.
- β±οΈ Claim Cooldown - After a pilot credit claim, users see the remaining time before the next claim.
- β‘ Sponsored Fees - Relayer can submit fee-bump transactions so users do not manage fees directly.
- π Transaction History - Local-first transaction records with Supabase sync.
- π Explorer Links - Stellar expert explorer URLs for accounts and transactions.
- π¦ Account Readiness - Relayer sponsors account creation and CPINR trustline setup.
User Experience
- π¨ Modern Mobile UI - Onboarding, PIN, biometric, home, profile, Add Money, and payment screens.
- πͺͺ Profile Management - Display name, photo, C-Pay ID, wallet address, and key export.
- π Change PIN - Secure PIN update flow.
- πͺ Session Management - Sign out clears in-memory PIN session.
- π΄ Offline-First Records - Transactions are saved locally first and synced later.
- π§ Clear Add Money Status - Add Money shows user feedback instead of silently failing.
Click to expand merchant features
- πͺ Merchant Registration - Business name, owner details, category, address, and wallet.
- βοΈ Merchant Phone Validation - Contact phone numbers are normalized and limited to a valid 10-15 digit range.
- π Merchant Dashboard - Sales totals, payment insights, and transaction access.
- π± Global Merchant QR - Reusable QR for receiving CPINR.
- π΅ Amount QR - Generate QR codes for a fixed payment amount.
- π Merchant Transactions - Dedicated transaction history for business payments.
- π Merchant C-Pay ID - Merchant-friendly display identifier.
- π Merchant Restore - After wallet recovery, merchant details are rehydrated from Supabase by wallet address/auth user.
- β Merchant Active State - Contract-side merchant state supports active/inactive behavior.
- π Stellar Testnet Rail - Current app is built around Stellar testnet CPINR.
- π§Ύ Express Relayer - Backend handles sponsored setup, Add Money, fee bumps, and status APIs.
- π§ Soroban Contract -
cpay_paymentsstores merchant and payment-intent state. - π Supabase Sync - Users, merchants, QR codes, transactions, Add Money claims, and encrypted wallet backups.
- π Rate Limiting - Relayer uses request rate limits.
- π©Ί Health Monitoring -
/healthreports sponsor XLM and distribution CPINR inventory. - π¨ Low Balance Alerts - Optional webhook for low sponsor XLM or low CPINR.
- π§° Operator Scripts - Key generation, testnet CPINR setup, contract build, and contract deploy.
flowchart LR
user["User / Merchant"]
app["Expo React Native App<br/>Email OTP, PIN, QR, local wallet signing"]
supabase["Supabase Auth + Postgres<br/>users, merchants, transactions<br/>wallet_backups, add_money_claims"]
storage["Supabase Storage<br/>profile photos, merchant logos"]
relayer["Express Relayer<br/>sponsored setup, Add Money<br/>fee bumps, contract intents"]
stellar["Stellar Testnet + Horizon<br/>accounts, trustlines, CPINR"]
soroban["Soroban cpay_payments<br/>merchant registry, payment intents"]
user --> app
app <-->|email session, profile sync, backups| supabase
app <-->|image upload/download| storage
app -->|Bearer Supabase token + signed XDR| relayer
relayer -->|verify token / persist claims| supabase
relayer -->|sponsor, fee-bump, distribute CPINR| stellar
relayer -->|register merchant, confirm intent| soroban
soroban -->|contract state for merchant/payment flow| stellar
sequenceDiagram
autonumber
actor User
participant App as Expo React Native App
participant Supabase as Supabase Auth / DB
participant Relayer as Express Relayer
participant Chain as Stellar Horizon / Soroban
User->>App: Enter email address
App->>Supabase: Request Supabase email OTP
Supabase-->>App: Verify 8-digit code and create session
App->>App: Create PIN, generate Stellar keypair, encrypt local wallet
App->>Supabase: Save profile, email C-Pay ID, encrypted wallet backup
App->>Relayer: Prepare sponsored account and CPINR trustline
Relayer->>Chain: Submit sponsored setup transaction
Chain-->>Relayer: Account and trustline confirmed
Relayer-->>App: Return setup status
User->>App: Scan QR, Add Money, or send CPINR
App->>Relayer: Send bearer token with signed XDR/payment request
Relayer->>Supabase: Verify token and persist claim cooldown when configured
Relayer->>Chain: Submit fee-bump payment or CPINR distribution
Chain-->>Relayer: Return transaction hash / contract status
Relayer-->>App: Return receipt, failure, or claim countdown
App->>Supabase: Sync transaction, merchant, and profile state
App/
βββ App.tsx
βββ index.ts
βββ src/
β βββ navigation/ # Stack + tab navigation
β βββ screens/ # Onboarding, PIN, Home, Profile, Payment, Merchant
β βββ components/ # Buttons, cards, PIN input, modals, transaction UI
β βββ services/
β β βββ wallet.ts # Stellar keypair, encrypted wallet, PIN verifier
β β βββ blockchain.ts # Stellar/relayer client
β β βββ auth.ts # OTP and sign-out
β β βββ cloudWalletBackup.ts # Encrypted Supabase wallet backup
β β βββ storage.ts # Local + Supabase transaction storage
β β βββ merchant.ts # Merchant database helpers
β β βββ supabase.ts # Supabase client
β βββ utils/
β β βββ cpayId.ts # C-Pay ID generation and lookup
β β βββ biometric.ts # Biometric helpers
β β βββ qrCode.ts # QR payload helpers
β β βββ paymentAuth.ts # Payment authorization helpers
β βββ constants/ # Theme and config
β
relayer-service/
βββ server.js # Express API
βββ test-relayer.js # Health/status test script
βββ .env.example # Backend env template
β
Blockchain/
βββ contracts/cpay_payments/ # Rust Soroban contract
βββ scripts/create-keypairs.js # Generate setup keypairs
βββ scripts/setup-testnet-asset.js
βββ scripts/deploy-contract.js
βββ src/config.js
βββ src/stellarRail.js
βββ test/stellarRail.test.js
βββ contract-ids.json
New User Setup
Supabase email OTP
β
Create PIN
β
Generate Stellar keypair in app
β
Encrypt Stellar secret with PIN-derived key
β
Save encrypted wallet in SecureStore
β
Save profile + email-based C-Pay ID locally and in Supabase
β
Create encrypted cloud wallet backup with recovery password
β
Optional biometric backup
β
Home screen
Restore After Cache Delete/Reinstall
Supabase email OTP
β
App finds existing users row by auth_user_id/email
β
If local SecureStore wallet is missing, app opens RestoreWallet
β
User enters recovery password
β
App fetches wallet_backups row for auth.uid()
β
PIN-independent recovery password decrypts the Stellar secret
β
User creates a new local 6-digit PIN
β
App recreates SecureStore wallet and rehydrates profile/merchant state
The cloud backup restores the Stellar wallet. Profile and merchant details come from Supabase rows keyed by auth_user_id, email, and wallet address.
Sponsored Account Setup
App calls POST /accounts/prepare
β
Relayer builds sponsor-funded account/trustline transaction
β
App signs user-required operations
β
App calls POST /accounts/submit
β
Relayer submits to Stellar
β
User account can receive CPINR
Add Money
User taps Add Money
β
App ensures account + trustline are ready
β
App calls POST /add-money
β
Relayer checks cooldown, amount, distribution CPINR
β
Distribution account sends CPINR to user
β
App saves transaction locally and syncs Supabase
Send Money
User enters recipient or scans QR
β
App validates Stellar account and amount
β
App signs CPINR payment XDR locally
β
App calls POST /payments/submit
β
Relayer validates payment and builds fee-bump tx
β
Stellar confirms payment
β
App stores and displays receipt
users
id, auth_user_id, wallet_address, cpay_id, email, phone_number,
biometric_enabled,
profile_photo_url, display_name, stellar_network, cpinr_asset_code,
cpinr_asset_issuer, created_at, updated_at
merchants
id, auth_user_id, business_name, wallet_address, cpay_id, owner_name, email,
phone_number, business_address, category, logo_url, is_active,
total_transactions, total_revenue, stellar_network, cpinr_asset_code,
cpinr_asset_issuer, created_at, updated_at
transactions
id, user_id, transaction_id, transaction_type, merchant_id, tx_hash,
stellar_network, asset_code, asset_issuer, to_address, from_address,
amount, status, internal_status, user_visible_status, merchant_name,
note, sender_name, recipient_name, failure_reason, timestamps
merchant_qr_codes
id, merchant_id, qr_name, amount, asset_code, asset_issuer,
is_active, scan_count, timestamps
add_money_claims
id, wallet_address, amount, asset_code, asset_issuer, tx_hash,
idempotency_key, claimed_at, next_available_at
relayer_idempotency_keys
key, response, expires_at, created_at
wallet_backups
id, auth_user_id, wallet_address, backup_version, cipher, kdf,
kdf_iterations, salt, nonce, ciphertext, created_at, updated_atRun the schema from:
App/supabase_schema.sql
Important schema notes:
users.emailis the current verified login address.users.phone_numberstays for a future phone OTP/Twilio rollout.wallet_backupsstores only encrypted wallet material plus cryptographic metadata. It does not store the recovery password or plaintext Stellar secret.wallet_backupsis one row per Supabaseauth.users.id, enforced byUNIQUE(auth_user_id).add_money_claimsis used by the relayer for persistent pilot-credit cooldowns. Without it, cooldown can still work in relayer memory, but it will not survive restarts or multi-instance deployment.relayer_idempotency_keysis reserved in the schema; the current relayer code uses an in-memory idempotency cache.get_own_merchant_by_wallet(p_wallet_address)lets the app restore merchant state after wallet recovery while keeping RLS user-scoped.
CryptoPay/
βββ App/
β βββ App.tsx
β βββ app.json
β βββ eas.json
β βββ package.json
β βββ supabase_schema.sql
β βββ src/
β βββ components/
β βββ constants/
β βββ navigation/
β βββ screens/
β βββ services/
β βββ types/
β βββ utils/
β
βββ Blockchain/
β βββ contract-ids.json
β βββ package.json
β βββ src/
β βββ scripts/
β βββ test/
β βββ contracts/
β βββ cpay_payments/
β βββ Cargo.toml
β βββ src/lib.rs
β
βββ relayer-service/
β βββ package.json
β βββ server.js
β βββ test-relayer.js
β βββ .env.example
β
βββ MANUAL_SETUP.md
βββ README.md
node --version
npm --version
stellar version
rustup target add wasm32v1-noneRequired tools:
- Node.js 18 or newer
- npm
- Expo through
npm startornpx expo - Supabase project
- Rust 1.84 or newer
- Stellar CLI v25 or newer
- Android device with Expo Go, Android emulator, iOS simulator, or development build
cd Blockchain
npm install
cd ../relayer-service
npm install
cd ../App
npm installTerminal 1:
cd relayer-service
npm startTerminal 2:
cd App
npx expo start --clearDo not run:
npm expo startexpo is not an npm command. Use npm start from App/ or npx expo start.
GitHub Actions workflows:
.github/workflows/ci.yml
.github/workflows/eas-production-build.yml
The CI pipeline runs on pushes to main/master, pull requests, and manual workflow_dispatch runs.
| Job | Checks |
|---|---|
Mobile app |
npm ci, Expo dependency compatibility, TypeScript compile |
Relayer |
npm ci, Node syntax checks, Jest with --passWithNoTests |
Blockchain and contract |
npm ci, Stellar rail Jest tests, Rust formatting, Soroban contract tests |
The EAS production build workflow runs automatically for Android APK builds when changes under App/ are pushed to main or master. It can also be started manually with android, ios, or all as the platform input. The workflow is guarded by the repository secret EXPO_TOKEN and also accepts an existing EAS_TOKEN as a fallback; if neither secret is configured, it exits successfully with a clear skip message instead of failing unexpectedly.
Before using the production build workflow for releases, configure EXPO_TOKEN, Android/iOS credentials, and release approval rules in GitHub/EAS.
- Create a Supabase project.
- Copy the project URL into
App/.envasEXPO_PUBLIC_SUPABASE_URL. - Copy the anon/publishable key into
App/.envasEXPO_PUBLIC_SUPABASE_ANON_KEY. - Do not put the service-role key in the Expo app.
- Run the SQL in
App/supabase_schema.sql. - Enable Supabase email OTP for Auth. The app uses email OTP for onboarding/login and expects an 8-digit code in the UI.
- Add
emailto theuserstable by running the current schema if your project was created before the email-auth change. - Keep phone auth/SMS disabled until the Twilio or other SMS subscription is ready. The phone column remains for future migration.
- For relayer persistence and token verification, put the service-role key only in the relayer environment as
SUPABASE_SERVICE_ROLE_KEY. - For local development only, set
EXPO_PUBLIC_DEV_MODE=trueif you are testing legacy dev-only auth helpers. Production/internal pilot builds should keep itfalse.
cd Blockchain
cp .env.example .env
npm run create:keypairsThe keypair script prints:
ASSET_ISSUER_PUBLIC_KEYandASSET_ISSUER_SECRETASSET_DISTRIBUTION_PUBLIC_KEYandASSET_DISTRIBUTION_SECRETCONTRACT_ADMIN_PUBLIC_KEYandCONTRACT_ADMIN_SECRETRELAYER_PUBLIC_KEYandRELAYER_SECRET
Create the Stellar CLI deployer identity:
stellar keys generate cpay-deployer --fund
stellar keys public-key cpay-deployerTestnet asset setup:
STELLAR_NETWORK=testnet
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
ASSET_CODE=CPINR
ASSET_ISSUER_PUBLIC_KEY=<issuer public key>
ASSET_DISTRIBUTION_PUBLIC_KEY=<distribution public key>
ASSET_ISSUER_SECRET=<issuer secret>
ASSET_DISTRIBUTION_SECRET=<distribution secret>
INITIAL_SUPPLY=1000000000
TRUSTLINE_LIMIT=1000000000
LOCK_ISSUER_AFTER_SETUP=false
Run:
npm run setup:testnetContract deployment values:
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
SOROBAN_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
STELLAR_CLI_NETWORK=testnet
STELLAR_CLI_SOURCE_ACCOUNT=cpay-deployer
CONTRACT_ADMIN_PUBLIC_KEY=<contract admin public key>
RELAYER_PUBLIC_KEY=<contract relayer public key>
Build and deploy:
npm run contract:build
npm run deploy:contractThe deploy script writes:
Blockchain/contract-ids.json
cd relayer-service
cp .env.example .envMinimum local env:
PORT=3000
NODE_ENV=development
CORS_ORIGIN=*
STELLAR_NETWORK=testnet
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
STELLAR_BASE_FEE=100
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
TOKEN_CONTRACT_ID=CDR6RDWPZAHOARJKV5YF57VEOE2PJQP6KTE5FGQSJVKLPN5M3KCFE3SN
CPAY_CONTRACT_ID=CBHYSB5W6TRDTGGYSZUYJBXPPIO7XJS2SLNHJVKWEINOKQC7MKU4N6CR
CONTRACT_FLOW_ENABLED=true
CONTRACT_INTENT_TTL_SECONDS=600
CPINR_ASSET_CODE=CPINR
CPINR_ASSET_ISSUER=GA2SFZ4GJVMLPULSJMTY7RMIOPQD5W5JGTDSD3N7I2PR5KZRFGPQF5BJ
SPONSOR_SECRET=<sponsor secret seed>
DISTRIBUTION_SECRET=<distribution secret seed>
RELAYER_SECRET=<contract relayer secret seed>
CONTRACT_ADMIN_SECRET=<contract admin secret seed>
STARTING_BALANCE=1.5
TRUSTLINE_LIMIT=1000000000
FEE_BUMP_MULTIPLIER=10
TRANSACTION_TIMEOUT_SECONDS=60
ENABLE_ADD_MONEY=true
ADD_MONEY_AMOUNT=100
MAX_ADD_MONEY_AMOUNT=1000
ADD_MONEY_COOLDOWN_MS=86400000
MAX_PAYMENT_AMOUNT=100000
IDEMPOTENCY_TTL_MS=600000
RELAYER_AUTH_REQUIRED=false
SUPABASE_URL=
SUPABASE_SERVICE_ROLE_KEY=
SUPABASE_JWT_SECRET=
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX_REQUESTS=100
LOW_XLM_THRESHOLD=5
LOW_CPINR_THRESHOLD=1000
ALERT_WEBHOOK_URL=
Start:
npm startHealth:
http://localhost:3000/health
Healthy Add Money requires:
{
"status": "healthy",
"lowXlm": false,
"lowAsset": false,
"distributionCpinrBalance": "1000000000.0000000"
}If distributionCpinrBalance is 0, Add Money will fail even if the relayer status is healthy.
For deployed or authenticated relayer requests, use one of these auth setups:
- Recommended now: set
RELAYER_AUTH_REQUIRED=true,SUPABASE_URL, andSUPABASE_SERVICE_ROLE_KEY. The relayer verifies the app's Supabase access token through Supabase Auth and also uses the service-role key to persist Add Money claim cooldowns. - Legacy HS256 only: set
RELAYER_AUTH_REQUIRED=trueandSUPABASE_JWT_SECRETif your Supabase project still issues HS256 JWTs. - MVP testing only: set
RELAYER_AUTH_REQUIRED=false. This bypasses relayer auth and should not be used for public production.
cd App
cp .env.example .envMinimum env:
EXPO_PUBLIC_SUPABASE_URL=<your Supabase project URL>
EXPO_PUBLIC_SUPABASE_ANON_KEY=<your Supabase anon key>
EXPO_PUBLIC_STELLAR_NETWORK=testnet
EXPO_PUBLIC_STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
EXPO_PUBLIC_STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
EXPO_PUBLIC_STELLAR_BASE_FEE=100
EXPO_PUBLIC_STELLAR_EXPLORER_URL=https://stellar.expert/explorer/testnet
EXPO_PUBLIC_CPINR_ASSET_CODE=CPINR
EXPO_PUBLIC_CPINR_ASSET_ISSUER=GA2SFZ4GJVMLPULSJMTY7RMIOPQD5W5JGTDSD3N7I2PR5KZRFGPQF5BJ
EXPO_PUBLIC_STELLAR_RELAYER_URL=http://<your computer LAN IP>:3000
EXPO_PUBLIC_PILOT_MODE=true
EXPO_PUBLIC_PILOT_CREDIT_NAME=C-Pay pilot credits
EXPO_PUBLIC_PILOT_CREDIT_UNIT=credits
EXPO_PUBLIC_PILOT_CREDIT_SYMBOL=Cr
EXPO_PUBLIC_PILOT_ACCESS_CODE=
EXPO_PUBLIC_DEV_MODE=false
# Legacy/dev-only; the active MVP login screen uses email OTP
EXPO_PUBLIC_DEV_PHONE=+911234567890
EXPO_PUBLIC_DEV_OTP=123456
For your current Wi-Fi output, the phone-reachable local relayer URL is:
http://172.29.78.86:3000
Use it in App/.env:
EXPO_PUBLIC_STELLAR_RELAYER_URL=http://172.29.78.86:3000
Restart Expo after changing env:
npx expo start --clear| Variable | Required | Description |
|---|---|---|
EXPO_PUBLIC_SUPABASE_URL |
Yes | Supabase project URL |
EXPO_PUBLIC_SUPABASE_ANON_KEY |
Yes | Supabase anon/publishable key |
EXPO_PUBLIC_STELLAR_NETWORK |
Yes | testnet or public |
EXPO_PUBLIC_STELLAR_HORIZON_URL |
Yes | Stellar Horizon endpoint |
EXPO_PUBLIC_STELLAR_NETWORK_PASSPHRASE |
Yes | Stellar passphrase |
EXPO_PUBLIC_STELLAR_BASE_FEE |
Yes | Base fee in stroops |
EXPO_PUBLIC_STELLAR_EXPLORER_URL |
Yes | Stellar explorer base URL |
EXPO_PUBLIC_CPINR_ASSET_CODE |
Yes | CPINR |
EXPO_PUBLIC_CPINR_ASSET_ISSUER |
Yes | CPINR issuer public key |
EXPO_PUBLIC_STELLAR_RELAYER_URL |
Yes for real device/builds | Relayer URL reachable from the app |
EXPO_PUBLIC_PILOT_MODE |
Optional | Keep true for closed-pilot/test-credit UX |
EXPO_PUBLIC_PILOT_CREDIT_NAME |
Optional | User-facing pilot credit name |
EXPO_PUBLIC_PILOT_CREDIT_UNIT |
Optional | User-facing unit label, defaults to credits |
EXPO_PUBLIC_PILOT_CREDIT_SYMBOL |
Optional | Compact balance symbol, defaults to Cr |
EXPO_PUBLIC_PILOT_ACCESS_CODE |
Optional | Soft invite gate shown before OTP; not a backend secret |
EXPO_PUBLIC_DEV_MODE |
Optional | Development mode flag |
EXPO_PUBLIC_DEV_PHONE |
Optional | Legacy/dev-only fallback phone; not used by the active email OTP screen |
EXPO_PUBLIC_DEV_OTP |
Optional | Legacy/dev-only fallback OTP; not used by the active email OTP screen |
| Variable | Required | Description |
|---|---|---|
PORT |
No | Defaults to 3000 |
CORS_ORIGIN |
No | Use * locally, restrict in production |
STELLAR_NETWORK |
Yes | testnet or public |
STELLAR_HORIZON_URL |
Yes | Stellar Horizon endpoint |
STELLAR_NETWORK_PASSPHRASE |
Yes | Stellar network passphrase |
CPINR_ASSET_CODE |
Yes | CPINR |
CPINR_ASSET_ISSUER |
Yes | CPINR issuer public key |
SPONSOR_SECRET |
Yes | Sponsor account secret seed |
DISTRIBUTION_SECRET |
Yes | Distribution account secret seed |
SOROBAN_RPC_URL |
Contract flow | Soroban RPC endpoint |
TOKEN_CONTRACT_ID |
Contract flow | Stellar Asset Contract ID for CPINR |
CPAY_CONTRACT_ID |
Contract flow | Deployed C-Pay payments contract ID |
CONTRACT_FLOW_ENABLED |
No | Enables merchant payment intent flow when contract env is present |
CONTRACT_INTENT_TTL_SECONDS |
No | Payment intent expiry window, defaults to 600 seconds |
RELAYER_SECRET |
Contract confirmation | Secret seed matching the contract relayer public key |
CONTRACT_ADMIN_SECRET |
Merchant sync | Secret seed matching the contract admin public key |
STARTING_BALANCE |
Yes | XLM for sponsored user account creation |
TRUSTLINE_LIMIT |
Yes | CPINR trustline limit |
FEE_BUMP_MULTIPLIER |
Yes | Fee-bump max fee multiplier |
TRANSACTION_TIMEOUT_SECONDS |
Yes | Stellar transaction timeout |
ENABLE_ADD_MONEY |
No | Defaults to enabled on testnet and disabled on public |
ADD_MONEY_AMOUNT |
Yes | Default Add Money amount |
MAX_ADD_MONEY_AMOUNT |
Yes | Maximum Add Money API amount |
ADD_MONEY_COOLDOWN_MS |
Yes | Per-account Add Money cooldown |
MAX_PAYMENT_AMOUNT |
Yes | Maximum payment amount |
IDEMPOTENCY_TTL_MS |
Yes | Duplicate request cache lifetime |
RELAYER_AUTH_REQUIRED |
No | Defaults to true on public network |
SUPABASE_URL |
Recommended when auth/persistence is enabled | Supabase project URL for Auth API verification and REST persistence |
SUPABASE_SERVICE_ROLE_KEY |
Recommended when auth/persistence is enabled | Server-only key for Supabase Auth API verification and Add Money persistence; never place this in the app |
SUPABASE_JWT_SECRET |
Legacy HS256 auth only | Verifies older HS256 Supabase access tokens when Auth API verification is not used |
RATE_LIMIT_WINDOW_MS |
Yes | Rate limit window |
RATE_LIMIT_MAX_REQUESTS |
Yes | Rate limit count |
LOW_XLM_THRESHOLD |
Yes | Sponsor XLM warning threshold |
LOW_CPINR_THRESHOLD |
Yes | Distribution CPINR warning threshold |
ALERT_WEBHOOK_URL |
Optional | Low-balance alert webhook |
| Variable | Required | Description |
|---|---|---|
STELLAR_NETWORK |
Yes | testnet or public |
STELLAR_HORIZON_URL |
Yes | Horizon endpoint |
STELLAR_NETWORK_PASSPHRASE |
Yes | Network passphrase |
SOROBAN_RPC_URL |
Deploy | Soroban RPC URL |
SOROBAN_NETWORK_PASSPHRASE |
Deploy | Soroban passphrase |
STELLAR_CLI_NETWORK |
Deploy | Stellar CLI network alias |
STELLAR_CLI_SOURCE_ACCOUNT |
Deploy | CLI identity such as cpay-deployer |
ASSET_CODE |
Yes | CPINR |
ASSET_ISSUER_PUBLIC_KEY |
Yes | Issuer public key |
ASSET_DISTRIBUTION_PUBLIC_KEY |
Setup | Distribution public key |
ASSET_ISSUER_SECRET |
Testnet setup | Issuer secret seed |
ASSET_DISTRIBUTION_SECRET |
Testnet setup | Distribution secret seed |
CONTRACT_ADMIN_PUBLIC_KEY |
Deploy | Contract admin public key |
RELAYER_PUBLIC_KEY |
Deploy | Contract relayer public key |
TOKEN_CONTRACT_ID |
Optional | Existing Stellar Asset Contract ID |
CPAY_CONTRACT_ID |
Optional | Existing C-Pay contract ID |
INITIAL_SUPPLY |
Setup | CPINR amount issued to distribution |
TRUSTLINE_LIMIT |
Setup | Distribution trustline limit |
LOCK_ISSUER_AFTER_SETUP |
Optional | Lock issuer master key after setup |
Onboarding & Auth
SplashScreenOnboardingScreenPhoneVerificationScreenCreatePINScreenConfirmPINScreenProfileSetupScreenCloudBackupSetupScreenBiometricSetupScreenRestoreWalletScreenLoginScreenForgotPINScreenChangePINScreen
Payments & Wallet
HomeScreenSendMoneyScreenScanScreenPaymentConfirmScreenPaymentProcessingScreenPaymentSuccessScreenPaymentFailureScreenTransactionHistoryScreenQRGeneratorScreenProfileScreen
Merchant
MerchantRegistrationScreenMerchantDashboardScreenMerchantQRGeneratorScreenMerchantGlobalQRScreenMerchantTransactionsScreen
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/ |
Service information |
GET |
/health |
Health and inventory |
GET |
/account/:accountId/status |
Account and trustline readiness |
GET |
/account/:accountId/balance |
CPINR and XLM balance |
POST |
/accounts/prepare |
Build sponsored setup transaction |
POST |
/accounts/submit |
Submit signed setup transaction |
GET |
/contract/config |
Read deployed C-Pay contract config |
POST |
/contract/merchants/register |
Sync merchant ID and account to Soroban |
POST |
/payments/intents/prepare |
Build user-signed contract payment intent transaction |
POST |
/payments/intents/submit |
Submit signed contract payment intent transaction |
POST |
/payments/submit |
Validate and submit fee-bump payment, then confirm contract intent when supplied |
POST |
/add-money |
Send CPINR from distribution |
GET |
/tx/:hash |
Transaction status |
| Function | Purpose |
|---|---|
__constructor |
Initialize admin, token, relayer |
config |
Read contract config |
set_admin |
Rotate admin |
set_token |
Update token contract |
set_relayer |
Rotate relayer |
set_paused |
Pause or unpause contract workflow |
register_merchant |
Add merchant account |
set_merchant_account |
Rotate merchant account without overwriting registration |
set_merchant_active |
Enable or disable merchant |
merchant |
Read merchant record |
create_intent |
Create payment intent with bounded expiry |
confirm_intent |
Relayer confirms payment hash |
cancel_intent |
Payer cancels intent |
intent |
Read intent |
extend_ttl |
Extend instance TTL |
| Layer | Technology | Purpose |
|---|---|---|
| Mobile | Expo, React Native, TypeScript | Android/iOS app experience |
| Wallet | @stellar/stellar-base, SecureStore, noble crypto | Stellar keypair, local signing, encrypted storage, cloud-backup encryption |
| Backend | Node.js, Express, @stellar/stellar-sdk | Relayer, fee bumps, Add Money, sponsored setup |
| Blockchain | Stellar testnet, Horizon, Soroban | CPINR balances, transactions, payment-intent contract |
| Contract | Rust, soroban-sdk | Merchant registry and payment intent state |
| Database | Supabase Postgres | Auth-linked users, merchants, QR codes, transaction records, encrypted wallet backups |
6-digit PIN entered by user
β
Stellar keypair generated on device
β
Secret encrypted with XChaCha20-Poly1305
β
PIN verifier stored separately
β
Encrypted wallet saved in SecureStore
Recovery password entered by user
β
Rules checked: 12+ chars, uppercase, number, special character
β
PBKDF2-SHA256 derives a 32-byte key with 60000 iterations
β
Stellar secret is encrypted with XChaCha20-Poly1305
β
Supabase wallet_backups stores salt, nonce, ciphertext, kdf metadata
The recovery password is never stored. Supabase stores only encrypted ciphertext and metadata needed to derive the key again during restore.
verified email handle + wallet fingerprint
β
user@cpayk8f3qz
The C-Pay ID is for display and lookup. Stellar payments still settle to real Stellar account IDs.
STARTING_BALANCE=1.5
TRUSTLINE_LIMIT=1000000000
ADD_MONEY_AMOUNT=100
MAX_ADD_MONEY_AMOUNT=1000
ADD_MONEY_COOLDOWN_MS=86400000
MAX_PAYMENT_AMOUNT=100000
These policy values are backend .env values used by relayer-service/server.js, not Rust contract constants.
| Item | Cost | Notes |
|---|---|---|
| Stellar testnet XLM | Free | Fund test accounts with Friendbot or stellar keys generate --fund |
| CPINR test asset | Free | Issued by the testnet issuer account |
| Soroban testnet deployment | Free testnet funds | Uses Stellar CLI deployer identity |
| Supabase local testing | Free tier possible | Depends on project usage |
| Expo development | Free locally | EAS builds depend on Expo account limits |
| Relayer local run | Free | Runs on your machine on port 3000 |
| Item | Cost Driver |
|---|---|
| Stellar public network | Real XLM reserves and transaction fees |
| Relayer hosting | Server/container hosting and HTTPS |
| Supabase | Database/storage/auth usage |
| Email OTP | Supabase Auth email usage and configured SMTP, if custom SMTP is used |
| SMS OTP future | SMS provider cost through Supabase phone auth when Twilio/SMS is enabled later |
| Monitoring | Logs, alerts, uptime checks |
| Custody/security | Secret management, multisig, operational process |
- Stellar secret is generated on device.
- Stellar secret is encrypted before storage.
- Raw PIN is not persisted in AsyncStorage.
- PIN verifier uses PBKDF2-SHA256.
- Wallet encryption uses XChaCha20-Poly1305.
- Cloud wallet backup uses a separate recovery-password-derived key.
- Cloud backup KDF uses PBKDF2-SHA256 with 60000 iterations.
- Cloud backup stores ciphertext, salt, nonce, and metadata in Supabase, not the recovery password.
- Biometric backup is optional and device-local.
- Sign out clears the in-memory PIN session.
SPONSOR_SECRETandDISTRIBUTION_SECRETstay in relayer infrastructure only.- Relayer validates signed payment XDR before submission.
- Relayer only accepts the configured CPINR asset.
- Relayer rejects invalid accounts, invalid XDR, and over-limit amounts.
- Express rate limiting protects public endpoints.
- When enabled, relayer auth verifies Supabase access tokens before protected requests.
SUPABASE_SERVICE_ROLE_KEYis server-only and is used by the relayer for Auth API verification and Add Money claim persistence.- Low-balance health flags help detect sponsor/distribution inventory problems.
- Issuer secret should be moved to cold custody after setup.
- Contract admin should be protected with secure custody or multisig.
- Relayer account can confirm payment intents but should not be a user wallet.
- Production public network must use real custody and monitoring.
The README details above are tied to the current code paths:
| Area | Evidence in repo |
|---|---|
| Email OTP onboarding | App/src/screens/PhoneVerificationScreen.tsx uses sendLoginEmailOTP, verifyLoginEmailOTP, and an 8-digit OTP input. |
| Supabase email auth helper | App/src/services/auth.ts calls supabase.auth.signInWithOtp({ email }) and verifies with type: 'email'. |
| Local wallet encryption | App/src/services/wallet.ts uses PBKDF2-SHA256 and XChaCha20-Poly1305 before writing the wallet to SecureStore. |
| Cloud backup encryption | App/src/services/cloudWalletBackup.ts uses CLOUD_BACKUP_KDF_ITERATIONS = 60000, pbkdf2-sha256, xchacha20-poly1305, random salt, random nonce, and Supabase wallet_backups. |
| Recovery password rules | App/src/services/cloudWalletBackup.ts checks length, uppercase, number, and special-character rules; CloudBackupSetupScreen shows them inline. |
| Restore after data loss | App/src/screens/RestoreWalletScreen.tsx restores the encrypted cloud backup, asks for a new local PIN, and recreates the local wallet. |
| Merchant restore | App/src/services/merchant.ts calls get_own_merchant_by_wallet; merchant dashboard/QR/transactions reload merchant state by restored wallet address. |
| Supabase schema | App/supabase_schema.sql defines email, auth_user_id, wallet_backups, add_money_claims, RLS policies, and merchant recovery RPCs. |
| Relayer auth and persistence | relayer-service/server.js verifies Supabase bearer tokens and persists Add Money claims through Supabase REST when service-role env is configured. |
| Production APK/iOS build config | App/eas.json production profile builds Android APK and iOS device artifacts; App/package.json exposes production build scripts. |
| Media permission fix | App/app.json configures expo-media-library with granularPermissions: ["photo"]. |
Recommended local verification commands after code changes:
cd App
npx expo install --check
npx tsc --noEmit
cd ../relayer-service
node --check server.jscd Blockchain
npm test
npm run create:keypairs
npm run setup:testnet
npm run contract:build
npm run deploy:contractcd relayer-service
npm start
node test-relayer.js
curl http://localhost:3000/healthcd App
npm start
npx expo start --clear
npx tsc --noEmitip addr show wlan0Use:
http://<your laptop LAN IP>:3000/health
For your shown Wi-Fi IP:
http://172.29.78.86:3000/health
Stellar CLI says: Failed to find config identity for cpay-deployer
Create and fund the CLI identity:
stellar keys generate cpay-deployer --fundThen rerun:
cd Blockchain
npm run deploy:contractDeploy says optimized wasm file does not exist
The deploy script checks both:
target/stellar/cpay_payments.optimized.wasmtarget/stellar/cpay_payments.wasm
Rebuild from the latest code:
cd Blockchain
npm run contract:build
npm run deploy:contractBrowser shows Cannot GET
Use:
http://localhost:3000/health
The current relayer also returns service information at /. If / still shows Cannot GET, restart the relayer so the latest server.js is running.
Expo phone app shows Network request failed
Most likely the phone cannot reach the relayer URL.
Check:
- Phone and laptop are on the same Wi-Fi.
- Relayer is running on port
3000. - Phone browser can open
http://<LAN-IP>:3000/health. - Firewall allows port
3000. App/.envusesEXPO_PUBLIC_STELLAR_RELAYER_URL.- Expo was restarted after env changes.
For a real phone, avoid localhost. Use your laptop IP, for example:
EXPO_PUBLIC_STELLAR_RELAYER_URL=http://172.29.78.86:3000
Add Money fails while health says healthy
status: "healthy" means the process can run and read Stellar. Add Money also needs CPINR inventory.
Check:
distributionCpinrBalancelowAssetsponsorXlmBalancelowXlm
If distributionCpinrBalance is 0, issue CPINR to the distribution account or run the testnet asset setup with the distribution account used by the relayer.
Add Money says Unsupported authentication token
The app sends the current Supabase access token to the relayer. This error means the relayer could not verify that token.
Check:
- User completed email OTP login and has a current Supabase session.
- The deployed relayer has
RELAYER_AUTH_REQUIRED=true. - Preferred config is set on the relayer:
SUPABASE_URLandSUPABASE_SERVICE_ROLE_KEY. - If you use old HS256 JWT verification,
SUPABASE_JWT_SECRETmatches the Supabase project. - Relayer was restarted after env changes.
/healthshowsauthApiConfigured: truewhen using the Supabase Auth API path.
For MVP testing only, RELAYER_AUTH_REQUIRED=false bypasses this check.
Email verification code does not arrive
The current MVP login uses Supabase email OTP, not phone OTP.
Check:
- Supabase Auth email provider is enabled.
- The project email template sends the OTP token, not only a magic-link URL.
- The app's OTP input expects 8 digits, so Supabase Auth should be configured to send 8-digit OTP codes.
EXPO_PUBLIC_SUPABASE_URLandEXPO_PUBLIC_SUPABASE_ANON_KEYpoint to the same Supabase project where the SQL schema was run.- Spam/junk folder and Supabase Auth logs.
- Expo was restarted after env changes.
After clearing app data, profile looks new
AsyncStorage and SecureStore are local app data. Clearing app data removes the local PIN verifier, local profile cache, and local encrypted wallet. The future-proof path is the encrypted cloud backup:
- Verify the same email with Supabase OTP.
- Enter the recovery password created on
CloudBackupSetupScreen. - Create a new local 6-digit PIN.
- The app restores the Stellar wallet, then reloads profile and merchant rows from Supabase.
If the recovery password was never created or is lost, the cloud backup cannot be decrypted because the password is not stored by the app or Supabase.
QR download media-library error in Expo Go
Expo Go cannot provide every production Android media-library permission on newer Android versions. The app config already requests photo-only access with:
"granularPermissions": ["photo"]Build and test a development or production build:
cd App
npm run build:android:production-apkBalance is always zero
Check:
EXPO_PUBLIC_CPINR_ASSET_ISSUERequalsGA2SFZ4GJVMLPULSJMTY7RMIOPQD5W5JGTDSD3N7I2PR5KZRFGPQF5BJ.- User account exists on Stellar.
- User account has a CPINR trustline.
- Relayer
/account/<wallet>/balancereturns a CPINR balance. - Expo was restarted with
npx expo start --clear.
Phone OTP is missing from the screen
That is expected for the MVP. The active verification path is Supabase email OTP. Phone-number columns and helper functions remain in the codebase so phone OTP can be enabled later after Twilio/SMS provider setup.
- Deploy the relayer behind HTTPS before distributing builds.
- Set
EXPO_PUBLIC_STELLAR_RELAYER_URLto the deployed HTTPS backend URL for EAS builds. - Store relayer secrets in infrastructure secrets, not in source files.
- Restrict
CORS_ORIGIN. - Set
RELAYER_AUTH_REQUIRED=truefor production/public-network relayer deployments. - Prefer
SUPABASE_URLplusSUPABASE_SERVICE_ROLE_KEYon the relayer for Supabase Auth API token verification and Add Money claim persistence. - Use
SUPABASE_JWT_SECRETonly when your Supabase project still uses legacy HS256 JWT verification. - Keep
ENABLE_ADD_MONEY=falseon public network unless you have a real abuse-resistant funding policy. - Monitor sponsor XLM and distribution CPINR.
- Keep issuer/admin secrets offline or protected by multisig.
- Apply
App/supabase_schema.sqlafter this update to replace the old permissive Supabase RLS policies with user-scoped policies and limited lookup RPCs. - Keep phone OTP disabled until an SMS provider such as Twilio is configured; email OTP is the current production-pilot path.
- Store and rotate EAS build env values in EAS/project secrets when moving beyond internal testing.
- Use a reliable public-network Horizon/Soroban RPC provider for production.
- Update README,
.envfiles, app config, and EAS env after redeploying contracts.
- β Expo app onboarding, PIN, biometric, profile, wallet storage
- β Supabase email OTP onboarding with phone OTP paused for future SMS provider setup
- β Encrypted cloud wallet backup and restore after app data loss
- β CPINR issued asset on Stellar testnet
- β Sponsored account and trustline setup
- β Add Money through relayer distribution account
- β Fee-bump payment submission
- β Merchant screens and QR flows
- β Merchant profile restore after wallet recovery
- β Soroban payment-intent contract deployment
- β Backend API for contract-backed merchant payment intents
- β Merchant registration sync to Soroban
- β Relayer confirmation of contract intents after Stellar payment submission
- β³ Better relayer inventory dashboard
- β User-scoped Supabase RLS baseline
- β³ HTTPS relayer deployment
- β³ Secret rotation and custody runbook
- β³ Monitoring and alerting
- β³ Public-network migration plan
See CONTRIBUTING.md for setup, checks, PR expectations, UX guidelines, and security rules.
- Keep mobile app secrets out of
App/.env. - Keep Stellar
S...secret seeds out of committed docs and source. - Update
Blockchain/contract-ids.jsonafter contract redeployments. - Update this README whenever network, issuer, contract, or relayer details change.
- Run the relevant checks before sharing a build.
C-Pay: UPI-like payments on Stellar
Made for simple CPINR payments, sponsored setup, QR flows, and merchant-ready Stellar UX.
















