Rust API Reference¶
Complete API reference for the Rust bindings.
Installation¶
Add to Cargo.toml:
Or build from source:
Evm Struct¶
Constructor¶
Create a new EVM instance.
Returns: Result<Evm, EvmError>
Methods¶
reset¶
Reset execution state (keeps accounts).
set_gas_limit¶
Set maximum gas for execution.
set_block_number¶
Set current block number.
set_timestamp¶
Set block timestamp.
set_chain_id¶
Set chain ID.
set_coinbase¶
Set coinbase address.
set_address¶
Set current contract address.
set_caller¶
Set caller address (msg.sender).
set_origin¶
Set transaction origin (tx.origin).
set_value¶
Set call value (big-endian).
set_balance¶
Set account balance.
set_code¶
Set account bytecode.
set_storage¶
pub fn set_storage(&mut self, addr: &[u8; 20], key: &[u8; 32], value: &[u8; 32])
-> Result<(), EvmError>
Set storage slot.
get_storage¶
Get storage slot value.
execute¶
Execute bytecode.
gas_used¶
Get gas used in last execution.
gas_remaining¶
Get remaining gas.
return_data¶
Get return data.
logs¶
Get emitted logs.
stack_depth¶
Get stack depth.
stack_peek¶
Peek at stack value.
memory_size¶
Get memory size.
memory_read¶
Read memory region.
EvmResult¶
pub struct EvmResult {
pub success: bool,
pub error_code: EvmError,
pub gas_used: u64,
pub gas_remaining: u64,
pub return_data: Vec<u8>,
pub reverted: bool,
}
EvmError¶
#[repr(u8)]
pub enum EvmError {
Ok = 0,
OutOfGas = 1,
StackUnderflow = 2,
StackOverflow = 3,
InvalidOpcode = 4,
InvalidJump = 5,
Revert = 6,
StaticCallViolation = 7,
OutOfMemory = 8,
CallDepthExceeded = 9,
InsufficientBalance = 10,
InvalidArgument = 11,
UnknownError = 255,
}
Log¶
Examples¶
Basic Execution¶
use zigevm::{Evm, EvmError};
fn main() -> Result<(), EvmError> {
let mut evm = Evm::new()?;
evm.set_gas_limit(100_000);
// PUSH1 3, PUSH1 5, ADD, STOP
let code = vec![0x60, 0x03, 0x60, 0x05, 0x01, 0x00];
let result = evm.execute(&code, &[])?;
println!("Success: {}", result.success);
println!("Gas used: {}", result.gas_used);
Ok(())
}
Working with Accounts¶
use zigevm::Evm;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut evm = Evm::new()?;
// Set up account
let address = [0xaa; 20];
evm.set_balance(&address, 1_000_000_000_000_000_000u64)?; // 1 ETH
evm.set_address(&address);
// Set storage
let key = [0u8; 32];
let mut value = [0u8; 32];
value[31] = 42; // Store 42
evm.set_storage(&address, &key, &value)?;
// SLOAD slot 0
let code = vec![0x60, 0x00, 0x54, 0x00];
let result = evm.execute(&code, &[])?;
// Peek at stack
if let Some(stack_value) = evm.stack_peek(0) {
println!("Value: {}", stack_value[31]); // 42
}
Ok(())
}
With ethers-rs¶
use ethers::types::{Address, U256, Bytes};
use zigevm::Evm;
async fn simulate_call(
evm: &mut Evm,
to: Address,
calldata: Bytes,
) -> Result<Bytes, Box<dyn std::error::Error>> {
// Get contract code
let code = get_contract_code(to).await?;
// Set context
evm.set_address(&to.0);
// Execute
let result = evm.execute(&code, &calldata)?;
if result.success {
Ok(Bytes::from(result.return_data))
} else {
Err("Execution failed".into())
}
}
Error Handling¶
use zigevm::{Evm, EvmError};
fn main() {
let mut evm = match Evm::new() {
Ok(evm) => evm,
Err(e) => {
eprintln!("Failed to create EVM: {:?}", e);
return;
}
};
evm.set_gas_limit(100); // Very low
let code = vec![/* expensive operations */];
match evm.execute(&code, &[]) {
Ok(result) => {
if result.success {
println!("Success!");
} else if result.reverted {
println!("Reverted: {:?}", result.return_data);
} else {
match result.error_code {
EvmError::OutOfGas => println!("Out of gas"),
EvmError::StackUnderflow => println!("Stack underflow"),
_ => println!("Error: {:?}", result.error_code),
}
}
}
Err(e) => eprintln!("FFI error: {:?}", e),
}
}
Reading Logs¶
use zigevm::Evm;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut evm = Evm::new()?;
evm.set_gas_limit(1_000_000);
let code = vec![/* code that emits logs */];
let result = evm.execute(&code, &[])?;
for log in evm.logs() {
println!("Address: 0x{}", hex::encode(log.address));
for (i, topic) in log.topics.iter().enumerate() {
println!(" Topic {}: 0x{}", i, hex::encode(topic));
}
println!(" Data: 0x{}", hex::encode(&log.data));
}
Ok(())
}
Type Conversions¶
Address¶
// From [u8; 20]
let addr: [u8; 20] = [0xaa; 20];
evm.set_address(&addr);
// From ethers Address
let addr: ethers::types::Address = "0xaaaa...".parse()?;
evm.set_address(&addr.0);
Values¶
// From u64
evm.set_balance(&addr, 1_000_000u64)?;
// From [u8; 32] (big-endian)
let mut balance = [0u8; 32];
balance[31] = 100;
evm.set_balance(&addr, balance)?;
// From ethers U256
let balance: U256 = U256::from(1_000_000);
let mut bytes = [0u8; 32];
balance.to_big_endian(&mut bytes);
evm.set_balance(&addr, bytes)?;
Cargo Features¶
| Feature | Description |
|---|---|
default | Base functionality |
ethers | ethers-rs type conversions |
serde | Serialization support |