Architecture
what runs where.
One picture of the whole product: the app on your users' devices, your Firebase project, your admin panel and the outside services. Read it once before you install; most setup problems make sense after it.
01The big picture
Three parts are yours: the wallet app, the admin panel and one Firebase project. Everything else is an outside service that the app or the backend calls.
02What runs where
| Part | Runs on | Holds | Source |
|---|---|---|---|
| Wallet app | Your users' phones and browsers | Seed phrase and private keys, encrypted in device storage; a cached copy of your settings | crypto_wallet/lib/, key storage in lib/core/vault_service.dart |
| Admin panel | Any static web host (Firebase Hosting by default) | Nothing of its own. It reads and writes your Firestore and calls your functions. | crypto_wallet_admin/ |
| Cloud Functions | Your Firebase project, region europe-west1 | Server settings in functions/.env and two secrets in Secret Manager | crypto_wallet/functions/src/index.ts |
| Firestore | Your Firebase project | Settings, content lists, admins, fee records, PRO status, activity log | crypto_wallet/firestore.rules |
| Remote Config | Your Firebase project | One JSON value, admin_config, that every app reads | crypto_wallet/remoteconfig.template.json |
The wallet signs in to Firebase anonymously (lib/core/firebase/firebase_identity_service.dart). That anonymous account is used for push, fee records and PRO status. It is not a login your users see, and it has nothing to do with their wallet keys.
03Four flows to know
1 · A user creates a wallet
The app makes the seed phrase on the device and stores it encrypted with AES-256-GCM. The encryption key is held by the iOS Keychain or the Android Keystore. A browser has neither, so in the web build the user first sets a vault passphrase of at least 10 characters;
PBKDF2-HMAC-SHA256 with 600,000 iterations in the browser's Web Crypto derives 64 bytes from it, which encrypt the vault's AES key and wrap the key flutter_secure_storage keeps in the browser (lib/core/web_vault_passphrase.dart, details).
Nothing about the seed is sent to Firebase or to you. If a user loses the phone and the recovery phrase — or forgets the web vault passphrase and never wrote the phrase down — nobody can restore the wallet.
2 · You change a setting
- SaveThe admin page writes to Firestore (
app_config/runtime_admin_config). Your admin's/config.jsonserves that document straight away through thegetRuntimeConfigJsonfunction. - Publish to mobile appThe
publishAdminRemoteConfigfunction writes the same settings into the Remote Config valueadmin_config. It refuses a fee without a valid wallet and checks your role. - The app picks it upOn the next start (release builds fetch at most once an hour), or at once while the app is open, through Remote Config's live updates. If you built the app with
ADMIN_CONFIG_URL, it also downloadsconfig.jsonon each start.
3 · A user swaps
The app asks the aggregators for quotes directly: 0x and 1inch on EVM chains, Jupiter on Solana. If you set a fee, the app adds it to the quote request with your fee wallet as the recipient. The user signs on the device and the aggregator's contract pays your fee on-chain. Afterwards the app reports the swap to recordFeeEvent, so the admin can show revenue. The money never passes through Firebase.
4 · A user buys PRO
Apple or Google charges the user. The app sends the purchase proof to validatePremiumEntitlement, which checks it with the App Store or Google Play using your server credentials, then stores the PRO status in Firestore.
04Public or private?
Some places are readable by anyone who has your app. Never put a secret there.
| Place | Who can read it | Put secrets there? |
|---|---|---|
Remote Config admin_config | Every app install | No |
Firestore app_config/* and /config.json | Anyone, no sign-in needed (rule allow read: if true) | No |
crypto_wallet/.env (build-time keys) | Anyone who unpacks your app | No. Client keys only, restricted in each provider's dashboard. |
Firestore admin_users, admin_config/* (except onramp) | Signed-in admins | Admin data only |
functions/.env, Secret Manager | Your Cloud Functions and people with access to your Google Cloud project | Yes, this is where server secrets go |
Details, rotation and backups: Secrets & backups.