Skip to Content
Blockchain specificsEthereumEVM as L2

EVM as L2

The Ethereum Virtual Machine (EVM) is the most widely deployed programmable execution environment in blockchain. Using the EVM as a Gummiworm L2 ledger allows existing Solidity contracts to run at L2 speed on Cardano, with L1 settlement handled by the standard Gummiworm protocol. Existing Ethereum development tools — Hardhat, Foundry, MetaMask, ethers.js — interact with the Gummiworm EVM head without modification, since it exposes a standard Ethereum JSON-RPC interface.

Note

This section is a sketch of how the Ethereum Virtual Machine could be used as a black-box L2 ledger in a Gummiworm head. The details here are indicative, not final.

Note

This article uses Cardano as the L1 for illustrative purposes. Using a different L1 would change the specifics — the asset model, address format, and precompile interfaces — but the overall structure of the EVM L2 integration would remain the same.

State

The main compartment holds the EVM world state:

  • accounts: HashMap<Address, Account> — the EVM account state
  • chain_id: u64 — set at head initialization; used by EIP-155 transaction signatures to prevent replay across chains
  • block_number: u64 — incremented with each Gummiworm block

An EVM account consists of:

  • balance: u256 — the account’s native token balance (ADA in a Cardano-backed head), denominated in the head’s configured base unit
  • nonce: u64 — incremented on each transaction sent; provides replay prevention
  • code: bytes — the account’s deployed bytecode (empty for externally-owned accounts, i.e. regular user wallets)
  • storage: HashMap<bytes32, bytes32> — the account’s persistent key-value storage

Cardano native tokens other than ADA are not held in the EVM account struct. Instead, all Cardano native tokens are managed by a single multi-token precompile at a fixed well-known address. The precompile tracks balances in a table keyed by (Address, AssetClass), where an asset class is a (policyId, assetName) pair — the standard Cardano identifier for a fungible token type. This per-account, per-asset-class structure means the full Cardano Value held by any given EVM address can always be reconstructed by combining its native balance (ADA) with all its entries in the precompile’s table. The precompile exposes functions analogous to ERC-20 (balanceOf, transfer, transferFrom) parameterized by asset class. For interoperability with existing ERC-20-aware tooling, thin wrapper contracts can be auto-deployed at deterministic addresses (derived from each asset class) that delegate to the central precompile — making each Cardano native token appear as a standard ERC-20 to any wallet or contract that expects one.

The deposit compartments hold pending deposit state:

  • pending_deposits: HashMap<RequestId, (Address, Value)> — the target EVM address and deposited assets for each unresolved deposit request

Deposit request

The L2 payload of a deposit request consists of:

  • target_address: Address — the EVM address to receive the deposited funds
  • evacuation_destination: Option<(L1Address, Datum)> — the Cardano address and optional datum where this EVM address’s funds should be remitted on evacuation. Defaults to the deposit’s refundDestination if omitted.

Upon registration, if valid, a new entry is added to pending_deposits.

If the head peers decide to absorb the deposit, the deposited value is decomposed:

  • The ADA component is credited to target_address’s native balance
  • Each non-ADA component is credited to target_address in the multi-token precompile’s balance table, keyed by (target_address, assetClass)

The evacuation destination for target_address is updated. These changes are reported to Gummiworm as an evacuation map update.

If the head peers decide to reject the deposit, the pending deposit entry is removed.

Transaction request

The L2 payload of a transaction request is an RLP-encoded, EIP-155-signed EVM transaction. The EVM executes the transaction in the context of the current world state, using the Gummiworm block’s block number and a timestamp derived from the L1.

The nonce field in the EVM transaction serves as Gummiworm’s replay prevention mechanism. A transaction is invalid if its nonce does not match the sender’s current account nonce.

Withdrawals to L1

The EVM cannot natively express “produce a Cardano transaction output as a side effect.” To bridge this gap, the Gummiworm EVM head provides a bridge precompile at a well-known address. Calling it deducts the specified amount from the caller’s balance and reports an immediate L1 payout to Gummiworm, which remits it via the next settlement or rollout effect — identical in behavior to the l1outputs mechanism in the EUTXO L2.

The bridge precompile exposes a single withdrawal function that accepts a full Cardano Value — lovelace plus any number of native tokens — in one atomic call:

struct TokenAmount { bytes28 policyId; bytes32 assetName; uint256 amount; } function withdraw( bytes calldata l1Address, bytes calldata l1Datum, uint256 lovelace, TokenAmount[] calldata tokens ) external;

Both the bridge precompile and the multi-token precompile are precompiles in the standard EVM sense — fixed addresses backed by native code rather than EVM bytecode, in the same tradition as Ethereum mainnet’s ecRecover (0x01) or KZG point evaluation (0x0a), and analogous to the custom precompiles added by Arbitrum, Optimism, and Cosmos-based EVM chains for their chain-specific functionality. Because both are implemented natively rather than as EVM contracts, the bridge precompile can directly deduct from msg.sender’s ADA balance and from the multi-token precompile’s balance table for msg.sender in a single atomic operation. From a contract developer’s perspective, calling either precompile is indistinguishable from calling a smart contract.

The bridge precompile also supports producing oracle deposits on L1, as described in Chainlink via Gummiworm.

Smart contract deployment

Smart contracts are deployed via normal EVM CREATE or CREATE2 transactions, which are ordinary transaction requests. No special Gummiworm handling is required.

Evacuation map

The evacuation map is HashMap<EVMAddress, (EvacuationDestination, Value)>, keyed by EVM address. Each EVM address independently registers its own L1 evacuation destination, and its Value is reconstructed by combining its native balance (ADA) with all entries in the multi-token precompile’s balance table whose key begins with that address — one quantity per asset class.

Evacuation destinations are set via the evacuation_destination field of the deposit request L2 payload, falling back to refundDestination if omitted. Since refundDestination is always present in a deposit, every address that has absorbed a deposit has a registered destination.

Any address can update its registered destination at any time, or register one for the first time, by calling the bridge precompile:

function setEvacuationDestination( bytes calldata l1Address, bytes calldata l1Datum ) external;

Only msg.sender can update its own entry. The one edge case where an address may hold assets without a registered destination is if it received funds exclusively via EVM-internal transfers — for example, a contract funded by another contract rather than by a deposit. Such addresses fall back to the head’s configured recovery address on evacuation. Contract developers are responsible for calling setEvacuationDestination during deployment if their contract is intended to hold assets.

Design considerations

Gas: The head operates with a configurable base fee denominated in ADA. For most private or permissioned deployments — such as the Chainlink integration — the head can set a nominal gas price. Gas is a configuration concern for the head operators rather than a market-priced resource inside the head.

Block parameters: block.number increments with each Gummiworm block. block.timestamp is derived from the Gummiworm block’s creation start time. block.basefee, block.difficulty, and similar parameters are set at head initialization.

Signature scheme: Standard EVM transactions use secp256k1 ECDSA signatures. These are independent of Cardano’s Ed25519 signing scheme — users interact with the EVM head using Ethereum-compatible wallets (such as MetaMask), while Cardano L1 security is unaffected by the choice of L2 signing scheme.

Last updated on