AURA Wallet — Setup & Integration Guide

Self-custody multi-chain wallet: mobile app, backend/admin and native signer module.
Format: offline, self-contained HTML (open directly in any browser, no internet or build tools required) Print to PDF: use your browser's Print → Save as PDF for an offline PDF copy

1 Overview

AURA Wallet is a self-custody, multi-chain crypto wallet source-code product covering Ethereum, Base, BNB Chain, TRON, Solana and Bitcoin. The product is a monorepo with four parts that this guide walks through in order: the mobile app (React Native, iOS/Android), the backend and Admin Control Center (Next.js on Vercel + MongoDB), a small set of background workers (Vercel Cron + QStash), and the native signer module that holds private-key material outside JavaScript.

This document is written for a developer who is comfortable with React Native and Node.js tooling but has not seen this codebase before. Follow the sections in order the first time through.

2 What's Included

Mobile app source

Full React Native TypeScript source, native iOS and Android projects, all wallet screens (Portfolio, Send, Receive, Swap, DApp Browser, WalletConnect, Notifications, Settings, AURA Entity chat).

Backend & Admin

Next.js API routes for device auth, balances, prices, history, swap quotes, TRON gasless gating, remote config, and the full Admin Control Center UI.

Chain adapters

packages/chains: derivation paths, transaction building, decoding and fee logic shared between the app and backend for every supported network.

Native signer module

Real, hand-reviewed @aura/signer-native: BIP‑39/32/SLIP‑10 derivation, PIN-gated encrypted seed storage and transaction/message signing on both platforms. See Section 9 for the full API surface and implementation notes.

3 Architecture

The codebase follows a hexagonal architecture: domain logic knows nothing about specific chains or vendors, and everything chain- or vendor-specific sits behind an adapter.

repo/
├── app/               React Native app (iOS + Android)
│   └── src/           application (ports/use-cases) · infrastructure (adapters) · presentation (UI)
├── web/               Next.js backend (public API) + Admin Control Center
├── worker/            Vercel Cron handlers + QStash consumers (indexers, retries, price watcher)
├── packages/
│   ├── chains/        Chain adapters: derivation, tx building, decode — shared by app + web + worker
│   ├── domain/         Pure domain types (Asset, Tx, FeeQuote, Verdict…)
│   ├── shared/         i18n resources, constants, utils
│   └── signer-native/  Native signing module (Nitro Module, Kotlin/Swift) — see Section 9
└── spec/, docs/        Module specs and architecture decision records
InvariantWhat it means for you
Keys never enter JSAll key material lives in native code. JavaScript sends unsigned transaction bytes in and receives signatures out — never a private key or seed.
One signing pipelineSend screen, WalletConnect and the in-app DApp browser all route through the same decode → review → sign flow. There is no alternate "fast path" that skips review.
Read via backend, write directThe app reads balances/prices/history through your backend (cached, provider-backed). It broadcasts signed transactions directly to chain RPCs, not through your backend.
Fees are transparentPlatform commission is always shown as its own labeled line in every quote and confirmation screen — never folded into the displayed rate.

4 Prerequisites

ToolVersionUsed for
node≥ 20Everything
pnpm10.x (see packageManager in package.json)Monorepo package management
Xcodecurrent stable, iOS 17 SDK+iOS build (CocoaPods included)
Android Studio / JDK 17current stableAndroid build (minSdk 29)
MongoDBAtlas or self-hostedBackend persistence
Upstash RedisREST APINonce replay protection, rate limiting, challenge storage
Upstash QStashCron fan-out and background job delivery
Vercel accountRecommended hosting for web/ (Cron + serverless functions)

You will also want accounts with the third-party data/quote providers used by the backend: Moralis (EVM + Solana balances/history/prices), TronGrid (optional, higher rate limit), CoinGecko (optional, higher rate limit), Helius (Solana transaction history), 0x (EVM swap quotes), Jupiter (Solana swap quotes) and OneSignal (push notifications). Each is optional in the sense that the corresponding feature degrades gracefully without it — see the table in Section 6.

5 Quick Start

pnpm i                       # install all workspace packages (pnpm workspaces)
pnpm lint && pnpm typecheck   # sanity-check the checkout builds cleanly
pnpm test                    # unit tests across all packages

From here, set up the backend first (Section 6) — the mobile app needs a running API to talk to for anything beyond static screens.

6 Backend & Admin Setup

The backend lives in web/ — a Next.js app that serves the device-facing /api/v1/* routes and the /admin Admin Control Center from one deployment.

6.1 Local development

cd web
cp .env.example .env.local     # fill in the values described below
pnpm dev                       # pnpm --filter web dev, from the repo root

6.2 Environment variables

web/.env.example is the authoritative list with inline comments. The groups below summarize what each is for and what happens if it's left unset.

GroupVariablesRequired?Effect if unset
DatabaseMONGODB_URI, MONGODB_DB_NAMErequiredEvery device-, address- and data-scoped endpoint fails; /api/ready reports Mongo unconfigured.
RedisUPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKENrequiredAuth/rate limiting degrade; address-ownership challenges can be lost between serverless workers.
Background jobsQSTASH_PUBLISH_URL, QSTASH_TOKEN, WORKER_SECRETrequired/api/ready reports QStash unconfigured and returns 503 even if Mongo/Redis are healthy.
Balances/history/pricesMORALIS_API_KEYrequiredEvery call to /api/v1/balances, /api/v1/history, /api/v1/prices fails.
Tron / price fallbackTRONGRID_API_KEY, COINGECKO_API_KEYoptionalBoth providers still work unauthenticated at a lower rate limit if omitted.
Solana historyHELIUS_API_KEYrequired for SOL historySolana is the one chain whose history is not served by Moralis. Without this key, Solana history returns a clear "Helius API key" error.
Swap quotesZEROX_API_KEY (EVM), JUPITER_API_KEY (Solana)optionalOmitting either simply removes that provider's pairs from the swap asset catalog — not an error. TRON/SunSwap needs neither.
Push notificationsONESIGNAL_APP_ID, ONESIGNAL_REST_API_KEYoptionalNeeded only when push is enabled.
Device attestation (Android)GOOGLE_PLAY_INTEGRITY_PACKAGE_NAME, GOOGLE_PLAY_INTEGRITY_SERVICE_ACCOUNT_EMAIL, GOOGLE_PLAY_INTEGRITY_PRIVATE_KEYrequired for real Android device registrationAndroid device registration fails 503 attestation_not_configured unless the dev bypass below is on.
Dev-only bypassALLOW_DEV_ATTESTATION_BYPASSlocal dev onlyWhen exactly true, accepts any attestation token on any environment — never set this in production.
Fee vaultsETHEREUM_FEE_VAULT_ADDRESS, BASE_FEE_VAULT_ADDRESS, BNB_FEE_VAULT_ADDRESS, TRON_FEE_VAULT_ADDRESS, SOLANA_FEE_VAULT_ADDRESS, BITCOIN_FEE_VAULT_ADDRESSrequired for commissionPublic destination addresses (not private keys) that seed default per-chain fee policies on first run.
Admin bootstrapADMIN_USERNAME, ADMIN_EMAIL, ADMIN_DISPLAY_NAME, ADMIN_PASSWORD_HASH, ADMIN_TOTP_SECRET, ADMIN_TOTP_ENCRYPTION_KEY, ADMIN_ALLOWED_IPSrequiredSee Section 11 — these bootstrap the first Super Admin only, once.
Marketplace demo iframeADMIN_EMBEDDED_DEMOoptional, off by defaultSet exactly true only for a hosted marketplace demo that must run inside preview.codecanyon.net. It permits that frame origin and uses a SameSite=None; Secure admin session cookie. Leave unset/false for normal buyer deployments, which keep framing denied and SameSite=Strict.
Operator tokensCRON_SECRET, WORKER_SECRET, DEPLOYMENT_CHECK_TOKENrequiredProtect the cron entry point, worker delivery endpoint and deployment-verification endpoint respectively.
AI remote fallbackAI_REMOTE_ENABLED, AI_REMOTE_BASE_URL, AI_REMOTE_API_KEY, AI_REMOTE_MODEL, AI_REMOTE_TIMEOUT_MSoptional, off by defaultSee Section 10.

6.3 Generating admin secrets

ADMIN_PASSWORD_PLAINTEXT='replace-with-a-long-password' node web/scripts/create-admin-credentials.mjs
node -e "console.log(require('node:crypto').randomBytes(32).toString('base64url'))"   # ADMIN_TOTP_ENCRYPTION_KEY

Store the generated password hash and TOTP secret only in your deployment's secret manager — never commit the plaintext password. Enroll ADMIN_TOTP_SECRET in the operator's authenticator app before first login.

6.4 Deploying

  1. Push web/ to a Vercel project (or another Node host that supports Next.js route handlers and Vercel Cron-compatible scheduling).
  2. Set every variable from the table above for the Preview and Production environments.
  3. Deploy, then confirm web/vercel.json is detected so Cron is registered.
  4. Follow the verification checklist in Section 12 before pointing a mobile build at the deployment.

7 Background Workers

worker/ holds the Vercel Cron handlers and QStash consumers. Each job is stateless: it reads a cursor from MongoDB, processes one batch, and writes the cursor back — safe to re-run and safe to run concurrently.

JobCadence
TRON indexerevery 1 minute
Bitcoin indexerevery 1 minute
Undelegate / reclaim (TRON gasless)every 5 minutes
Price watcherevery 1 minute
Fee retryQStash-driven
Device garbage collectiondaily
Balance-refresh tiershourly / daily

No separate deployment step is required beyond deploying web/ with Cron and QStash configured (Section 6) — GET /api/cron/minutely is the single Vercel Cron entry point that fans out into QStash-delivered jobs against POST /api/workers.

8 Mobile App Setup

8.1 Environment

The app reads configuration via react-native-config. Create app/.env.dev and/or app/.env.prod with at least:

API_BASE_URL=https://your-backend-domain.example
API_TIMEOUT_MS=10000
WALLETCONNECT_PROJECT_ID=your-walletconnect-cloud-project-id
ONESIGNAL_APP_ID=your-onesignal-app-id

# Optional EVM RPC overrides — sane public defaults are used if omitted
ETHEREUM_RPC_URL=
BASE_RPC_URL=
BNB_RPC_URL=

API_BASE_URL must point at the backend you deployed in Section 6 — the app reads balances, prices and history through it, and registers each device against it.

8.2 Install

pnpm i                        # from the repo root, installs the whole workspace
cd app/ios && LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 pod install && cd ../..

8.3 Run in development

# from app/
pnpm ios:dev        # ENVFILE=.env.dev react-native run-ios
pnpm android:dev     # ENVFILE=.env.dev react-native run-android

8.4 Build a release package

# Android
pnpm apk:prod        # ENVFILE=.env.prod ./gradlew assembleRelease
pnpm aab:prod        # ENVFILE=.env.prod ./gradlew bundleRelease

# iOS
# Archive and export through Xcode (Product → Archive) using your own
# signing team and provisioning profiles — these are not included and
# must be created in your own Apple Developer account.
iOS requires SDK 17+ and the Android project targets minSdk 29 for marketplace compatibility. The optional on-device AI model still requires a sufficiently capable device; Android devices below API 33 or with under 4 GB RAM keep the deterministic parts of the AURA Entity but do not offer the on-device model — see Section 10.

9 Native Signer Module

packages/signer-native is a real, fully implemented, hand-reviewed native module — not a placeholder. Both Android and iOS have genuine BIP‑39/BIP‑32/SLIP‑10 derivation, PIN-gated encrypted seed storage (Android Keystore / iOS Keychain), and transaction/message signing for the secp256k1 and ed25519 curves used across every supported chain, built on proven crypto libraries (libsecp256k1, libsodium) rather than hand-written primitives. It is built as a Nitro Module so the interface (src/specs/AuraSigner.nitro.ts) is a normal, readable TypeScript contract even though the implementation is native Kotlin/Swift.

9.1 API surface

This is the exact contract the rest of the app integrates against:

hasSeed(): Promise<boolean>
createSeed(pin): Promise<string[]>        // mnemonic, returned once, for hold-to-reveal backup
importSeed(words, pin): Promise<void>
revealSeed(pin): Promise<string[]>        // backup screen only
getPublicKeys(requests): Promise<PublicKeyResult[]>
unlock(pin): Promise<void>
lock(): Promise<void>
sign(path, curve, digest): Promise<ArrayBuffer>
signMessage(path, curve, message): Promise<ArrayBuffer>
wipe(): Promise<void>

Every method is async. curve is one of secp256k1 or ed25519. The app never calls this module directly — it goes through the hexagonal port pattern at app/src/application/signer/port/in/signer.port.ts, which keeps the SACRED signing surface small and independently reviewable from ordinary UI/native glue.

9.2 Non-negotiable rules this module follows

  • Private keys and seeds never cross into JavaScript — JS sends unsigned bytes in, receives signatures out.
  • Use only reviewed, real cryptographic libraries (e.g. libsecp256k1, libsodium, @scure/*, @noble/*) — never hand-written or AI-generated primitives.
  • Never log seeds, private keys, or full addresses.
  • Seed reveal screens require hold-to-reveal plus screenshot/recording protection (FLAG_SECURE on Android, blur-on-snapshot on iOS).

9.3 Regenerating the Nitro glue

If you extend the interface, edit src/specs/AuraSigner.nitro.ts and regenerate the generated bindings:

pnpm --filter @aura/signer-native specs

10 AI Entity Configuration

The AURA Entity's AI-backed behavior is tiered, and only two tiers involve a language model at all — both optional. Tiers 0–2 (deterministic Send/Swap intent parsing, balance/history lookups, canned EN/VI explanations) never call a model.

10.1 Tier 3 — on-device model (optional)

A quantized Qwen 2.5 1.5B model, run fully on-device via react-native-executorch. Nothing is bundled at build time — the end user downloads it from Settings → Entity AI, and no wallet data leaves the device for this tier. Requires iOS 17+ / Android API 33+ and at least 4 GB RAM; on Android 29–32 the app keeps Tiers 0–2 and reports Tier 3 unsupported.

10.2 Tier 4 — remote fallback (optional, off by default)

Disabled in both the app and the backend until explicitly configured. To enable it, set on the backend:

AI_REMOTE_ENABLED=true
AI_REMOTE_BASE_URL=https://your-provider.example/v1   # must be HTTPS, OpenAI-compatible
AI_REMOTE_API_KEY=...
AI_REMOTE_MODEL=...
AI_REMOTE_TIMEOUT_MS=20000

The API key stays server-side and is never bundled into the mobile app. AI_REMOTE_BASE_URL is treated as an OpenAI-API-compatible base — bring any provider (OpenAI or a compatible self-hosted endpoint) that speaks that protocol; this product does not include or resell any third-party AI subscription. The user must also separately enable Tier 4 in Settings → Entity AI — an operator-side config alone does not turn it on for anyone.

Only a minimal, redacted context is ever sent for Tier 4: language, wallet label, asset/network/amount context, recent transaction metadata, and up to six prior text-only chat turns. Wallet addresses, counterparties, transaction hashes, device IDs, seed phrases, private keys and PINs are never sent, and the backend also rejects any address/hash/secret-looking text before it reaches the provider.

In every tier, the Entity can explain, navigate and pre-fill forms — never sign, approve, broadcast, or move funds on its own.

11 Admin Access & Roles

  1. Deploy with MongoDB healthy and every variable in the "Admin bootstrap" row of Section 6.2 set for Production.
  2. Call GET /api/deployment/verify with DEPLOYMENT_CHECK_TOKEN; confirm configuration.adminAuth is true.
  3. Open /admin and sign in with ADMIN_EMAIL (or the legacy ADMIN_USERNAME), the password behind ADMIN_PASSWORD_HASH, and the authenticator code from ADMIN_TOTP_SECRET.
  4. The first authenticated request creates the four system roles (Super Admin, Operations Admin, Security Admin, Viewer) and the initial Super Admin, if admin_users is empty.
  5. Confirm the bootstrapped account appears under /admin/access/users and the system roles under /admin/access/roles.
  6. Create at least one additional Super Admin, then treat the bootstrap environment values as historical — changing them afterwards does not modify the Mongo-backed user record.

All admin routes independently enforce IP allowlisting, TOTP, an HttpOnly session cookie, and same-origin mutation checks — front-end navigation visibility is a convenience, not the security boundary.

12 Deployment Verification

Run through this checklist after every backend deployment, before pointing a mobile build at it:

  1. GET /api/health → HTTP 200 with an x-request-id header (liveness only, no dependency checks).
  2. GET /api/ready → HTTP 200 with MongoDB, Redis and QStash all ok: true.
  3. GET /api/deployment/verify with Authorization: Bearer <DEPLOYMENT_CHECK_TOKEN> → HTTP 200, every configuration flag true.
  4. Trigger GET /api/cron/minutely with Authorization: Bearer <CRON_SECRET> → HTTP 202, three queued topics.
  5. Confirm QStash delivers to POST /api/workers, returns HTTP 202, and your logs show matching jobId/requestId values.
  6. Confirm unauthenticated calls to the cron, worker and deployment-verification endpoints return HTTP 401.

Runtime logs are single-line JSON with timestamp, level, service and event; keys that look like tokens, secrets, authorization headers, signatures, passwords or private keys are redacted recursively before logging.

13 Known Limitations

Documented honestly so you can plan around them before a production rollout:

  • TRON gasless delegation is gating-only. POST /api/v1/tron/delegate validates address ownership and daily energy caps and returns 202, but does not yet perform an on-chain stake+delegate transaction — the chain-adapter for that transaction type is not built. Do not surface a "gasless send succeeded" UI state from this response alone.
  • Third-party data providers are verified against realistic mocks, not live traffic, in the environment this was built in. Confirm behavior against your own real MORALIS_API_KEY, TRONGRID_API_KEY, HELIUS_API_KEY etc. before depending on it in production.
  • EVM networks are reported separately, never merged. The same asset held on Ethereum, Base and BNB Chain returns as three separate balance/history entries — by design, since each network keeps its own address ownership and signing context even though the underlying key is shared.

14 Support

For questions about this setup guide, the native signer module, or custom development, contact the seller through the channel listed on the CodeCanyon item page.