Adding Solana — what changed in our stack
We added Solana support a few weeks ago. The interesting part wasn't the address generation — it was that Solana doesn't fit our existing HD-wallet model.
EVM and UTXO chains both use BIP-32 hierarchical deterministic derivation. We generate one master mnemonic per tenant and derive a wallet for each customer by concatenating the tenant's external ID with our path prefix. Same master can derive billions of addresses; they all share custody of the parent key.
Solana's ed25519 keys don't play nice with BIP-32 in the same way. The standard derivation paths exist (BIP-44 over ed25519) but the ecosystem typically generates fresh keypairs per address rather than deriving them. We could've forced HD-derivation on Solana but the cost-benefit didn't work out — most Solana SDKs and wallets expect raw keypairs, and forcing HD means we can't use them.
So: for Solana, each customer wallet has its own ed25519 keypair. The keypair is encrypted with the tenant DEK and stored. The master Solana wallet is a sweep destination that receives consolidated funds from customer wallets.
The tradeoff: Solana customers can't recover wallets from a master mnemonic. They have to export each keypair individually. The export tool handles batching for tenants with many wallets — encrypted gzip, downloadable from the dashboard with admin auth.
Our internal ChainAdapter interface had to grow a generateDirect() alongside deriveFromMaster(). Tron will be similar. UTXO and EVM stay HD. Adding the divergence as a first-class concept in the abstraction was the right call.