Skip to content

soumen0818/C-Pay

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

52 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

C-Pay logo

C-Pay

UPI for Stellar - Making Blockchain Payments Simple

React Native Expo Stellar Soroban TypeScript License

Making Stellar payments as simple as scanning a QR code
No crypto knowledge required

Download APK Demo Video Give Feedback Feedback Sheet


πŸ“‹ Table of Contents

Click to expand

🎯 Overview

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.

Why C-Pay?

Traditional Crypto Wallets C-Pay

❌ Manual wallet address handling
❌ Seed phrases exposed to users
❌ Users pay network fees directly
❌ Trustlines are confusing
❌ Merchant flows are separate
❌ Blockchain concepts appear in the UX

βœ… Email OTP onboarding now, phone OTP ready for a future SMS provider
βœ… 6-digit PIN and optional biometric unlock
βœ… Encrypted cloud wallet recovery after reinstall/cache loss
βœ… Sponsored Stellar account setup
βœ… Relayer handles fees and Add Money
βœ… C-Pay IDs and QR codes
βœ… UPI-like payment experience

Planned Feature Improvements

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.

πŸ“Š Current Project Snapshot

🌐 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

Closed Pilot Mode

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.


πŸ“± Download APK

Current Stellar Testnet Build

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-apk

For both Android and iOS production builds, run:

cd App
npm run build:production:all

The 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.


πŸ“ Feedback Responses

Want to try C-Pay and share feedback? Fill out the C-Pay feedback form.

Live response sheet: C-Pay feedback responses

Table 1: Pilot Users

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

Table 2: User Feedback Implementation

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.

Full Feedback Response Export

# 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.

πŸ“Έ App Screenshots

Get started screen
Get Started
Email input screen
Email OTP
PIN input screen
Create PIN
Restore backup screen
Restore Backup
Loading screen
Loading
Home screen
Home
Send screen
Send
Send money screen
Send Money
User QR screen
User QR
Merchant QR screen
Merchant QR
Merchant dashboard screen
Merchant Dashboard
Profile screen
Profile
Profile details screen
Profile Details
Transaction details screen
Transaction Details
Payment successful screen
Payment Successful
Failed payment screen
Failed Payment

🌐 Current Testnet Values

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 S must never be added to the mobile app or committed to source control.


πŸ’‘ Vision

Make Blockchain Payments Invisible

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.

The UPI Analogy

Banking Abstraction (UPI) Stellar Abstraction (C-Pay)

🏦 Bank account β†’ VPA
πŸ” Net banking β†’ UPI PIN
πŸ“‹ Account number β†’ QR code
⏰ Slow transfers β†’ Fast settlement
πŸͺ Separate POS β†’ Unified merchant QR

πŸ”‘ Stellar secret β†’ encrypted local wallet
πŸ” Secret signing β†’ PIN/biometric unlock
πŸ“ Wallet address β†’ C-Pay ID and QR
β›½ Network fees β†’ relayer fee-bump flow
πŸͺ Merchant registry β†’ C-Pay merchant mode


✨ Key Features

πŸ‘€ User Features

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.

πŸͺ Merchant Features

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.

🌐 Platform Features

  • πŸš€ 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_payments stores 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 - /health reports 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.

πŸ—οΈ Architecture

System Overview

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
Loading

User Workflow Architecture

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
Loading

Component Architecture

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

Data Flow

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

Database Schema

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_at

Run the schema from:

App/supabase_schema.sql

Important schema notes:

  • users.email is the current verified login address. users.phone_number stays for a future phone OTP/Twilio rollout.
  • wallet_backups stores only encrypted wallet material plus cryptographic metadata. It does not store the recovery password or plaintext Stellar secret.
  • wallet_backups is one row per Supabase auth.users.id, enforced by UNIQUE(auth_user_id).
  • add_money_claims is 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_keys is 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.

πŸ“ Project Structure

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

Quick Start

Prerequisites

node --version
npm --version
stellar version
rustup target add wasm32v1-none

Required tools:

  • Node.js 18 or newer
  • npm
  • Expo through npm start or npx 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

Install Dependencies

cd Blockchain
npm install

cd ../relayer-service
npm install

cd ../App
npm install

Run Locally

Terminal 1:

cd relayer-service
npm start

Terminal 2:

cd App
npx expo start --clear

Do not run:

npm expo start

expo is not an npm command. Use npm start from App/ or npx expo start.


πŸ” CI/CD

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.


🧭 Runbook

1. Supabase Setup

  1. Create a Supabase project.
  2. Copy the project URL into App/.env as EXPO_PUBLIC_SUPABASE_URL.
  3. Copy the anon/publishable key into App/.env as EXPO_PUBLIC_SUPABASE_ANON_KEY.
  4. Do not put the service-role key in the Expo app.
  5. Run the SQL in App/supabase_schema.sql.
  6. Enable Supabase email OTP for Auth. The app uses email OTP for onboarding/login and expects an 8-digit code in the UI.
  7. Add email to the users table by running the current schema if your project was created before the email-auth change.
  8. Keep phone auth/SMS disabled until the Twilio or other SMS subscription is ready. The phone column remains for future migration.
  9. For relayer persistence and token verification, put the service-role key only in the relayer environment as SUPABASE_SERVICE_ROLE_KEY.
  10. For local development only, set EXPO_PUBLIC_DEV_MODE=true if you are testing legacy dev-only auth helpers. Production/internal pilot builds should keep it false.

2. Blockchain Setup

cd Blockchain
cp .env.example .env
npm run create:keypairs

The keypair script prints:

  • ASSET_ISSUER_PUBLIC_KEY and ASSET_ISSUER_SECRET
  • ASSET_DISTRIBUTION_PUBLIC_KEY and ASSET_DISTRIBUTION_SECRET
  • CONTRACT_ADMIN_PUBLIC_KEY and CONTRACT_ADMIN_SECRET
  • RELAYER_PUBLIC_KEY and RELAYER_SECRET

Create the Stellar CLI deployer identity:

stellar keys generate cpay-deployer --fund
stellar keys public-key cpay-deployer

Testnet 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:testnet

Contract 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:contract

The deploy script writes:

Blockchain/contract-ids.json

3. Relayer Setup

cd relayer-service
cp .env.example .env

Minimum 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 start

Health:

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, and SUPABASE_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=true and SUPABASE_JWT_SECRET if 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.

4. Mobile App Setup

cd App
cp .env.example .env

Minimum 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

πŸ”§ Environment Reference

πŸ“± App Public Variables

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

🧾 Relayer Backend Variables

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

πŸ¦€ Blockchain Variables

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

🧩 Components

Mobile Screens

Onboarding & Auth
  • SplashScreen
  • OnboardingScreen
  • PhoneVerificationScreen
  • CreatePINScreen
  • ConfirmPINScreen
  • ProfileSetupScreen
  • CloudBackupSetupScreen
  • BiometricSetupScreen
  • RestoreWalletScreen
  • LoginScreen
  • ForgotPINScreen
  • ChangePINScreen
Payments & Wallet
  • HomeScreen
  • SendMoneyScreen
  • ScanScreen
  • PaymentConfirmScreen
  • PaymentProcessingScreen
  • PaymentSuccessScreen
  • PaymentFailureScreen
  • TransactionHistoryScreen
  • QRGeneratorScreen
  • ProfileScreen
Merchant
  • MerchantRegistrationScreen
  • MerchantDashboardScreen
  • MerchantQRGeneratorScreen
  • MerchantGlobalQRScreen
  • MerchantTransactionsScreen

Relayer Endpoints

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

Soroban Contract Functions

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

πŸ› οΈ Tech Stack

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

πŸ”„ How It Works

Wallet Creation

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

Cloud Wallet Backup

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.

C-Pay ID

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.

Relayer Policy

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.


πŸ’° Cost Breakdown

Local/Testnet

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

Production

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

πŸ” Security

Mobile

  • 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.

Backend

  • SPONSOR_SECRET and DISTRIBUTION_SECRET stay 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_KEY is 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.

Blockchain

  • 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.

βœ… Implementation Proof

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.js

πŸ§ͺ Useful Commands

Blockchain

cd Blockchain
npm test
npm run create:keypairs
npm run setup:testnet
npm run contract:build
npm run deploy:contract

Relayer

cd relayer-service
npm start
node test-relayer.js
curl http://localhost:3000/health

App

cd App
npm start
npx expo start --clear
npx tsc --noEmit

Phone URL

ip addr show wlan0

Use:

http://<your laptop LAN IP>:3000/health

For your shown Wi-Fi IP:

http://172.29.78.86:3000/health

🩺 Troubleshooting

Stellar CLI says: Failed to find config identity for cpay-deployer

Create and fund the CLI identity:

stellar keys generate cpay-deployer --fund

Then rerun:

cd Blockchain
npm run deploy:contract
Deploy says optimized wasm file does not exist

The deploy script checks both:

  • target/stellar/cpay_payments.optimized.wasm
  • target/stellar/cpay_payments.wasm

Rebuild from the latest code:

cd Blockchain
npm run contract:build
npm run deploy:contract
Browser 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/.env uses EXPO_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:

  • distributionCpinrBalance
  • lowAsset
  • sponsorXlmBalance
  • lowXlm

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_URL and SUPABASE_SERVICE_ROLE_KEY.
  • If you use old HS256 JWT verification, SUPABASE_JWT_SECRET matches the Supabase project.
  • Relayer was restarted after env changes.
  • /health shows authApiConfigured: true when 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_URL and EXPO_PUBLIC_SUPABASE_ANON_KEY point 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-apk
Balance is always zero

Check:

  • EXPO_PUBLIC_CPINR_ASSET_ISSUER equals GA2SFZ4GJVMLPULSJMTY7RMIOPQD5W5JGTDSD3N7I2PR5KZRFGPQF5BJ.
  • User account exists on Stellar.
  • User account has a CPINR trustline.
  • Relayer /account/<wallet>/balance returns 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.


🚒 Production Notes

  • Deploy the relayer behind HTTPS before distributing builds.
  • Set EXPO_PUBLIC_STELLAR_RELAYER_URL to 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=true for production/public-network relayer deployments.
  • Prefer SUPABASE_URL plus SUPABASE_SERVICE_ROLE_KEY on the relayer for Supabase Auth API token verification and Add Money claim persistence.
  • Use SUPABASE_JWT_SECRET only when your Supabase project still uses legacy HS256 JWT verification.
  • Keep ENABLE_ADD_MONEY=false on 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.sql after 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, .env files, app config, and EAS env after redeploying contracts.

πŸ—ΊοΈ Roadmap

Phase 1 - Current Stellar Testnet Rail

  • βœ… 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

Phase 2 - Backend Contract Integration

  • βœ… 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

Phase 3 - Production Readiness

  • βœ… User-scoped Supabase RLS baseline
  • ⏳ HTTPS relayer deployment
  • ⏳ Secret rotation and custody runbook
  • ⏳ Monitoring and alerting
  • ⏳ Public-network migration plan

🀝 Contributing

See CONTRIBUTING.md for setup, checks, PR expectations, UX guidelines, and security rules.

  1. Keep mobile app secrets out of App/.env.
  2. Keep Stellar S... secret seeds out of committed docs and source.
  3. Update Blockchain/contract-ids.json after contract redeployments.
  4. Update this README whenever network, issuer, contract, or relayer details change.
  5. 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.

About

UPI for Stellar - Making Blockchain Payments Simple

Topics

Resources

License

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors