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 viaeth_gasPrice) ·opStackL1Fee(Base/OP: addGasPriceOracle.getL1Fee(unsigned tx)at0x42…0Fto the confirm total) ·scrollL1Fee(oracle0x5300…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)
- Solana / USDC — cheapest build (solana-swift is macOS-native) and top USDC venue; pipe-cleaner for the adapter pattern.
- Tron / USDT-TRC20 — largest USDT corridor on earth; energy-fee UX is
the main work (estimate via
triggerconstantcontract,fee_limit100 TRX). - TON / USDT jetton — jetton-wallet indirection, 1 rps toncenter queue.
- XRPL / RLUSD + XRP — trustline UX (one-tap TrustSet, check recipient
account_linespre-send), reserves surfaced as non-spendable. - 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.