System Contracts Usage


System Contracts Usage

Many EVM instructions require special handling by the System Contracts. Among them are: ORIGIN, CALLVALUE, BALANCE, CREATE, SHA3, and others. To see the full detailed list of instructions that require special handling, see the EVM instructions reference.

There are several types of System Contracts from the perspective of how they are handled by the zkSync Era compilers:

  1. Environmental data storage.
  2. KECCAK256 hash function.
  3. Contract deployer.
  4. Ether value simulator.
  5. Simulator of immutables.
  6. Event handler.

Environmental Data Storage

Such storage contracts are accessed with static calls in order to retrieve values for the block, transaction, and other environmental entities: CHAINID, DIFFICULTY, BLOCKHASH, etc.

One good example of such contract is SystemContextopen in new window that provides the majority of the environmental data.

Since EVM is not using external calls for these instructions, we must use the auxiliary heap for their calldata.

Steps to handle such instructions:

  1. Store the calldata for the System Contract call on the auxiliary heap.
  2. Call the System Contract with a static call.
  3. Check the return status code of the call.
  4. Revert or throw if the status code is zero.
  5. Read the ABI data and extract the result. All such System Contracts return a single 256-bit value.
  6. Return the value as the result of the original instruction.

For reference, see the LLVM IR codegen source codeopen in new window.

KECCAK256 Hash Function

Handling of this function is similar to Environmental Data Storage with one difference:

Since EVM also uses heap to store the calldata for KECCAK256, the required memory chunk is allocated by the IR generator, and zkSync Era compiler does not need to use the auxiliary heap.

For reference, see the LLVM IR codegen source codeopen in new window.

Contract Deployer

See handling CREATE and dependency code substitution instructions on zkSync Era documentation.

For reference, see LLVM IR codegen for the deployer callopen in new window and CREATE-related instructionsopen in new window.

Ether Value Simulator

EraVM does not support passing Ether natively, so this is handled by a special System Contract called MsgValueSimulatoropen in new window.

An external call is redirected through the simulator if the following conditions are met:

  1. The call has the Ether value parameter.
  2. The Ether value is non-zero.

Calls to the simulator require extra data passed via ABI using registers:

  1. Ether value.
  2. The address of the contract to call.
  3. The system call bitopen in new window, which is only set if a call to the ContractDeployer is being redirected, that is CREATE or CREATE2 is called with non-zero Ether.

Passing Ether value in EraVM is implemented by using a combination of:

The process of setting up a value and capturing it is described in details in the section Context Register of the EraVM specificationopen in new window.

For reference, see the LLVM IR codegen source codeopen in new window.

Simulator of Immutables

See handling immutables on zkSync Era documentation.

For reference, see LLVM IR codegen for instructions for immutablesopen in new window and RETURN from the deploy codeopen in new window.

Event Handler

Event payloads are sent to a special System Contract called EventWriteropen in new window. Like on EVM, the payload consists of topics and data:

  1. The topics with a length-prefix are passed via ABI using registers.
  2. The data is passed via the default heap, like on EVM.

For reference, see the LLVM IR codegen source codeopen in new window.

Auxiliary Heap

Both zksolc and zkvyper compilers for EraVM operate on the IR level, so they cannot control the heap memory allocator which remains a responsibility of the high-level source code compilers emitting the IRs.

However, there are several cases where EraVM needs to allocate memory on the heap and EVM does not. The auxiliary heap is used for these cases:

  1. Returning immutables from the constructor.
  2. Allocating calldata and return data for calling the System Contracts.

While the ordinary heap contains calldata and return data for calls to user contracts, auxiliary heap contains calldata and return data for calls to System Contracts. This ensures better compatibility with EVM as users should be able to call EraVM-specific System Contracts in a transparent way, without System Contracts affecting calldata or return data. This prevents situations where calling System Contracts interferes with the heap layout expected by the contract developer.

For more details on the heaps, refer to the EraVM specification, which describes types of heapsopen in new window, their connections to the stack frames and memory growthopen in new window, and their role in communication between contractsopen in new window.