elizaos-plugin-evm (Rust)
Rust implementation of the EVM blockchain plugin for elizaOS.
Features
- Wallet Management: Local key management using alloy-rs
- Token Transfers: Native and ERC20 token transfers
- Token Swaps: DEX aggregator integration via LiFi API
- Cross-Chain Bridges: Cross-chain transfers via LiFi API
- Strong Types: Compile-time safety with zero-cost abstractions
Installation
Add to your Cargo.toml:
[dependencies]
elizaos-plugin-evm = "2.0"
Quick Start
use elizaos_plugin_evm::{
WalletProvider, WalletProviderConfig, TransferAction, TransferParams,
SupportedChain,
};
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = WalletProviderConfig::new("0x...") .with_chain(SupportedChain::Mainnet, None)
.with_chain(SupportedChain::Base, None);
let provider = Arc::new(WalletProvider::new(config).await?);
let balance = provider.get_formatted_balance(SupportedChain::Mainnet).await?;
println!("Balance: {} ETH", balance);
let transfer = TransferAction::new(provider);
let params = TransferParams::native(
SupportedChain::Mainnet,
"0x...".parse()?, "0.1",
);
let tx = transfer.execute(params).await?;
println!("Transaction: {:?}", tx.hash);
Ok(())
}
Supported Chains
- Ethereum Mainnet
- Sepolia (Testnet)
- Base
- Base Sepolia (Testnet)
- Arbitrum One
- Optimism
- Polygon
- Avalanche C-Chain
- BNB Smart Chain
- And more...
Actions
Transfer
Transfer native tokens or ERC20 tokens:
let params = TransferParams::native(chain, recipient, "1.0");
let tx = transfer.execute(params).await?;
let params = TransferParams::erc20(chain, recipient, token_address, "100.0");
let tx = transfer.execute_erc20(params).await?;
Swap
Swap tokens using DEX aggregators:
let swap = SwapAction::new(provider);
let params = SwapParams::new(
SupportedChain::Mainnet,
weth_address,
usdc_address,
"1.0",
);
let quote = swap.get_quote(¶ms).await?;
println!("Min output: {}", quote.min_output_amount);
let tx = swap.execute(params).await?;
Bridge
Bridge tokens across chains:
let bridge = BridgeAction::new(provider);
let params = BridgeParams::new(
SupportedChain::Mainnet,
SupportedChain::Base,
eth_address,
eth_address,
"0.5",
);
let (tx, status) = bridge.execute(params).await?;
println!("Bridge status: {:?}", status.status);
Error Handling
All errors are strongly typed with EVMError:
match transfer.execute(params).await {
Ok(tx) => println!("Success: {:?}", tx.hash),
Err(EVMError { code: EVMErrorCode::InsufficientFunds, .. }) => {
println!("Not enough funds!");
}
Err(e) => println!("Error: {}", e),
}
Testing
Run unit tests:
cargo test
Run integration tests (requires funded testnet wallet):
export TEST_PRIVATE_KEY="0x..."
export SEPOLIA_RPC_URL="https://..."
cargo test --test integration_tests -- --ignored
Building
Native build:
cargo build --release
WASM build (for browser):
cargo build --release --target wasm32-unknown-unknown --features wasm
License
MIT