Rust NIFs for Elixir: local EVM simulation via revm, Solidity ABI parsing via Alloy, debug/trace APIs, and contract codegen. Built on onchain.
Requires a Rust toolchain for NIF compilation.
def deps do
[
{:onchain, "~> 0.10"},
{:onchain_evm, "~> 0.3"}
]
end| Module | Purpose |
|---|---|
Onchain.EVM |
Local EVM execution — fork mainnet state, simulate calls/transactions/batches |
Onchain.Solidity |
Alloy-powered Solidity ABI parser (JSON ABI, .sol source, import resolution) |
Onchain.Trace |
Debug/trace APIs — trace_transaction, trace_call, storage_at |
Onchain.Contract.Generator |
.sol file → typed Elixir module at compile time |
EVM simulation forks state from an RPC endpoint passed per-call via :rpc_url:
# Simulate a read (eth_call semantics)
Onchain.EVM.simulate_call(usdc_address, calldata, rpc_url: "https://eth-mainnet.example.com")
# Full execution result (gas_used, success, return data)
Onchain.EVM.simulate_transaction(address, calldata, rpc_url: url)
# Batch many calls against one shared fork
Onchain.EVM.simulate_batch(calls, rpc_url: url)Options:
| Option | Meaning |
|---|---|
:rpc_url |
RPC endpoint to fork from (required; validated — empty/non-HTTP(S)/hostless rejected) |
:block |
Block to fork at — integer, "0x…" hex, or a tag ("latest", "finalized", "safe", "pending", "earliest") |
:timeout_ms |
Per-RPC-request timeout (positive integer; default 30s, 5s connect). Surfaces as {:error, {:timeout, msg}} |
:value, :gas_limit, :state_overrides |
Validated and threaded into the fork (invalid input fails fast, not silently dropped) |
Every public function has a bang (!) variant that raises on error.
Generate a typed module from a .sol file or JSON ABI at compile time:
defmodule USDC do
use Onchain.Contract.Generator, abi_file: "priv/abis/erc20.json"
end
USDC.balance_of(contract, holder, rpc_url: url) # => {:ok, [balance]}Generator inputs (in precedence order): :abi_json, :abi_file, :sol, :sol_file. Solidity sources support :remappings (Foundry-style) and :root_contract for import resolution.
All modules use descripex for self-describing APIs:
OnchainEvm.describe() # Module overview
OnchainEvm.describe(:evm) # Function listings
OnchainEvm.describe(:evm, :simulate_call) # Full function detailsmix test.json --quiet # Offline unit tests
mix test.json --quiet --include integration # + integration (requires an RPC node)Integration tests read ETHEREUM_API_URL (or ETH_RPC_URL).
MIT