EIP-n: Beacon chain withdrawals on EVM


eip:
title: Beacon chain withdrawals on EVM
description: Enable withdrawals from the Beacon chain via a special contract on the EVM
author:
discussions-to:
status: Draft
type: Standards Track
category: Core
created: 2022-02-18
requires: 4788

Abstract

TBD

Motivation

TBD

Specification

Constant Value
FORK_BLOCK TBD
DEPOSIT_CONTRACT_ADDRESS 0x00000000219ab540356cBB839Cbe05303d7705Fa
WITHDRAWAL_CONTRACT_ADDRESS TBD
WITHDRAWAL_CODE_HASH TBD

Block validation

On FORK_BLOCK the code hash of the account WITHDRAWAL_CONTRACT_ADDRESS must equal to WITHDRAWAL_CODE_HASH, otherwise the block is invalid.

After FORK_BLOCK, before processing any transactions in a block, apply the following changes to the state:

  1. Set the balance of account DEPOSIT_CONTRACT_ADDRESS to 0.
  2. Set the balance of account WITHDRAWAL_CONTRACT_ADDRESS to blockHeader.totalBeaconValidatorBalance.

Block creation

Starting FORK_BLOCK the block header will contain one more field, called the totalBeaconValidatorBalancer at the last position. This field must be set to sum(BeaconState.balances).

Contract implementation

pragma solidity 0.8.12;

contract WithdrawalContract {
    struct WithdrawalReceipt {
        uint64 index;
        address recipient;
        uint64 amount;
    }

    error AlreadySpent();
    error InvalidProof();

    /// A bitmap of the spent receipt indexes.
    mapping (uint256 => uint256) public spent;

    function withdraw(WithdrawalReceipt calldata receipt, bytes calldata merkle_branch, uint256 merkle_root_slot) external {
        uint256 slot_index = receipt.index / 256;
        uint256 slot_bit = 1 << (receipt.index % 256);
        uint256 slot = spent[slot_index]; // Keeping a copy here is an SLOAD optimisation

        if (slot & slot_bit) revert AlreadySpent();

        // Reassemble SSZ-encoded leaf
        bytes memory leaf = ssz_hash_tree_root(receipt);

        bytes32 beacon_root;
        assembly {
            // This is the beaconstateroot(slot) instruction from EIP-4788.
            beacon_root := verbatim_1i_1o(hex"48", merkle_root_slot)
        }

        // Calculate proof of the branch
        ... using leaf + merkle_branch

        if (calculated_root != beacon_root) revert InvalidProof();

        // Mark as spent
        spent[slot_index] = slot | slot_bit;

        // TODO: use low-level transfer or the `TRANSFER` opcode (the potential future of `SELFDESTRUCT`) here? 
        receipt.recipient.transfer(receipt.amount * 1 gwei);
    }
}

This code is compiled using the specified Solidity version and settings (TBD) resulting in runtime bytecode equaling to WITHDRAWAL_CODE_HASH.

Rationale

Fork block and code hash

We ensure that on FORK_BLOCK the correct contract is exists in place of the WITHDRAWAL_CONTRACT_ADDRESS.

Alternatively we could choose to insert the code at the address on the FORK_BLOCK.

Ether supply accounting

In order to avoid special account rules, the withdrawal contract must be able to send an Ether balance. It would be possible to set once an arbitrary large balance for the account, and not touch anything else.

However we chose to keep total supply accounting in balance, by modifying the supply of both the deposit and withdrawal contracts at the beginning of the block. Transactions in a block can modify the balances by properly depositing and withdrawing, and so their balances should stay valid throughout the block.

There are two cases these balances could get out of sync:

  1. Either of these accounts are targets of a miner reward
  2. Either of these accounts are targets of a selfdestruct

Should these happen, these balances will vanish from the chain. A side-effect is that these two accounts become the ultimate burner addresses, instead of the commonly used 0x0000000000000000000000000000000000000000 account (among others).

Backwards Compatibility

This change will affect the balance of the deposit contract. Other contracts and services depending on this value may see some disruption. If they assume the balance can only grow, their assumption will be broken.

Security Considerations

TBA

Copyright and related rights waived via CC0.