Skip to main content
A fundamental operation in smart contracts is to look up data from other contracts, such as the ERC20 token balance of a specific address. This operation is known as a “view call” - it “views” state without altering it. Steel allows developers to query EVM state, within the zkVM, by just defining the Solidity method they wish to view call (using alloy’s sol! macro).
This code is taken from the erc20-counter example, which you can find here. The sol! macro parses Solidity syntax to generate Rust types; this is used to call the balanceOf function, within the guest program, using balanceOfCall:

Proving smart contract execution within the zkVM

The zkVM guest has no network connection, and there is no way to call an RPC provider to carry out the view call from within the guest; so how does Steel make this possible? Steel’s key innovation is the use of revm for simulation of an EVM environment within the guest program. This EVM environment has the necessary state populated from RPC calls, and verified with Merkle storage proofs, to carry out verifiable execution of view calls. In the host program, the preflight call constructs the EVM environment, evm_env which is passed through as input to the guest program:
The preflight step calls the RPC provider for the necessary state and for the Merkle storage proofs via eth_getProof (EIP-1186). These Merkle proofs are given to the guest which verifies them to prove that the RPC data is valid, without having to run a full node and without trusting the host or RPC provider.

Verifying the proof onchain

At this point, we have generated a proof of: a view call of state onchain and some execution based on that view call state (e.g. checking that the balance is at least 1). When using Steel, the general pattern for onchain functions incorporating Steel follows this pseudo-code:
The interesting onchain logic, doSomethingElse(), is only reached if the journal data, the steel commitment and the proof are all valid. Concretely, in the erc20-counter example, the counter is only updated if the caller has a balance of at least one, and this counter update is gated by Steel and the zkVM.
Within a single proof, we’ve seen Steel can handle view calls orders of magnitude larger than onchain execution can handle. Specifically, one partner application has shown gas savings of 1.2 billion gas for a contract call using around 400,000 SLOADs. 1.2 billion gas is around 30 blocks worth of execution and this can be verified onchain in one proof, that costs under $10 to generate, and less than 300k gas to verify (see RISC Zero’s verification contracts). With proof aggregation, cost savings are amortized even further, by taking multiple separate applications of RISC Zero, and wrapping them all up into a single SNARK.