| Crates.io | apex-sdk-evm |
| lib.rs | apex-sdk-evm |
| version | 0.1.5 |
| created_at | 2025-11-15 09:04:29.402694+00 |
| updated_at | 2026-01-13 06:53:53.945531+00 |
| description | EVM adapter for Apex SDK |
| homepage | |
| repository | https://github.com/carbobit/apex-sdk |
| max_upload_size | |
| id | 1934171 |
| size | 438,447 |
EVM blockchain adapter for the Apex SDK, providing seamless interaction with Ethereum and EVM-compatible chains.
Note: This package has been fully migrated from ethers-rs to Alloy. Examples in this README are being updated. For the latest API usage, see the source code and tests.
apex-sdk-evm enables developers to interact with Ethereum and other EVM-compatible blockchains through a unified, type-safe Rust API. It supports HTTP and WebSocket connections, transaction building, smart contract interaction, and wallet management.
Add this to your Cargo.toml:
[dependencies]
apex-sdk-evm = "0.1.3"
tokio = { version = "1.0", features = ["full"] }
use apex_sdk_evm::EvmAdapter;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to Ethereum mainnet
let adapter = EvmAdapter::connect("https://eth.llamarpc.com").await?;
// Get latest block number
let block_number = adapter.get_block_number().await?;
println!("Latest block: {}", block_number);
// Get chain ID
let chain_id = adapter.get_chain_id().await?;
println!("Chain ID: {}", chain_id);
Ok(())
}
use apex_sdk_evm::EvmAdapter;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect via WebSocket
let adapter = EvmAdapter::connect("wss://eth.llamarpc.com").await?;
// Query blockchain data
let block_number = adapter.get_block_number().await?;
println!("Latest block: {}", block_number);
Ok(())
}
use apex_sdk_evm::wallet::Wallet;
// Generate a new wallet
let wallet = Wallet::generate();
println!("Address: {:?}", wallet.eth_address());
println!("Private key: {}", wallet.private_key_hex());
// Import from private key (hex string with or without 0x prefix)
let wallet = Wallet::from_private_key("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")?;
// Import from mnemonic
let wallet = Wallet::from_mnemonic("test test test test test test test test test test test junk")?;
// Set chain ID for transaction signing
let wallet = wallet.with_chain_id(1); // Ethereum mainnet
The recommended way to execute EVM transactions is through the unified Apex SDK interface:
use apex_sdk::prelude::*;
use apex_sdk_evm::wallet::Wallet;
#[tokio::main]
async fn main() -> Result<()> {
// Create wallet from private key
let wallet = Wallet::from_private_key("0x...")?
.with_chain_id(11155111); // Sepolia testnet
// Initialize SDK with wallet
let sdk = ApexSDK::builder()
.with_evm_endpoint("https://eth-sepolia.g.alchemy.com/v2/demo")
.with_evm_wallet(wallet)
.build()
.await?;
// Build and execute transaction
let recipient = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
let amount = 10_000_000_000_000u128; // 0.00001 ETH in wei
let tx = sdk
.transaction()
.from_evm_address(&wallet.address())
.to_evm_address(recipient)
.amount(amount)
.build()?;
let result = sdk.execute(tx).await?;
println!("Transaction hash: {}", result.source_tx_hash);
println!("Status: {:?}", result.status);
Ok(())
}
See examples/evm-transfer/ for a complete working example.
sol! MacroApex SDK uses Alloy's sol! macro for compile-time safe contract interactions:
use alloy::sol;
use alloy_primitives::{Address as EthAddress, U256};
use apex_sdk::prelude::*;
// Define ERC20 interface using Alloy's sol! macro
sol! {
#[sol(rpc)]
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function totalSupply() external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
}
}
#[tokio::main]
async fn main() -> Result<()> {
// Initialize SDK
let sdk = ApexSDK::builder()
.with_evm_endpoint("https://eth-sepolia.g.alchemy.com/v2/demo")
.build()
.await?;
let evm = sdk.evm()?;
let provider = evm.provider();
// Contract and account addresses
let weth: EthAddress = "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14".parse()?;
let account: EthAddress = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045".parse()?;
// Query balance (read-only, no gas)
let balance_call = IERC20::balanceOfCall { account };
let balance_data = balance_call.abi_encode();
let result = provider
.inner
.call(&alloy::rpc::types::TransactionRequest::default()
.to(weth)
.input(balance_data.into()))
.await?;
let balance = IERC20::balanceOfCall::abi_decode_returns(&result, true)?._0;
println!("Balance: {} WETH", balance);
Ok(())
}
For a complete example including write transactions, see examples/evm-contract-call/.
sol! Macrouse apex_sdk_evm::EvmAdapter;
use apex_sdk_core::ChainAdapter;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let adapter = EvmAdapter::connect("https://eth.llamarpc.com").await?;
// Get account balance
let address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
let balance = adapter.get_balance(address).await?;
println!("Balance: {} wei", balance);
// Get balance in ETH format
let balance_eth = adapter.get_balance_eth(address).await?;
println!("Balance: {} ETH", balance_eth);
// Get transaction status
let tx_hash = "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060";
let status = adapter.get_transaction_status(tx_hash).await?;
println!("Transaction status: {:?}", status);
// Get latest block number
let block_num = adapter.get_block_number().await?;
println!("Latest block: {}", block_num);
// Get chain ID
let chain_id = adapter.get_chain_id().await?;
println!("Chain ID: {}", chain_id);
Ok(())
}
use apex_sdk_evm::wallet::Wallet;
let wallet = Wallet::from_private_key("0x...")?;
// Sign a message (EIP-191 personal sign)
let message = "Hello, Ethereum!";
let signature = wallet.sign_message(message).await?;
println!("Signature: {:?}", signature);
// Verify signature
let recovered_address = signature.recover_address_from_msg(message)?;
assert_eq!(recovered_address, wallet.eth_address());
The adapter works with any EVM-compatible blockchain:
// Ethereum Mainnet
let eth = EvmAdapter::new("https://eth.llamarpc.com");
// Polygon
let polygon = EvmAdapter::new("https://polygon-rpc.com");
// BSC
let bsc = EvmAdapter::new("https://bsc.publicnode.com");
// Arbitrum
let arbitrum = EvmAdapter::new("https://arb1.arbitrum.io/rpc");
// Optimism
let optimism = EvmAdapter::new("https://mainnet.optimism.io");
// Local development (Ganache, Hardhat)
let local = EvmAdapter::new("http://localhost:8545");
Comprehensive error types for robust applications:
use apex_sdk_evm::{EvmError, Result};
match some_evm_operation().await {
Err(EvmError::InsufficientFunds) => {
println!("Not enough ETH for transaction");
}
Err(EvmError::GasTooLow) => {
println!("Gas limit too low");
}
Err(EvmError::ContractError(reason)) => {
println!("Contract reverted: {}", reason);
}
Err(EvmError::NetworkError(msg)) => {
println!("Network error: {}", msg);
}
Ok(result) => {
// Handle success
}
}
cargo test
cargo test --features integration-tests
The integration tests require a running Ethereum node or testnet access.
Complete working examples are available in the examples directory:
sol! macroAll examples use the modern Alloy library and demonstrate blockchain interactions.
# Provider URLs
ETHEREUM_RPC_URL="https://eth.llamarpc.com"
POLYGON_RPC_URL="https://polygon-rpc.com"
# Private keys (use with caution)
PRIVATE_KEY="0x..." # For testing only
# API keys
INFURA_API_KEY="your-infura-key"
ALCHEMY_API_KEY="your-alchemy-key"
# config.toml
[evm]
default_network = "ethereum"
request_timeout = "30s"
[evm.networks.ethereum]
rpc_url = "https://eth.llamarpc.com"
chain_id = 1
[evm.networks.polygon]
rpc_url = "https://polygon-rpc.com"
chain_id = 137
[evm.cache]
enabled = true
max_entries = 10000
ttl = "5m"
[evm.metrics]
enabled = true
prometheus_endpoint = "0.0.0.0:9090"
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.