This example demonstrates managing accounts, keys, and identities across both Substrate and EVM ecosystems using Apex SDK’s unified account abstraction.
Substrate and EVM use fundamentally different cryptographic systems:
| Aspect | Substrate | EVM |
|---|---|---|
| Signature Scheme | SR25519 or Ed25519 | ECDSA (secp256k1) |
| Address Format | SS58 (Base58) | Hexadecimal (0x) |
| Address Length | 47-48 characters | 42 characters (20 bytes) |
| Nonce System | Per-account | Per-transaction |
| Decimals | Varies (10-18) | Typically 18 |
// For Substrate
import { Keyring } from '@polkadot/keyring';
const keyring = new Keyring({ type: 'sr25519' });
const substrateAccount = keyring.addFromUri(seed);
// For EVM
import { ethers } from 'ethers';
const evmWallet = ethers.Wallet.fromMnemonic(seed);
// Two completely separate systems!
// Single SDK, both ecosystems
let sdk = ApexSDK::builder()
.with_substrate_endpoint("wss://...")
.with_evm_endpoint("https://...")
.build()
.await?;
// Same account object for everything
let account = MultiChainAccount::new(name, substrate_addr, evm_addr);
This example implements wallet functionality:
cd examples/account-manager
cargo run
// From single seed, derive both formats
let substrate_address = "5GrwvaEF5z..."; // SR25519, SS58
let evm_address = "0x742d35Cc..."; // secp256k1, 0x
let account = MultiChainAccount::new(
"My Wallet".to_string(),
substrate_address,
evm_address,
);
// Query Substrate chain
account.balances.insert(Chain::Polkadot, dot_balance);
// Query EVM chain
account.balances.insert(Chain::Ethereum, eth_balance);
// Calculate total across all chains
let total = account.total_balance_usd(&prices);
let identity = SubstrateIdentity {
display_name: "Ilara".to_string(),
web: Some("https://ilara.dev".to_string()),
twitter: Some("@ilara_dev".to_string()),
// ...
};
// Set verifiable on-chain identity
sdk.execute(set_identity_tx).await?;
// Substrate transfer (SR25519 signature)
let substrate_tx = sdk.transaction()
.from_substrate_account(substrate_addr)
.to_substrate_account(recipient)
.build()?;
// EVM transfer (ECDSA signature)
let evm_tx = sdk.transaction()
.from_evm_address(evm_addr)
.to_evm_address(recipient)
.build()?;
// Same API, different signature schemes!
This pattern enables:
Substrate chains have built-in identity pallets that allow:
This is native to Substrate, while EVMs need separate solutions like ENS.
Different chains handle nonces differently:
Apex SDK abstracts this difference!
// Different signature schemes, same security
match chain.chain_type() {
ChainType::Substrate => sign_sr25519(tx), // Schnorr signature
ChainType::EVM => sign_ecdsa(tx), // Elliptic curve signature
}
Both are cryptographically secure, just different algorithms.
| Feature | Traditional Multi-Chain | Apex SDK |
|---|---|---|
| Account Generation | 2+ libraries | Single API |
| Address Formats | Manual handling | Automatic |
| Balance Queries | Different RPCs | Unified interface |
| Transaction Signing | Different signers | Same SDK |
| Nonce Management | Manual tracking | Abstracted |
| Type Safety | Runtime errors | Compile-time |
| Code Complexity | High | Low |