---
eip: 8282
title: Builder Execution Requests
description: Predeploy builder deposit and exit request contracts for EIP-7732 builders on the EIP-7685 request bus
author: Cayman (@wemeetagain), Nico Flaig <nflaig@protonmail.com>, Felix Lange <fjl@ethereum.org>, Justin Traglia <jtraglia@ethereum.org>
discussions-to: https://ethereum-magicians.org/t/eip-8282-builder-execution-requests/28699
status: Review
type: Standards Track
category: Core
created: 2026-05-22
requires: 1559, 7685, 7732
---

## Abstract

This EIP introduces two [EIP-7685](./eip-7685.md) request types and corresponding predeploy contracts for [EIP-7732](./eip-7732.md) builders. A builder deposit contract handles initial registration and stake top-ups. A builder exit contract lets a builder's `execution_address` trigger a full exit. Both contracts follow the request-bus pattern of [EIP-7002](./eip-7002.md) and [EIP-7251](./eip-7251.md). Builders no longer onboard through the validator deposit flow or exit through the voluntary-exit operation.

## Motivation

[EIP-7732](./eip-7732.md) introduces builders as a separate, staked consensus-layer actor, but reuses validator flows for their lifecycle. A builder is registered by a validator deposit whose withdrawal credential carries the `0xB0` `BUILDER_WITHDRAWAL_PREFIX`, and it exits through a builder branch of the voluntary-exit operation. Dedicated builder request types improve on this in several ways.

Dedicated types make the actor explicit from the request type alone. The consensus layer no longer routes deposits by inspecting credential prefixes, and the validator and builder registries are keyed independently.

A builder deposit's proof-of-possession is verified inline when the deposit is processed, unlike a validator deposit's, which is deferred to the churn-limited `pending_deposits` queue. Builder deposits carried on the validator deposit request inherit its high per-payload ceiling. A dedicated request type isolates the verification work and caps it at `MAX_DEPOSIT_REQUESTS_PER_BLOCK` per block.

Under [EIP-7732](./eip-7732.md), a builder can only exit with a signature from its BLS key, the same hot key that signs its bids. The exit contract instead authorizes exit by the builder's `execution_address`, as [EIP-7002](./eip-7002.md) does for validators.

Builders that must exist at the fork are unaffected. The [EIP-7732](./eip-7732.md) fork-transition onboarding of builder-credentialed pending deposits is retained, and only post-fork onboarding moves to the new contract.

## Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) and [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174).

### Constants

| Name | Value | Comment |
| --- | --- | --- |
| `BUILDER_DEPOSIT_CONTRACT_ADDRESS` | `0x0000bFF46984e3725691FA540a8C7589300D8282` | Predeploy address of the builder deposit contract |
| `BUILDER_EXIT_CONTRACT_ADDRESS` | `0x000064D678505ad48F8cCb093BC65613800E8282` | Predeploy address of the builder exit contract |
| `BUILDER_DEPOSIT_REQUEST_TYPE` | `0x03` | [EIP-7685](./eip-7685.md) request-type byte for builder deposits |
| `BUILDER_EXIT_REQUEST_TYPE` | `0x04` | [EIP-7685](./eip-7685.md) request-type byte for builder exits  |
| `SYSTEM_ADDRESS` | `0xfffffffffffffffffffffffffffffffffffffffe` | Address that invokes the end-of-block system call (as in [EIP-7002](./eip-7002.md)) |
| `MAX_DEPOSIT_REQUESTS_PER_BLOCK` | `64` | Maximum records the builder deposit contract drains into one block |
| `TARGET_DEPOSIT_REQUESTS_PER_BLOCK` | `8` | Per-block request count above which the fee rises for the deposit contract |
| `MAX_EXIT_REQUESTS_PER_BLOCK` | `16` | Maximum records the builder exit contract drains into one block |
| `TARGET_EXIT_REQUESTS_PER_BLOCK` | `2` | Per-block request count above which the fee rises for the exit contract |
| `MIN_REQUEST_FEE` | `1` | Minimum request fee, in wei |
| `REQUEST_FEE_UPDATE_FRACTION` | `17` | Controls the fee's rate of change |
| `BUILDER_MIN_DEPOSIT` | `1000000000000000000` | Minimum credited stake for a deposit, in wei (1 ETH — the [EIP-7732](./eip-7732.md) builder minimum) |
| `BUILDER_DEPOSIT_CONTRACT_RUNTIME_CODE` | *see [Reference Implementation](#reference-implementation)* | Runtime bytecode of the builder deposit contract |
| `BUILDER_EXIT_CONTRACT_RUNTIME_CODE` | *see [Reference Implementation](#reference-implementation)* | Runtime bytecode of the builder exit contract |

Final request-type values MUST be unique across all active [EIP-7685](./eip-7685.md) request types. Allocation is coordinated in consensus-specs, where the existing types are defined ([`electra/beacon-chain.md`](https://github.com/ethereum/consensus-specs/blob/e310d1c0d316e4dcc822164966c5bfa592adae2b/specs/electra/beacon-chain.md)).

### Deployment

Both contracts are deployed by a `CREATE2` factory ([EIP-7997](./eip-7997.md)). Each address is determined by the factory, a salt, and the contract's init code. The salt was mined so that the addresses above result from the current reference bytecode.

The contracts MUST be deployed before the fork that activates this EIP. If there is no code at either address once the EIP is active, every block from activation onward MUST be invalid.

### Request queue and system call

Both predeploys follow the [EIP-7002](./eip-7002.md) and [EIP-7251](./eip-7251.md) contract design, with minor tweaks, and reuse their storage layout. There is no Solidity-compatible ABI. Each contract dispatches on the caller and on `calldatasize` alone. Calls that match none of the cases below MUST revert.

#### Write path

A call from any address other than `SYSTEM_ADDRESS`, with calldata of exactly the contract's input size, submits a request. The contract MUST validate the request and the value sent (see below), append one record to its queue, increment the per-block count, and emit the accepted record as an anonymous log.

#### Fee getter

A call from any address other than `SYSTEM_ADDRESS`, with empty calldata, returns the current fee without modifying state. The contract MUST revert if any value is attached.

#### System call

At the end of each block, the contract is called by `SYSTEM_ADDRESS`. If any calldata is included, the queue is permanently disabled via an inhibitor. If no calldata is included, it MUST dequeue up to its per-block maximum of records (`MAX_DEPOSIT_REQUESTS_PER_BLOCK` or `MAX_EXIT_REQUESTS_PER_BLOCK`, oldest first), return their concatenation as its `request_data`, and reset the per-block count. Records beyond the cap remain queued for subsequent blocks.

The execution layer prepends the contract's request-type byte and includes `request_type ++ request_data` in the block requests list, committed via the `requests_hash` ([EIP-7685](./eip-7685.md)). The system call follows the same rules as in [EIP-7002](./eip-7002.md). It runs with a dedicated gas limit of `30_000_000` that does not count against the block gas limit. If either contract's system call fails, the block MUST be invalid.

### Request fee

Each request carries a fee, computed as in [EIP-7002](./eip-7002.md):

```
fee = fake_exponential(MIN_REQUEST_FEE, excess, REQUEST_FEE_UPDATE_FRACTION)
```

where `fake_exponential` is the [EIP-1559](./eip-1559.md)-style integer approximation of `MIN_REQUEST_FEE * e**(excess / REQUEST_FEE_UPDATE_FRACTION)`. The fee rises super-linearly while blocks contain more than the target number of requests and decays back to `MIN_REQUEST_FEE` otherwise. It is charged on top of any staked value and is left locked in the contract.

Both contracts are modified to apply fee increases for each write path, rather than at end-of-block, as in [EIP-7002](./eip-7002.md).

### Deposit requests

A deposit request is submitted by calling `BUILDER_DEPOSIT_CONTRACT_ADDRESS` with calldata of exactly `184` bytes:

| Bytes | Field | Description |
| --- | --- | --- |
| `0:48` | `pubkey` | 48-byte BLS public key |
| `48:80` | `withdrawal_credentials` | 32-byte commitment (`version` byte + `execution_address`) |
| `80:88` | `amount` | Big-endian `uint64`, in gwei |
| `88:184` | `signature` | 96-byte BLS proof-of-possession |

A deposit request serves both a builder's first deposit and subsequent top-ups. The contract MUST reject the request unless `amount * 1 gwei >= BUILDER_MIN_DEPOSIT` and `msg.value >= amount * 1 gwei + fee`. Any value beyond `amount * 1 gwei + fee` is retained by the contract and not credited to the builder.

On success the contract queues the 184 input bytes. The dequeued record is the input verbatim with `amount` converted to little-endian, as in [EIP-7002](./eip-7002.md). The contract does not verify the `signature`. It is carried in the record and verified by the consensus layer. Submitters SHOULD verify the proof-of-possession off-chain before broadcasting a first deposit.

### Exit requests

An exit request is submitted by calling `BUILDER_EXIT_CONTRACT_ADDRESS` with calldata of exactly `48` bytes, the `pubkey` of the builder to exit. The contract MUST require `msg.value >= fee`. No value is staked. On success it queues a record of `source_address (20) ++ pubkey (48)`, where `source_address` is `msg.sender`.

Authorization is by `source_address`, as in [EIP-7002](./eip-7002.md). The contract records `msg.sender` and performs no further check. The consensus layer honors the request only when `source_address` equals the target builder's `execution_address`.

### Consensus layer processing

The consensus layer decodes each dequeued record into one of two SSZ containers, selected by request type:

```python
class BuilderDepositRequest(Container):
    pubkey: Bytes48
    withdrawal_credentials: Bytes32
    amount: uint64  # Gwei
    signature: Bytes96

class BuilderExitRequest(Container):
    source_address: Bytes20
    pubkey: Bytes48
```

A type's `request_data` is the concatenation of the fixed-size SSZ serializations of its records, which is exactly the bytes the system call returns, in the same order. `BuilderDepositRequest` is the [EIP-6110](./eip-6110.md) `DepositRequest` without the `index` field.

Detailed state-transition behavior is specified in consensus-specs. In summary:

- A `BuilderDepositRequest` for a `pubkey` not in the builder registry registers a new builder if its `signature` is a valid proof-of-possession over `(pubkey, withdrawal_credentials, amount)` under `DOMAIN_BUILDER_DEPOSIT`, a builder-specific signing domain. A record with an invalid signature is ignored and its stake forfeited. Deposits are applied immediately rather than routed through the validator `pending_deposits` queue.
- A `BuilderDepositRequest` for an already-registered `pubkey` is a top-up. The `amount` is credited and the record's `withdrawal_credentials` and `signature` are ignored, as with validator deposits.
- A `BuilderExitRequest` initiates a full exit only if its `pubkey` is an active builder, its `source_address` equals that builder's `execution_address`, and the builder has no pending balance to withdraw. Otherwise the record is dropped rather than re-queued, and the request must be resubmitted.

### Changes to EIP-7732

#### Deposit routing

The builder branch of `process_deposit_request` is removed, so a deposit to the validator deposit contract is always an ordinary validator deposit. Builders are created and topped up only through `BUILDER_DEPOSIT_REQUEST_TYPE`. A post-fork deposit to the validator contract with a `0xB0` credential mints a validator that cannot withdraw its balance, so builder deposits MUST be sent to the builder deposit contract.

#### Fork-transition onboarding

The one-time [EIP-7732](./eip-7732.md) onboarding of builder-credentialed pending deposits at the fork is retained, so builders exist from the first slot. This is the only path that onboards builders through the validator deposit contract. The `0xB0` `BUILDER_WITHDRAWAL_PREFIX` is deprecated afterward.

#### Exit routing

The builder branch of `process_voluntary_exit` is removed, making the voluntary-exit operation validator-only. Builders exit only through `BUILDER_EXIT_REQUEST_TYPE`.

## Rationale

### Two predeploys, two request types

This mirrors withdrawals (`0x01`) and consolidations (`0x02`). The execution layer needs no new read semantics, and the consensus layer routes by request type rather than by inspecting credentials.

### One request for deposits and top-ups

This matches the validator deposit contract. The proof-of-possession is checked on a `pubkey`'s first appearance, and later deposits credit stake. A top-up cannot redirect a builder's withdrawals because its `withdrawal_credentials` and `signature` are ignored.

### Exit by `execution_address`

A builder's BLS key is hot, since it signs bids continuously, so it should not also authorize exits. Routing exit through the cold `execution_address` mirrors the [EIP-7002](./eip-7002.md) rationale for validator withdrawal credentials and gives builders a single, well-defined exit authorizer.

### Request fee

The same demand-responsive fee as [EIP-7002](./eip-7002.md) and [EIP-7251](./eip-7251.md) meters submission, together with the per-block caps and the per-deposit stake.

### Onboarding at the fork

Some applications depend on builders existing from the first slot of the fork, which post-fork deposits to the new contract cannot provide. The existing [EIP-7732](./eip-7732.md) onboarding path is therefore retained for the initial builder set.

## Backwards Compatibility

This EIP is additive at the execution layer. It introduces new contracts at previously empty addresses and does not modify the validator deposit contract or the validator request predeploys. At the consensus layer it modifies the [EIP-7732](./eip-7732.md) builder lifecycle as described in [Changes to EIP-7732](#changes-to-eip-7732). Builders onboarded at the fork are unaffected.

## Reference Implementation

See [`src/builder_deposits`](https://github.com/ethereum/sys-asm/tree/3bba94c696bc46beeecef05db6c2df0f18b4b239/src/builder_deposits) and [`src/builder_deposits`](https://github.com/ethereum/sys-asm/tree/3bba94c696bc46beeecef05db6c2df0f18b4b239/src/builder_exits).

## Security Considerations

### Exit authorization

The exit contract records `msg.sender` as `source_address` and performs no further check. The request carries no signature, so the `source_address` check during [consensus layer processing](#consensus-layer-processing) is the only exit authorization; without it an arbitrary caller could exit any builder.

### Signing-domain separation

Builder deposits are signed under `DOMAIN_BUILDER_DEPOSIT`, distinct from the validator `DOMAIN_DEPOSIT`, so deposit proofs-of-possession cannot be replayed across the two classes. Fork-transition seed deposits are made through the validator deposit contract and are necessarily signed under `DOMAIN_DEPOSIT`.

### Replayable deposit records

A deposit's fields are public in calldata, so a third party can resubmit them for an already-registered builder at an amount it funds itself. Such a replay is a top-up whose credentials and signature are ignored. It credits stake and redirects nothing.

### Custodial-split exit standoff

Exit requires a zero pending balance, every winning bid adds pending balance, and only the `execution_address` can authorize exit. Where the `execution_address` (capital owner) and the BLS key (bidding operator) are held by different parties, an operator that keeps winning bids can indefinitely block the owner's exit. Delegating parties should retain off-chain control over the operator's bidding.

### Spam and state growth

The per-block caps bound the drain rate, not enqueue, so the in-state queues can grow across blocks. Growth is gated by value, since each deposit locks at least `BUILDER_MIN_DEPOSIT` plus the fee. An attacker submitting valid proofs-of-possession forfeits nothing, because the stake remains a withdrawable builder balance, so post-fork onboarding can be delayed behind a backlog of attacker deposits at the cost of locked capital. This is tolerable because the time-critical initial builder set is seeded through the fork transition rather than the steady-state contract.

### Locked funds

The request fee, any overpayment, and the principal of a first deposit that the consensus layer rejects for an invalid proof-of-possession are permanently locked in the predeploy. The execution layer does not verify BLS signatures, so the off-chain proof-of-possession check advised in [Deposit requests](#deposit-requests) is a submitter's only protection against losing a first deposit's principal.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
