SPB Git

spb/os-vault Public

Self-custody, multi-chain crypto wallet for macOS. One recovery phrase, six chain families, zero API keys — nothing leaves your Mac.

Swift 96% Shell 3.4% Makefile 0.6%
6.6 KB

# Multi-chain implementation research — synthesis (2026-08-05)

Five parallel research tracks (wallet-core/architecture, Bitcoin, non-EVM chains, EVM expansion, keyless infra), all endpoint/address claims verified live during research. This file is the implementation blueprint; statuses below reflect what is already shipped in the code.

# Verdicts at a glance

Track Verdict Status in OS Vault
EVM multichain Data-driven: 11 chains, 4 real fee models, PublicNode primary keyless RPC + failover Implemented (Network.swift, TransactionService.swift)
Native coin send Always eth_estimateGas (never 21000); OP-stack/Scroll L1 data fee via oracle Implemented
Stablecoin matrix Verified per-chain addresses; BNB peg = 18 decimals; USDC.e ≠ USDC by address only Implemented (Token.swift)
Bitcoin bdk-swift 3.0.0 — only maintained macOS+SPM option; BIP-84; keyless Esplora (mempool.space) Implemented (BitcoinService.swift, watch-only + transient signer)
Fiat prices CoinGecko keyless batched (/simple/price, USD/CAD/EUR); DefiLlama fallback; prices-OFF mode Implemented (PriceService.swift)
wallet-core (Tron/TON/XRPL signing) Vendored at vendor/WalletCoreSPM (binaryTarget; duplicate Rust _rust_eh_personality vs bdkFFI demoted surgically in the archive — see vendor script) Vendored + tested (ETH vector, Tron cross-stack, XRP/TON derive)
Solana p2p-org/solana-swift vendored (vendor/solana-swift — its Boilertalk secp256k1 dep clashed with web3swift's target name; CKSecp256k1 re-backed by Web3Core); PublicNode RPC keyless; ATA rent surfaced pre-send Implemented (SolanaService.swift, SOL + USDC, devnet default)
Tron wallet-core TransferContract/TransferTRC20Contract + TronGrid keyless; energy burn estimated pre-send via triggerconstantcontract, fee_limit 100 TRX; Nile default (USDT TXYZ…AeBf verified live) Implemented (TronService.swift)
TON tonkeeper/ton-swift + toncenter (1 req/s keyless); jetton indirection; BIP-39 path m/44'/607' (Tonkeeper won't import directly — document) ⏭ Next
XRPL wallet-core signer (TrustSet + issued currencies = RLUSD); xrplcluster.com genuinely free; 1 XRP base reserve + 0.2/trustline ⏭ Next
Stellar Soneso stellar-ios-mac-sdk — best non-EVM Swift SDK, nearly free to add ⏭ Bonus
History indexing No keyless multi-chain indexer exists. Per chain: Blockscout v2 (7 EVM chains), Routescan (Avalanche/Mantle/Blast), mempool.space (BTC), else eth_getLogs incremental. BNB/Linea = optional user key ⏭ Next
Fiat FX Frankfurter (ECB, keyless, unlimited); avoid exchangerate.host (keyed now) Covered via CoinGecko native CAD/EUR
Auto-update Sparkle 2 via SPM, EdDSA + notarization, static appcast on GitHub Releases ⏭ When distribution starts

# Key implementation facts (already coded)

  • Fee models (Network.FeeModel): eip1559 · zeroBaseFee (BSC/BEP-226: price via eth_gasPrice) · opStackL1Fee (Base/OP: add GasPriceOracle.getL1Fee(unsigned tx) at 0x42…0F to the confirm total) · scrollL1Fee (oracle 0x5300…0002) · arbitrumInclusive (estimate already includes L1 buffer, tip 0, use verbatim) · lineaPinnedBase (base pinned at 7 wei, cost rides in the tip).
  • RPC failover (RPCService): ordered keyless endpoints per chain (PublicNode primary — all 11 verified; official RPC fallback), sticky primary, 60 s demotion cooldown, node-side errors surface immediately. Dead/keyed providers found in research: llamarpc (521), Ankr (key now), 1rpc (quota), polygon-rpc.com (401 intermittent).
  • Registry traps: BNB USDT/USDC are 18 decimals (separate Token entries); USDC.e shares symbol() with native USDC on Arb/OP/Polygon (distinguish by address, display "USDC.e"); Arbitrum/Polygon USDT upgraded in place to USDT0 (same address/decimals — never assert symbol strings); Gnosis native xDAI is itself dollar-pegged.
  • Bitcoin (BitcoinService): BIP-84 descriptors from the same vault mnemonic (BIP-84 spec vector unit-tested); watch-only persisted wallet (public descriptors, BDK SQLite) for sync/balance/receive with address rotation; sends build the PSBT on the watch wallet, then a throwaway in-memory signer wallet (secret descriptors re-derived from the password) signs and is discarded. Esplora keyless: mempool.space (+ blockstream.info broadcast fallback on mainnet); fees from /api/v1/fees/recommended. Default network signet (testnet-first), mainnet behind the switch.
  • Prices (PriceService): one batched CoinGecko call for every asset × USD/CAD/EUR at ≥120 s TTL (≈0.5 calls/min vs 5–15/min keyless budget); stale-while-revalidate JSON cache; Settings toggle removes the only non-blockchain egress. CoinCap and CryptoCompare are dead as keyless options; Binance geoblocks; Coinbase spot is the per-pair fallback.

# wallet-core vendoring (next phase enabler)

Upstream declined macOS SPM support (PR #3529), but the official CocoaPods tarball (TrustWalletCore-<v>.tar.xz on GitHub releases) contains WalletCoreCommon.xcframework with a macos-arm64_x86_64 slice plus the Swift wrappers. scripts/vendor-walletcore.sh automates: download → verify → C-headers target (incl. the security-critical SecRandom.m RNG shim) → sed module imports → local SPM package in vendor/WalletCoreSPM. Proven by a local build that derived BTC/ETH/Solana/Tron/TON/XRP addresses from one runtime mnemonic. Cost: ~33 MB binary. One library then signs every remaining chain (Tron TransferTRC20Contract, TON JettonTransfer + wallet v5R1, XRPL TrustSet/issued currencies, Solana CreateAndTransferToken).

# Non-EVM priority order (stablecoin volume × cost)

  1. Solana / USDC — cheapest build (solana-swift is macOS-native) and top USDC venue; pipe-cleaner for the adapter pattern.
  2. Tron / USDT-TRC20 — largest USDT corridor on earth; energy-fee UX is the main work (estimate via triggerconstantcontract, fee_limit 100 TRX).
  3. TON / USDT jetton — jetton-wallet indirection, 1 rps toncenter queue.
  4. XRPL / RLUSD + XRP — trustline UX (one-tap TrustSet, check recipient account_lines pre-send), reserves surfaced as non-spendable.
  5. Stellar / USDC — Soneso SDK, trustlines like XRPL, nearly free to add.

Full per-chain details (curves, derivation paths, endpoints, faucets, rate limits, sources) live in the research transcripts; the numbers used in code are restated in comments at their point of use.