Self-custody crypto wallet for Android, Chrome, and the open multi-chain web.
Website · Google Play · Chrome Web Store · Quick Start · Security
Built with Rust, TypeScript, React, Capacitor, and a focus on secure multi-chain wallet UX.
- What is Oxidity Wallet?
- Repository layout
- Supported platforms
- Supported blockchains
- Quick start
- Technology stack
- Architecture
- Wallet frontend
- Backend API
- Market price API
- Security model
- Configuration
- Build, lint, and test commands
- Deployment
- Contributing
- Versioning and releases
- License
Oxidity Wallet is a self-custodial, multi-chain crypto wallet built as a monorepo.
It ships across multiple surfaces from the same core wallet codebase:
| Surface | Status | Location |
|---|---|---|
| Android app | Released | apps/wallet/android |
| Browser extension | Released | apps/wallet |
| Web wallet / PWA | Released | apps/wallet |
| Marketing site | Released | apps/site |
| Rust backend API | Production | crates/api |
| Market price API | Production | oxidity-price |
Private keys are created, encrypted, and used client-side. The backend provides chain data, transaction preparation, swap and bridge routing, price data, activity indexing, and operational APIs. It does not custody user funds.
This repository is designed to be:
- Publicly auditable
- Contributor-friendly
- Reproducible across local and CI builds
- Clear about security boundaries
- Practical for real wallet development, not only demo usage
Security warning: this is wallet software. Development builds can move real funds if connected to real keys and real networks. Use throwaway wallets and test funds when developing, testing, or reviewing changes.
oxidity-wallet/
├── Cargo.toml
├── Cargo.lock
├── package.json
├── package-lock.json
├── VERSION
├── CHANGELOG.md
├── LICENSE
├── NOTICE
├── README.md
│
├── apps/
│ ├── wallet/ # React wallet app, browser extension, Android shell
│ │ ├── src/
│ │ ├── tests/
│ │ ├── android/
│ │ ├── scripts/
│ │ ├── vite.config.ts
│ │ └── playwright.config.ts
│ │
│ └── site/ # Marketing site and public docs pages
│ ├── src/
│ └── vite.config.ts
│
├── crates/
│ ├── api/ # Rust backend API
│ │ ├── src/
│ │ └── migrations/
│ │
│ └── core/ # Shared Rust domain/common crate
│ └── src/
│
├── data/
│ ├── global_data.json # Chain, token, RPC, feature, and asset registry
│ ├── chains/ # Chain/native asset artwork
│ ├── tokens/ # Token artwork
│ └── generated/ # Generated registry reports
│
├── oxidity-price/ # Market price and OHLC API
│
├── deploy/
│ ├── nginx/ # nginx templates and render scripts
│ ├── cloudflared/ # Cloudflare Tunnel service files
│ ├── systemd/ # systemd service templates
│ └── rebuild-deploy.sh # Build and deployment pipeline
│
├── scripts/
│ ├── build/
│ ├── release/
│ └── dev/
│
└── .github/
├── workflows/
└── dependabot.yml
The wallet app, site, backend, deployment assets, generated registry data, and release tooling live together so security fixes and chain updates can land consistently across every delivery surface.
| Platform | Package / target | Notes |
|---|---|---|
| Android | io.oxidity.wallet |
Capacitor shell around the wallet frontend |
| Chrome Extension | Chrome Web Store | Browser-extension package generated from apps/wallet |
| Web PWA | wallet.oxidity.app |
Same wallet UI deployed as a web app |
| Marketing site | oxidity.app |
Public landing site, docs, legal pages, support pages |
| Backend API | 127.0.0.1:9555 in production behind nginx |
Rust Axum service |
| Price API | 127.0.0.1:8787 in production behind nginx |
Market price and OHLC service |
The source of truth is data/global_data.json.
Oxidity supports EVM and non-EVM chains through a shared registry model. Chain entries define RPC endpoints, feature flags, explorer links, wrapped-native assets, derivation paths, icons, default tokens, and wallet capabilities.
Examples of supported chains include:
- Monero
- Ethereum
- BNB Smart Chain
- Polygon
- Base
- Avalanche C-Chain
- Optimism
- Arbitrum One
- Solana
- Cardano
- Bitcoin
- XRP Ledger
- Polkadot
- Cosmos Hub
- TRON
- Sei
- Litecoin
- Dogecoin
- Fraxtal
- NEAR Protocol
- Ethereum Classic
- Bitcoin Cash
- Unichain
- Ethereum Sepolia
- Avalanche Fuji C-Chain
- BNB Smart Chain Testnet
Each chain can independently advertise capabilities such as:
- Portfolio
- Activity
- Send
- Receive
- Swap
- Bridge
- Buy
- NFT
- Stake
- WalletConnect
When adding or changing chain support, update the registry and run the registry validation scripts before opening a pull request.
cargo runThe backend binds to 127.0.0.1:9555 by default.
cd apps/wallet
npm install --legacy-peer-deps
npm run devThe wallet dev server runs on port 3000.
cd apps/site
npm install --legacy-peer-deps
npm run devThe site dev server runs on port 3001.
scripts/dev/public-readiness.shFor full setup, extension packaging, Android builds, and local environment details, see CONTRIBUTING.md.
| Technology | Purpose |
|---|---|
| Rust | Backend API and core services |
| Tokio | Async runtime |
| Axum | HTTP server and routing |
| Tower HTTP | Middleware, CORS, headers |
| SQLx | SQLite database access and migrations |
| Alloy | Ethereum JSON-RPC, ABI, and transaction primitives |
| Reqwest | Outbound HTTP clients |
| Serde | JSON serialization |
| Tracing | Structured logging |
| DashMap | Shared concurrent state |
| Thiserror / Anyhow | Error handling |
| bitcoin / k256 / ed25519-dalek / bech32 / bs58 / sha2 / blake2 / ripemd | Multi-chain crypto primitives |
| Technology | Purpose |
|---|---|
| React | UI framework |
| Vite | Build tool and dev server |
| TypeScript | Static typing |
| Tailwind CSS | Styling |
| Motion | UI animations |
| Zustand | Global wallet state |
| Ethers | EVM wallet, signing, encoding |
| Solana Web3.js | Solana support |
| Polkadot API / Keyring | Polkadot support |
| XRPL libraries | XRP Ledger support |
| CosmJS | Cosmos support |
| monero-ts | Web/PWA Monero key and wallet runtime |
| Reown WalletKit / WalletConnect | WalletConnect v2 |
| Capacitor | Android bridge |
| Capacitor Secure Storage | Native secure storage |
| Capacitor Biometric Auth | Native biometric unlock |
| Stripe JS | Onramp integration |
| Playwright | End-to-end tests |
| Vitest | Unit tests |
The marketing site uses React, Vite, TypeScript, Tailwind CSS, React Router, Motion, and Stripe JS.
| Tool | Purpose |
|---|---|
| nginx | Reverse proxy, TLS-facing routing, static file serving, security headers |
| systemd | Backend process supervision |
| Cloudflare Tunnel | Public ingress without exposing origin ports directly |
| GitHub Actions | CI, checks, and release workflows |
| Gradle | Android release builds |
| Dependabot | Dependency update automation |
Oxidity is split into three main layers:
Wallet UI
React, Zustand, Capacitor, Extension runtime
|
| HTTPS /api/*
|
Rust backend
Axum, SQLx, Alloy, registry, quote/swap/send preparation
|
| RPC / HTTP integrations
|
External services
RPC providers, explorers, Stripe, market-data providers, WalletConnect relay
Private-key operations remain client-side. The backend prepares and validates operations, but does not store seed phrases, private keys, or decrypted signing material.
The wallet app lives in apps/wallet.
It is shared by:
- Web wallet
- Android app
- Browser extension
The app uses a flat view stack managed through Zustand instead of maintaining separate routers for each surface. This keeps navigation predictable across browser, Android, extension popup, and PWA contexts.
| View | Purpose |
|---|---|
| Splash | Startup and initialization |
| Welcome | New user entry |
| Create wallet | Generate a new wallet |
| Import wallet | Import mnemonic or private key |
| Walkthrough | Onboarding flow |
| Main | Portfolio, tabs, activity, and actions |
| Lock screen | PIN and biometric unlock |
| Buy | Stripe Onramp |
| Token management | Add, hide, and manage assets |
| Token details | Chart, balance, activity, and actions |
| Send | Send flow |
| Bridge | Cross-chain bridge |
| Stake | Multi-chain staking |
| WalletConnect | dApp sessions |
| Extension request | Browser-extension approvals |
| Notifications | Notification settings |
| Receive | Receive address display |
| Receive QR | QR receive screen |
| Address book | Saved recipients |
| Add wallet | Additional accounts |
| Transaction details | Activity details |
| Advanced settings | Developer and debug options |
| Legal | Terms and privacy |
| Licenses | Open-source license attribution |
| Support | Help and feedback |
Global wallet state lives in apps/wallet/src/store/appStore.ts.
It tracks:
- Vault and lock state
- Active account
- Portfolio balances
- Chain catalog
- Token registry
- Activity history
- Current view stack
- Theme and fiat preferences
- WalletConnect state
- Notification preferences
- Experience mode
App-wide state belongs in the store. Pure business logic belongs in lib/. Reusable UI primitives belong in components/.
Wallet secrets are never stored in plaintext.
The wallet vault flow:
- A mnemonic or private key is created or imported client-side.
- The secret is encrypted with AES-256-GCM.
- The encryption key is derived using PBKDF2 with a random salt.
- The encrypted vault payload is persisted.
- On Android, secure storage and biometric unlock can be backed by native platform APIs.
- Native signing paths can keep decrypted signing material out of the JavaScript thread after setup.
Development warning: never use a real seed phrase or private key in local builds, test builds, browser devtools, screenshots, logs, or issue reports.
Address derivation is isolated in apps/wallet/src/lib/chainAddresses.ts.
| Chain family | Derivation model |
|---|---|
| EVM | Standard BIP-44 EVM derivation through Ethers |
| Solana | Ed25519 derivation |
| Bitcoin | Native SegWit derivation |
| TRON | EVM-compatible key encoded with TRON address format |
| XRP Ledger | XRPL keypair and address codec |
| Polkadot | Substrate-compatible keyring |
| Cosmos | BIP-44 Cosmos derivation and bech32 encoding |
WalletConnect v2 support is implemented in apps/wallet/src/features/walletconnect.
The service handles:
- Session proposals
- Sign requests
- EVM action preparation
- Request queues
- Deep links
- App links
- Session policies
- Approval UI handoff
WalletConnect approvals create per-origin policies that define allowed methods, expiry windows, and limits for supported value-bearing requests.
The extension runtime lives in apps/wallet/src/features/extension.
The extension injects an EVM-compatible provider and routes dApp requests into the wallet approval UI.
Supported request classes include:
eth_requestAccountseth_sendTransactioneth_signTransactionpersonal_signeth_signeth_signTypedData_v4
Approval flows must preserve clear user intent and must not sign or broadcast from stale, orphaned, duplicated, or background-restored requests.
Send safety is handled through layered client-side checks.
| Module | Purpose |
|---|---|
addressRisk.ts |
Detects burn addresses, self-sends, poisoning-like addresses, and malformed inputs |
preflightChecks.ts |
Checks chain-specific requirements such as memos, tags, reserves, and fee risk |
transactionSimulation.ts |
Builds a human-readable transaction summary before confirmation |
Warnings should be explicit, understandable, and visible before the user confirms the action.
Staking support lives in apps/wallet/src/lib/staking.ts and apps/wallet/src/views/StakeView.tsx.
Current staking models include:
| Protocol | Chain | Type |
|---|---|---|
| Lido | Ethereum | Liquid staking |
| Native delegation | Solana | Validator delegation |
| Native delegation | Cosmos | Validator delegation |
| Nomination | Polkadot | Validator nomination |
Accessibility helpers live in apps/wallet/src/lib/accessibility.ts.
The wallet should respect:
- Screen-reader announcements
- Reduced-motion preference
- High-contrast mode
- Clear focus states
- Tap targets suitable for mobile use
The backend lives in crates/api.
It is a Rust Axum service responsible for:
- App bootstrap data
- Network status
- Token catalog access
- Portfolio reads
- Price changes
- Swap preparation
- Bridge preparation
- Send preparation
- Signed transaction broadcast
- NFT lookups
- WalletConnect EVM preparation
- Monero node status and companion routes
- Reward eligibility and claim handling
- Activity history
- Telemetry middleware for opted-in clients
The backend defaults to:
127.0.0.1:9555
The main AppState contains:
- SQLite pool
- Shared outbound HTTP client
- Global settings
- API key configuration
- Token catalog index
- Lazy EVM runtimes
- Runtime initialization locks
- Prepared swaps
- Prepared bridges
- Reward rate-limit state
- Network-health cache
- Price-change cache
- Price-history cache
All API routes are mounted under /api.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/health |
Liveness probe |
| GET | /api/bootstrap |
App bootstrap metadata |
| GET | /api/networks |
Enabled networks and health snapshot |
| GET | /api/fiat/rates |
Fiat conversion rates |
| GET | /api/catalog |
Chain and token catalog |
| POST | /api/wallet/address |
Derive chain address for a wallet |
| GET | /api/market/price-changes |
Cached 24h market changes |
| POST | /api/market/track-token |
Track token price history |
| GET | /api/market/noki |
NOKI market dashboard |
| GET | /api/market/noki/{endpoint} |
NOKI market sub-endpoint |
| GET | /api/image-proxy |
Proxied remote token and NFT images |
| POST | /api/portfolio |
Balances and fiat values |
| POST | /api/onramp/session |
Stripe Onramp session |
| POST | /api/google/oauth/exchange |
Google OAuth code exchange |
| POST | /api/token/resolve |
Token lookup |
| POST | /api/token/details |
Token details and chart data |
| POST | /api/nft/details |
NFT details |
| POST | /api/nft/marketplace/collections |
NFT collection search |
| POST | /api/nft/marketplace/collection |
NFT collection details |
| POST | /api/quote-preview |
Fast swap quote preview |
| POST | /api/swap/prepare |
Prepare swap |
| POST | /api/swap/execute |
Execute prepared swap |
| POST | /api/bridge/quote |
Bridge quote |
| POST | /api/bridge/prepare |
Prepare bridge |
| POST | /api/bridge/execute |
Execute prepared bridge |
| POST | /api/walletconnect/evm/prepare |
Prepare WalletConnect EVM action |
| POST | /api/stake/prepare |
Prepare staking transaction |
| POST | /api/send/prepare |
Prepare unsigned send transaction |
| POST | /api/send/broadcast |
Broadcast signed send transaction |
| POST | /api/activity |
Wallet activity |
| POST | /api/nft/send/prepare |
Prepare NFT transfer |
| POST | /api/rewards/eligibility |
Reward eligibility |
| POST | /api/rewards/claim |
Reward claim |
| GET | /api/rewards/claim/{claim_id} |
Reward claim status |
| GET | /api/rewards/ops |
Reward operations summary |
| POST | /api/ai/chat |
Assistant endpoint |
| GET | /api/monitor/stats |
Operational monitor statistics |
| GET | /api/monero/status |
Monero daemon/wallet-RPC status |
| POST | /api/monero/scan/register |
Monero view-key scan registration |
| GET | /api/monero/scan/state |
Monero scan progress |
| POST | /api/monero/tx/construct |
Monero unsigned txset construction |
| POST | /api/monero/tx/relay |
Monero signed txset relay |
The backend starts long-running workers for:
- Reward claim processing
- Network-health refresh
- Price-history sampling
Workers should be started from the backend boot path and should use shared application state rather than ad-hoc globals.
The backend price feed uses a layered provider model with short-lived caching.
Typical provider order:
- Chainlink
- CoinGecko
- CoinMarketCap
- CryptoCompare
- Binance
- Etherscan
- Fallback aggregators
Cached prices may be used during temporary provider failures.
Swap and bridge flows follow a two-phase model:
- Prepare on backend
- Client reviews and signs
- Backend validates and executes or broadcasts
This prevents the frontend from assembling high-risk transaction data blindly while still keeping signing client-side.
The market price service lives in oxidity-price.
It provides market data and OHLC-style endpoints used by the wallet and site.
cd oxidity-price
python3 oxidity_price_api_ohlc_wallet_rpc.pySecurity and cache helper tests:
python3 -m unittest test_price_api_security -vThe price API should remain defensive around:
- Provider failures
- Cache poisoning
- Untrusted symbols
- Rate limits
- Stale responses
- Unexpected upstream payloads
Oxidity is self-custodial wallet software. Security boundaries must stay clear.
- The backend does not custody private keys.
- Seed phrases and private keys must never be logged.
- Signing happens client-side or through native signing paths.
- Development must use throwaway wallets and test funds.
- The backend should validate signed transactions before broadcast when possible.
- Approval prompts must be explicit and resistant to stale state.
- dApp sessions must be scoped, reviewable, and revocable.
- Sensitive configuration belongs in environment variables or secret stores, not in Git.
- AES-256-GCM is used for encrypted vault storage.
- PBKDF2-derived keys are used for vault encryption.
- Android secure storage and biometric unlock can protect local unlock material.
- Native signing can reduce key exposure to JavaScript on Android.
- Send flows include address-risk and preflight checks.
- WalletConnect approvals use per-origin session policies.
- The backend validates transaction structure and signer expectations where possible.
- Protected RPCs can be used for MEV-sensitive sends.
- Reward claims are rate-limited.
- Telemetry is opt-in and handled through middleware.
- SQLite migrations are managed through SQLx.
- nginx applies security headers.
- systemd service hardening is used in production.
- Cloudflare Tunnel can provide public ingress without directly exposing origin services.
Do not open public issues for vulnerabilities.
Report security issues using SECURITY.md.
See .env.example and deploy/systemd/wallet-backend.env.example.
| Variable | Purpose |
|---|---|
OXIDITY_WALLET_BACKEND_DB |
SQLite database path |
OXIDITY_WALLET_BACKEND_BIND |
Backend bind address |
OXIDITY_WALLET_BACKEND_PORT |
Backend HTTP port |
WALLET_BACKEND_ADMIN_TOKEN |
Optional admin bearer token |
HTTP_PROVIDER_<CHAIN_ID> |
Per-chain HTTP RPC override |
PROTECTED_HTTP_PROVIDER_<CHAIN_ID> |
Per-chain protected RPC override |
WEBSOCKET_PROVIDER_<CHAIN_ID> |
Per-chain WebSocket RPC override |
COINGECKO_API_KEY |
CoinGecko API key |
ETHERSCAN_API_KEY |
Etherscan API key |
BINANCE_API_KEY |
Binance market-data API key |
OPENSEA_API_KEY |
OpenSea API key |
TATUM_API_KEY |
Tatum RPC gateway API key |
COINMARKETCAP_API_KEY |
CoinMarketCap API key |
CRYPTOCOMPARE_API_KEY |
CryptoCompare API key |
NOKI_URL |
NOKI/price API base URL override |
MASSIVE_API_KEY |
Fallback market-data API key |
STRIPE_SECRET_KEY |
Stripe secret key |
STRIPE_PUBLISHABLE_KEY |
Stripe publishable key |
LIDO_REWARDS_ADDRESS |
Optional Ethereum mainnet Lido referral address; empty disables it |
OAUTH_CLIENT_SECRET |
Google OAuth client secret |
GOOGLE_DRIVE_CLIENT_ID |
Google Drive OAuth client ID |
GOOGLE_DRIVE_REDIRECT_URI |
Google Drive OAuth redirect URI |
MONERO_DAEMON_URL |
Optional Monero daemon URL for backend status/companion checks |
MONERO_DAEMON_RPC_LOGIN_FILE |
Optional daemon RPC user:password file |
MONERO_DAEMON_RPC_LOGIN |
Optional daemon RPC inline user:password |
MONERO_WALLET_RPC_URL |
Optional local Monero wallet-RPC URL |
MONERO_WALLET_RPC_LOGIN_FILE |
Optional wallet-RPC user:password file |
MONERO_WALLET_RPC_LOGIN |
Optional wallet-RPC inline user:password |
MONERO_WALLET_RPC_SEND_ENABLED |
Enables backend wallet-RPC send paths when set intentionally |
OXIDITY_MONERO_MANIFEST |
Optional Monero launch manifest override |
RUST_LOG |
Rust log level |
CHAINS |
Optional enabled chain list |
MAX_GAS_PRICE_GWEI |
Optional gas safety cap |
Defined in the wallet build environment; see .env.example for the tracked template.
| Variable | Purpose |
|---|---|
VITE_WALLET_API_BASE_URL |
Primary backend API base URL |
VITE_WALLET_API_BASE_URLS |
Optional comma-separated fallback API URLs |
VITE_OXIDITY_PRICE_API_BASE_URL |
Wallet/site price API base URL override |
VITE_REOWN_PROJECT_ID |
WalletConnect / Reown project ID |
VITE_GOOGLE_DRIVE_CLIENT_ID |
Google Drive backup OAuth client ID |
VITE_GOOGLE_DRIVE_REDIRECT_URI |
Optional Google Drive backup redirect URI |
VITE_MONERO_DAEMON_RPC_URL |
Monero daemon base URL for web/native client sends |
Monero uses two local endpoints with different responsibilities:
VITE_MONERO_DAEMON_RPC_URLpoints the web/PWA and Android native Monero engines at a Monero daemon. Use a daemon base URL such ashttp://127.0.0.1:18081; do not point it atmonero-wallet-rpc.MONERO_WALLET_RPC_URLis an optional backend companion/helper endpoint for wallet-RPC subaddress, portfolio, and gated backend wallet-RPC send paths.
The expected daemon RPC is:
127.0.0.1:18081
Start the Oxidity wallet RPC helper (run from the repository root):
npm run monero:wallet-rpcThen configure:
VITE_MONERO_DAEMON_RPC_URL=http://127.0.0.1:18081
MONERO_WALLET_RPC_URL=http://127.0.0.1:18083/json_rpcOnly enable backend wallet-RPC sends after the daemon and wallet are synced and the backend is intentionally allowed to submit sends from that opened wallet:
MONERO_WALLET_RPC_SEND_ENABLED=1Android native Monero sends use the Molly engine and the daemon endpoint; they
do not use host monero-wallet-rpc. See docs/monero.md.
cargo check --locked
cargo test --locked
cargo build --release
cargo runcd apps/wallet
npm install --legacy-peer-deps
npm run dev
npm run build
npm run lint
npm run test:unit
npm run test:e2e
npm run build:extension
npm run build:androidcd apps/site
npm install --legacy-peer-deps
npm run dev
npm run build
npm run lintRun from the repository root:
npm run validate:registrycd oxidity-price
python3 oxidity_price_api_ohlc_wallet_rpc.py
python3 -m unittest test_price_api_security -vscripts/dev/public-readiness.shThe main workflow is .github/workflows/ci.yml.
Typical CI coverage includes:
| Job | Checks |
|---|---|
| Rust | cargo fmt, cargo check, cargo clippy, cargo test |
| Wallet | npm ci --legacy-peer-deps, npm run lint, npm run test:unit, npm run build |
| Site | npm ci --legacy-peer-deps, npm run lint, npm run build |
| Extension | npm ci --legacy-peer-deps, npm run build:extension, bundle secret check |
| Market API | Python compileall, python -m unittest test_price_api_security -v |
Pull requests should pass CI before review.
- Use clear module boundaries.
- Keep public errors typed with
thiserror. - Prefer
Result<T, AppError>or API-specific error wrappers. - Use
#[serde(rename_all = "camelCase")]for JSON-facing structs. - Keep Solidity ABI bindings in Rust source via
sol!macros where practical. - Avoid raw environment lookups scattered through handlers.
- Add migrations for schema changes.
- Keep source headers aligned with the project license.
- Keep app-wide state in Zustand.
- Keep pure logic in
lib/. - Keep reusable UI in
components/. - Keep full-screen screens in
views/. - Avoid unnecessary
any. - Respect strict TypeScript.
- Use platform gates for native-only functionality.
- Keep chain-specific logic isolated.
- Add tests for new pure-logic modules.
- Keep approval, signing, and send flows boring, explicit, and hard to misuse.
Wallet UX must be calm, obvious, and defensive.
Important flows should handle:
- Back navigation
- App switching
- Reloads
- Popup closes
- Background restarts
- Network failures
- Duplicate taps
- Slow RPC responses
- Stale approval state
- Locked wallet state
- Interrupted signing flows
A crypto wallet should not assume users behave gently. They do not.
- Add the chain to
data/global_data.json. - Add chain artwork under
data/chains/if needed. - Add token artwork under
data/tokens/if needed. - Add EVM constants only when needed by Rust code.
- Add address derivation support for non-EVM chains.
- Wire send, receive, swap, bridge, NFT, or staking support only where the chain actually supports it.
- Run registry validation.
- Add tests for chain-specific parsing, address handling, and transaction preparation where relevant.
Run from the repository root:
npm run validate:registryDo not mark a feature as supported in the registry until the app flow is actually usable.
- Define request and response types.
- Implement the Axum handler.
- Register the route.
- Add client support in
apps/wallet/src/lib/api.ts. - Add tests.
- Document configuration or operational requirements.
- Avoid adding new telemetry routes unless the existing telemetry middleware cannot support the use case.
Handlers should be explicit about validation, failure modes, and user-facing error messages.
Production deployment is designed around a hardened Debian host with nginx, systemd, Cloudflare Tunnel, and local services bound to loopback.
Main deployment pieces:
| Path | Purpose |
|---|---|
deploy/bootstrap-fresh-debian.sh |
One-time host bootstrap |
deploy/install-host-runtime.sh |
Runtime asset installation |
deploy/rebuild-deploy.sh |
Build, deploy, restart, and verify |
deploy/nginx/ |
nginx templates |
deploy/systemd/ |
systemd unit templates |
deploy/cloudflared/ |
Cloudflare Tunnel service files |
Common deployment command:
./deploy/rebuild-deploy.shUseful deployment options:
./deploy/rebuild-deploy.sh --build-only
./deploy/rebuild-deploy.sh --skip-androidHealth checks should include:
- Local backend health
- Local backend bootstrap
- Host-routed nginx bootstrap
- Marketing site root
- Wallet app root
/.well-known/assetlinks.json- Extension package availability
- Public HTTPS checks after Cloudflare Tunnel settles
Contributions are welcome.
Start here:
- CONTRIBUTING.md
- SECURITY.md
- CODE_OF_CONDUCT.md
- TRADEMARKS.md
- docs/architecture.md
- docs/development/BRANCH_PROTECTION.md
Before opening a pull request:
cargo test --locked
npm run validate:registry
scripts/dev/public-readiness.shFor frontend changes, also run the relevant workspace checks:
cd apps/wallet
npm run lint
npm run test:unitFor site changes:
cd apps/site
npm run lint
npm run buildSecurity-sensitive changes should be small, reviewable, and clearly explained.
VERSION is the canonical semantic version for the main project.
It is used for:
- Backend versioning
- Wallet app versioning
- Marketing site versioning
- Android
versionName - Derived Android
versionCode(MAJOR * 10000 + MINOR * 100 + PATCH) - Runtime version constants
The Chrome extension version can advance independently through apps/wallet/package.json when browser-store release timing requires it.
Release notes live in CHANGELOG.md, including a Play-publisher
XML-style block that mirrors Google Play localized release notes (language
BCP-47 tags) and includes store country metadata.
Releases are tagged in Git and published through the relevant distribution channels after default-branch release preparation is complete.
Oxidity depends on a large open-source ecosystem across Rust, TypeScript, cryptography, wallet infrastructure, chain clients, and developer tooling.
Thanks to the maintainers and contributors whose work makes secure wallet development possible.
Oxidity Wallet source code is licensed under the Apache License 2.0.
See:
You may view, audit, fork, copy, modify, build, and use the code, including commercially, under the terms of Apache-2.0.
The Apache-2.0 license covers the source code.
It does not grant rights to impersonate or confusingly reuse the Oxidity name, logo, icon, screenshots, promotional graphics, app identity, or brand assets.
Public forks must rename and rebrand before distribution.
See TRADEMARKS.md.