How OpenHuman's Web3 Wallet Enables Multi-Chain Signing: EVM, Bitcoin, Solana, and Tron
OpenHuman's Web3 wallet implements a core-owned, multi-chain architecture that signs transactions across EVM networks, Bitcoin, Solana, and Tron using a single encrypted BIP-39 mnemonic, with private keys derived on-demand inside an attested module process.
The tinyhumansai/openhuman repository provides a comprehensive Web3 wallet implementation that supports multi-chain signing through a unified interface. Unlike browser-extension wallets, this core-owned wallet maintains a single encrypted recovery phrase and derives chain-specific keys on demand, enabling seamless transaction signing across four distinct blockchain families without compromising key security.
Core Architecture of the Multi-Chain Wallet
Single Mnemonic, Multiple Chain Derivations
OpenHuman's wallet architecture centers on one encrypted BIP-39 mnemonic stored either in the OS keychain or a workspace-scoped JSON file, as detailed in src/openhuman/web3/wallet/README.md. This single secret seeds all supported chains through standardized derivation paths:
- EVM Networks (Ethereum, Base, Arbitrum, Optimism, Polygon, BNB Chain): BIP-44 path
m/44'/60'/…viasrc/openhuman/web3/wallet/chains/evm.rs - Bitcoin (Mainnet P2WPKH): BIP-84 path
m/84'/0'/…handled insrc/openhuman/web3/wallet/chains/btc.rs - Solana: Ed25519 derivation at
m/44'/501'/…insrc/openhuman/web3/wallet/chains/solana.rs - Tron: TRON-specific path
m/44'/195'/…insrc/openhuman/web3/wallet/chains/tron.rs
The onboarding logic in src/openhuman/web3/wallet/ops.rs (lines 18-27) creates this mnemonic once during wallet_setup, encrypts it, and derives the initial account for each chain family.
Module-Based Signing Boundary
The wallet enforces a critical security boundary: private keys never leave the process. When signing is requested, the secret_material(WalletChain::Evm) function (or its chain-specific variant) retrieves the encrypted mnemonic and decrypts it via crate::openhuman::security::encryption::rpc::decrypt_secret. The decrypted phrase is passed exactly once to modules::wallet::sign_transaction_in_module.
This module validates the derivation path, derives the secp256k1 or Ed25519 private key, signs the transaction, and returns only the raw signed bytes. This architecture ensures that private key material remains confined to the attested module, with no exposure to the broader application context.
Chain-Specific Signing Implementations
EVM Network Signing
For all EVM-compatible networks, the signing flow resides in src/openhuman/web3/wallet/chains/evm.rs (lines 38-45). The wallet builds a tinywallet_bus::wire::SecretMaterial struct, derives the private key from the BIP-44 path, and signs the transaction inside the loaded module. The signed raw transaction is broadcast via standard eth_sendRawTransaction RPC calls.
The EvmNetwork enum defined in src/openhuman/web3/wallet/defaults.rs encapsulates network-specific parameters including chain IDs, default RPC URLs, and block explorers. The same sign_and_broadcast primitive works across all EVM networks; the target network is selected from the prepared quote (quote.evm_network).
Bitcoin (BTC) PSBT Handling
Bitcoin signing follows the BIP-84 standard for SegWit (P2WPKH) addresses. In src/openhuman/web3/wallet/chains/btc.rs, the module derives the private key, constructs a Partially Signed Bitcoin Transaction (PSBT), signs the inputs, and broadcasts via Esplora REST endpoints. This supports both mainnet and testnet configurations.
Solana Ed25519 Signatures
Solana integration in src/openhuman/web3/wallet/chains/solana.rs uses Ed25519 key derivation at path m/44'/501'/…. The module constructs a Solana Message, signs it using the ed25519_dalek library, and transmits via Solana RPC methods. This handles both native SOL transfers and SPL token transactions.
Tron Network Integration
Tron signing in src/openhuman/web3/wallet/chains/tron.rs implements the TRON-specific derivation path m/44'/195'/…. After signing the transaction payload within the module, the wallet broadcasts to TronGrid REST endpoints, supporting both native TRX transfers and TRC-20 token transactions.
Transaction Flow from Quote to Broadcast
The multi-chain signing process follows a structured five-step flow:
-
Quote Preparation: The
wallet_prepare_transfertool acceptsPrepareTransferParamsspecifying the target chain, recipient address, and amount. This validates addresses, estimates fees, and stores aPreparedTransactionwith a 5-minute TTL bound to the originating chat thread (APPROVAL_CHAT_CONTEXT). -
Secret Retrieval: Upon execution confirmation,
sign_and_broadcastinsrc/openhuman/web3/wallet/chains/evm.rs(lines 45-66) callssecret_material()to decrypt the mnemonic and build theSecretMaterialstruct. -
Module Signing: The wallet invokes
modules::wallet::sign_transaction_in_modulewith the decrypted material and chain-specific derivation parameters. The module performs the cryptographic signing and returns the raw transaction bytes. -
Broadcast: Chain-specific RPC layers transmit the signed transaction:
- EVM:
eth_sendRawTransactionviasrc/openhuman/web3/wallet/rpc.rs - Bitcoin: Esplora REST endpoints
- Solana:
sendTransactionRPC - Tron: TronGrid REST API
- EVM:
-
Status Monitoring: The
tx_statusfunction queries receipt status, falling back toeth_getTransactionByHashfor EVM networks to distinguish pending from unknown transactions.
Practical Code Examples
Preparing a Cross-Chain Transfer Quote
use openhuman::web3::wallet::execution::PrepareTransferParams;
use openhuman::web3::wallet::defaults::EvmNetwork;
let params = PrepareTransferParams {
from_chain: WalletChain::Evm,
to_address: "0xAbC...".into(),
amount_raw: "0.01".into(),
token_address: None, // native ETH transfer
evm_network: Some(EvmNetwork::EthereumMainnet),
};
let quote = wallet::prepare_transfer(params).await?;
This validates the EVM address, estimates gas via eth_estimateGas, and stores the prepared transaction with a TTL.
Executing a Prepared Quote
use openhuman::web3::wallet::execution::ExecutePreparedParams;
let exec = ExecutePreparedParams {
quote_id: quote.quote_id.clone(),
confirmed: true,
};
let result = wallet::execute_prepared(exec).await?;
println!("Tx hash: {}", result.transaction_hash);
The execute_prepared function routes to chain-specific implementations like execute_evm_quote, which invoke the module-based signing flow.
Checking Transaction Status
let status = wallet::tx_status(EvmNetwork::EthereumMainnet, "0xabc123...").await?;
match status.state {
TxState::Confirmed => println!("Confirmed!"),
TxState::Pending => println!("Pending..."),
TxState::NotFound => println!("Tx not found"),
}
Direct EVM Signing (Internal API)
use openhuman::web3::wallet::sign_and_broadcast_evm;
let raw = sign_and_broadcast_evm(
EvmNetwork::Polygon,
"0xRecipient...",
Some("0xdeadbeef".into()), // contract calldata
"0", // zero native value
).await?;
println!("Broadcasted tx: {}", raw.transaction_hash);
Summary
- OpenHuman's wallet uses a single encrypted BIP-39 mnemonic to derive keys for EVM, Bitcoin, Solana, and Tron networks.
- Private keys never leave the module boundary; signing occurs inside
modules::wallet::sign_transaction_in_modulewith attestation. - Chain-specific derivation paths (BIP-44 for EVM, BIP-84 for Bitcoin, Ed25519 for Solana) are handled in dedicated files under
src/openhuman/web3/wallet/chains/. - Quote-based transactions include a 5-minute TTL and chat-thread binding to prevent session hijacking.
- All signing flows culminate in raw transaction broadcasts via chain-appropriate RPC endpoints (Ethereum JSON-RPC, Esplora, Solana RPC, TronGrid).
Frequently Asked Questions
How does OpenHuman's wallet secure private keys during multi-chain signing?
The wallet decrypts the BIP-39 mnemonic only within the attested wallet module via modules::wallet::sign_transaction_in_module. Private keys are derived on-demand inside this module, sign the transaction, and are immediately discarded. The raw signed bytes are returned, but the private key material never exits the module process, ensuring core-owned security across all supported chains.
Which blockchain networks does OpenHuman's Web3 wallet support?
According to the source code in tinyhumansai/openhuman, the wallet supports four blockchain families: EVM networks (Ethereum, Base, Arbitrum, Optimism, Polygon, BNB Chain), Bitcoin (Mainnet and Testnet P2WPKH), Solana (Mainnet and Devnet), and Tron (Mainnet and Testnet). Each implementation resides in its respective file under src/openhuman/web3/wallet/chains/.
What derivation path does OpenHuman use for Ethereum addresses?
OpenHuman follows the BIP-44 standard with path m/44'/60'/… for all EVM networks, including Ethereum, Base, and Polygon. This logic is implemented in src/openhuman/web3/wallet/chains/evm.rs, where the wallet module derives the secp256k1 private key from this path before signing transactions via eth_sendRawTransaction.
How does the wallet prevent replay attacks on prepared transactions?
Prepared transactions include a 5-minute time-to-live (TTL) and are bound to the originating chat thread via APPROVAL_CHAT_CONTEXT. This ensures quotes expire quickly and cannot be executed outside their original session context, preventing cross-session transaction hijacking while maintaining multi-chain signing flexibility.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →