OS Vault
Self-custody, multi-chain crypto wallet for macOS. One recovery phrase. Six chain families. Zero API keys. Nothing ever leaves your Mac.
Why OS Vault
Most wallets make you choose: convenience (custodial, tracked, keyed APIs) or sovereignty (CLI tools, manual everything). OS Vault refuses the trade:
- 🔐 Your keys, your Mac, your encryption. The BIP-39 mnemonic is sealed with OS Vault's own vault format — PBKDF2-HMAC-SHA512 (600k rounds) → AES-256-GCM — in a local file. No macOS Keychain, no iCloud, no telemetry.
- 🌐 One phrase, every chain. The same 12 words derive Bitcoin (BIP-84), 11 EVM chains, Solana, Tron, XRPL and TON — cross-validated against independent crypto stacks in the test suite.
- 🗝️ Zero mandatory API keys. Every endpoint is public and keyless, with automatic failover. The only egress is blockchain RPC (+ optional CoinGecko prices, one toggle to kill).
- ✍️ Sign-and-forget. The private key exists only for the milliseconds a transaction is being signed — every send re-derives it from your password and discards it.
Chains
| Family | Assets | Fees handled | Testnet default |
|---|---|---|---|
| EVM × 11 — Ethereum, Base, Arbitrum, OP, Polygon, BNB, Avalanche, Gnosis, Linea, Scroll (+ Base Sepolia) | USDC, USDC.e, USDT, DAI, USDS, EURC + native coin | EIP-1559, BSC zero-base-fee, OP-stack/Scroll L1 data fee via oracle, Arbitrum inclusive estimates, Linea pinned base | Base Sepolia |
| Bitcoin | BTC (native SegWit bc1q…) |
sat/vB presets live from mempool.space, RBF on | Signet |
| Solana | SOL + USDC (SPL) | ATA rent surfaced when the recipient has no token account | Devnet |
| Tron | TRX + USDT (TRC-20) | Energy burn estimated pre-send (~13–27 TRX), fee_limit capped | Nile |
| XRP Ledger | XRP + RLUSD | Reserves shown as locked; one-tap RLUSD trustline; recipient trustline checked | Testnet |
| TON | TON + USDT (jetton) | Jetton-wallet indirection handled; ~0.07 TON attached, excess refunded | Testnet |
Every stablecoin contract address and decimal count was verified live
on-chain before registration — including the traps: BNB-peg USDT/USDC are
18 decimals, bridged USDC.e is indistinguishable from native USDC by
symbol() alone, DAI is 18 while USDC is 6. See
docs/STABLECOINS.md.
Security model
password ──▶ PBKDF2-HMAC-SHA512 (600k) ──▶ AES-256-GCM ──▶ vault.json (0600)
▲
wrong password / tampering ─┘ indistinguishable (GCM auth)
unlock ──▶ public addresses only stay in memory
send ──▶ password → derive key → sign → discard (every single time)- Forced written-backup verification (3 random words) before the wallet exists
- Confirm screen with recipient, amount, network, worst-case fees — always
- EIP-55 checksums; per-chain address validation; TESTNET badges everywhere
- App Sandbox + Hardened Runtime; signed, notarized and stapled by Apple
- The watch-only Bitcoin wallet holds public descriptors only; a throwaway in-memory signer signs PSBTs
Infrastructure — no API keys
| Concern | Source (keyless) | Fallback |
|---|---|---|
| EVM RPC | PublicNode (11/11 verified) | official chain RPCs, health-scored failover |
| Bitcoin | mempool.space Esplora | blockstream.info |
| Solana | PublicNode | api.mainnet-beta.solana.com |
| Tron | TronGrid (anonymous, backoff) | — |
| XRPL | xrplcluster.com | s1.ripple.com |
| TON | toncenter v2/v3 (1 req/s, throttled client-side) | — |
| Prices | CoinGecko batched (USD/CAD/EUR), stale-while-revalidate, off switch | DefiLlama |
Build
Pure SwiftPM — no .xcodeproj, no CocoaPods, no manual steps:
scripts/vendor-walletcore.sh # one-time: vendors Trust wallet-core for macOS (~270 MB, not in git)
swift build # compile
swift test # 32 tests: BIP-39/BIP-84 vectors, vault crypto, decimals, validators
make dev # debug bundle, ad-hoc signed, launched
make release # Developer ID + notarize + staple + DMG with volume iconThe wallet-core vendoring is this repo's party trick: upstream ships no macOS
SwiftPM support, so the script repackages the official CocoaPods tarball as a
local binaryTarget — including a surgical ld -r pass that demotes the
duplicate Rust runtime symbol it shares with the Bitcoin Dev Kit. Details in
docs/RESEARCH-MULTICHAIN.md.
Architecture
Sources/OSVaultKit
├── Services
│ ├── VaultCrypto ← the encryption mechanism (no Keychain)
│ ├── KeyManager ← BIP-39, HD derivation, vault lifecycle
│ ├── RPCService ← EVM JSON-RPC with endpoint failover
│ ├── TransactionService ← EIP-1559 + 5 other real fee models
│ ├── BitcoinService ← bdk-swift, watch-only + transient signer
│ ├── SolanaService ← solana-swift (vendored), SPL + ATA
│ ├── TronService ← wallet-core signing + TronGrid REST
│ ├── XRPLService ← wallet-core signing + xrplcluster JSON-RPC
│ ├── TONService ← wallet-core signing + toncenter v2/v3
│ └── PriceService ← CoinGecko keyless, cached, optional
├── Models ← Network (chain registry), Token (verified matrix)…
└── Views ← SwiftUI: onboarding, home, per-chain panelsRequirements
- macOS 15.5+ (Apple silicon or Intel)
- That's it. No accounts, no keys, no configuration.
Testnet quickstart
- Create a wallet (write the 12 words down — the app makes you prove it).
- Fund: Circle faucet (USDC on Base Sepolia + Solana devnet), a Base Sepolia ETH faucet, mempool.space signet faucet, nileex.io (TRX + test USDT), XRPL faucet, @testgiver_ton_bot.
- Send. Watch it confirm on the linked explorer.
Built with Swift, paranoia, and a refusal to type API keys. © 2026 Simon-Pierre Boucher · contact@spboucher.ai