Configuration
keys, settings, publishing.
Where each setting lives: build-time keys in .env, backend settings in functions/.env, and everything else in the admin panel, delivered to the app through Remote Config.
01Three places, one rule
| Where | What goes there | Change needs |
|---|---|---|
crypto_wallet/.env | Client API keys (Reown, 0x, 1inch, RPC providers…) | A new build — or Admin → System Config → Remote API Keys |
crypto_wallet/functions/.env + Secret Manager | Server secrets: store validation, Stripe, owner UID | Redeploying the functions |
| Admin panel → Firestore → Remote Config | Fee, prices, branding, chains, tokens, dApps, switches | Save + Publish to mobile app. No new build. |
Everything passed with --dart-define is compiled into the app and can be extracted from it. Put only client-side keys in .env and restrict each key in its provider dashboard (bundle ID, domain, rate limits). Real secrets never go into the app.
02App keys (.env)
cd crypto_wallet
cp .env.example .env
# every run and build then adds:
flutter run --dart-define-from-file=.env
| Variable | Purpose | Get it at |
|---|---|---|
REOWN_PROJECT_ID Required | WalletConnect pairing | cloud.reown.com |
ZEROX_API_KEY | 0x swap quotes on EVM chains. Spell it exactly like this. | dashboard.0x.org |
ONEINCH_API_KEY | 1inch swap quotes on EVM chains | portal.1inch.dev |
ALCHEMY_API_KEY | Main EVM RPC | alchemy.com |
HELIUS_API_KEY | Solana RPC and asset data | helius.xyz |
MORALIS_API_KEY | NFT metadata, prices, history | admin.moralis.io |
ETHERSCAN_API_KEY, BSCSCAN_API_KEY, POLYGONSCAN_API_KEY, ARBISCAN_API_KEY, OPTIMISM_ETHERSCAN_API_KEY, BASESCAN_API_KEY | Transaction history per chain | Each explorer's API page |
BIRDEYE_API_KEY | Optional Solana market data | birdeye.so |
COINGECKO_API_KEY | Optional. Public CoinGecko endpoints work without it. | coingecko.com/en/api |
TRANSAK_API_KEY | Buy crypto screen | Transak partner dashboard |
IAP_PRO_WEEKLY_ID | Store product ID of the weekly PRO subscription | You choose it (Earnings → PRO) |
IAP_PRO_MONTHLY_ID, IAP_PRO_ANNUAL_ID | Extra plans. Leave empty unless you sell them. |
Leave these empty. They are in .env.example but this version does not use them: TENDERLY_*, INFURA_API_KEY, QUICKNODE_*, OPENSEA_API_KEY, FCM_SERVER_KEY, MIXPANEL_TOKEN, AMPLITUDE_API_KEY, FORCE_ENABLE_*, FORCE_DEBUG_LOGGING, APP_ENV, FEE_WALLET_ADDRESS, FEE_BPS. The fee is set in the admin, not here. CLAUDE_API_KEY must never be in the app's .env; it is a backend secret.
Without keys
| Missing | What happens |
|---|---|
REOWN_PROJECT_ID | WalletConnect screens open but cannot connect. |
ZEROX_API_KEY | 0x is skipped; 1inch is tried. |
| Both swap keys | Swaps show indicative prices with a Simulated badge and cannot be executed on EVM chains. |
03Backend settings (functions/.env)
Read by the Cloud Functions at deploy time. Never shipped inside the app.
| Variable | Purpose | Where to get it |
|---|---|---|
APP_NAME | Name shown in authenticator apps for admin sign-in codes | Your choice |
ANDROID_PACKAGE_NAME | Your app ID. Also used for App Store calls, so keep iOS and Android IDs identical. | Your bundle ID |
PRO_WEEKLY_PRODUCT_ID, PRO_MONTHLY_PRODUCT_ID, PRO_ANNUAL_PRODUCT_ID | Store product IDs the backend accepts. Same values as IAP_PRO_*. | App Store Connect, Play Console |
APP_STORE_KEY_ID, APP_STORE_ISSUER_ID, APP_STORE_PRIVATE_KEY | Checks iOS purchases. The private key is the text of your .p8 file, in double quotes, line breaks written as \n. | App Store Connect → Users and Access → Integrations |
APPLE_SHARED_SECRET | Fallback for older iOS receipts | App Store Connect → your app |
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON | Checks Android purchases. The service-account JSON on one line. | Google Cloud → Service accounts, then invite it in Play Console |
STRIPE_SECRET_KEY | Web PRO checkout and customer portal | dashboard.stripe.com/apikeys |
STRIPE_WEEKLY_PRICE_ID, STRIPE_MONTHLY_PRICE_ID, STRIPE_ANNUAL_PRICE_ID | Stripe prices for the PRO plans | Stripe → Products |
WEBHOOK_SECRET | Signs the optional "new PRO subscriber" webhook. 16+ characters. | Make one: openssl rand -hex 32 |
| Secret (Secret Manager) | Purpose |
|---|---|
OWNER_UID | Firebase UID of the owner, who can always manage admin rights. |
CLAUDE_API_KEY | Anthropic key for the optional Portfolio Brain PRO feature. |
cd crypto_wallet
firebase functions:secrets:set OWNER_UID
firebase deploy --only functions # after every change to functions/.env or a secret
04Runtime config: how a change reaches phones
- SaveEach admin page has its own save button (Apply Fee Config, Save Branding…). Saving writes to Firestore (
app_config/runtime_admin_config) and updates the live/config.jsonat once. - PublishPublish to mobile app (bottom-right of every page) calls
publishAdminRemoteConfig, which updates theadmin_configvalue in Firebase Remote Config. - Users get it on the next startRelease builds fetch Remote Config at most once an hour; debug builds on every start. The
config.jsoncopy is refreshed in the background on each cold start.
To see a change on a test phone: publish, then fully close and reopen the app.
05Remote Config values
You normally change these through the admin pages. The table helps when you look at the JSON in Firebase console → Remote Config → admin_config.
| Key | Meaning | Admin page |
|---|---|---|
maintenance_mode, maintenance_message | Shows a maintenance screen instead of the wallet | Remote Config, System Config |
swap_enabled, bridge_enabled, buy_enabled, sell_enabled, send_enabled, walletconnect_enabled, discover_enabled, push_enabled | On/off switch per feature | Remote Config |
min_app_version | Force-update gate (x.y.z). Empty = off. | Remote Config |
announcement_banner, announcement_url | Banner text and HTTPS link inside the app | Remote Config, Campaigns |
fee_wallet_address, fee_bps | Where swap fees go and how large they are (100 bps = 1 %) | Monetization |
pro_fee_waiver | PRO users swap without your fee | Monetization |
pro_weekly_price_eur, pro_trial_days | PRO price shown in the app and trial days | Monetization, System Config |
pro_crypto_payment_* | Pay-PRO-in-crypto settings | System Config |
admin_chains, admin_tokens, admin_dapps, featured_tokens, default_home_tokens | Content lists pushed to the app | Chains, Tokens, DApps |
app_name, tagline, primary_color, logo_url, support_email, terms_url, privacy_url | Branding and legal links | Branding, System Config |
config_version | Goes up with each publish | Publish Config |
Editing the JSON by hand works, but the next publish from the admin overwrites it, and the admin checks addresses and ranges for you.
06Where data is stored
| Firestore collection | Contains |
|---|---|
app_config/runtime_admin_config | The full admin config; source of /config.json |
admin_config/* | Admin-only: on-ramp, remote API keys, IP allowlist |
chains, tokens, dapps, admin_nft_collections | Content you curate |
swap_config, branding/global | Swap routing, bridge fee, branding |
campaigns, banners, ab_flags, promo_codes, scheduled_campaigns, notification_templates | Marketing tools |
fee_events, users, premium_entitlements, pro_crypto_payments | Written by the app and functions; shown in Revenue, Users, Analytics |
admin_users, admin_audit_log, config_versions | Admins and roles, audit trail, config snapshots |
Who can read and write each collection is decided by crypto_wallet/firestore.rules.