# Titan Relay

Titan operates a MEV-Boost compatible relay which can be found at the locations below:

<table data-full-width="false"><thead><tr><th width="152">Network</th><th>Relay URL</th></tr></thead><tbody><tr><td>Hoodi</td><td><a href="https://0xaa58208899c6105603b74396734a6263cc7d947f444f396a90f7b7d3e65d102aec7e5e5291b27e08d02c50a050825c2f@hoodi.titanrelay.xyz/">https://0xaa58208899c6105603b74396734a6263cc7d947f444f396a90f7b7d3e65d102aec7e5e5291b27e08d02c50a050825c2f@hoodi.titanrelay.xyz</a></td></tr><tr><td>Mainnet Global <br>(non-filtering)</td><td><a href="https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@titanrelay.xyz
">https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@global.titanrelay.xyz</a></td></tr><tr><td>Mainnet Regional (filtering)</td><td><a href="https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@regional.titanrelay.xyz/">https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@regional.titanrelay.xyz</a></td></tr></tbody></table>

These URLs use AWS geo-routing to find the best relay cluster to send to. We have found this can sometimes route requests to the wrong region, so we have also added specific geo-location URLs. You can drop these directly in place of `regional.titanrelay.xyz` or `global.titanrelay.xyz` in the above URLs.

**Global URLs:**

* `eu-global.titanrelay.xyz`
* `us-global.titanrelay.xyz`
* `tk-global.titanrelay.xyz`

**Regional URLs:**

* `eu-regional.titanrelay.xyz`
* `us-regional.titanrelay.xyz`
* `tk-regional.titanrelay.xyz`

## MEV-Boost Client Configuration

In order to include the Titan relay in your MEV boost configuration, simply append it to the list of relays in the command line arguments.

`./mev-boost -mainnet -relay-check -relays <relay1>,<relay2>`

Simply replace the placeholders `<relay1>` and `<relay2>` with the appropriate connection URL.


# Builders


# Builder Integration

This document outlines the key aspects of integrating with TitanRelay, a high-performance MEV-Boost relay. It supports standard APIs with a few enhancements for improved functionality and performance.

## Get Validators

We've added a "preferences" field to validator submissions, enabling relay-level PEPC (Protocol Enforced Proposer Commitments). Currently, we support two preferences:

1. `filtering`: The relay supports both filtering and non-filtering proposers under a single URL. Filtering is now per-proposer instead of per-relay.
2. `trusted_builders`: When signing up for optimistic relaying, you'll receive a BuilderID (e.g., "Titan"). Proposers can specify to only accept blocks from certain builders.

```rust
struct ValidatorPreferences {
    /// A string indicating which filtering policy to use ("regional" or "global").
    filtering: String,
    /// An optional list of BuilderIDs. If this is set, the relay will only accept
    /// submissions from builders whose public keys are linked to the IDs in this list.
    /// This allows for limiting submissions to a trusted set of builders.
    trusted_builders: Option<Vec<String>>,
}

struct BuilderGetValidatorsResponse {
    slot: u64,
    validator_index: usize,
    entry: SignedValidatorRegistration,
    preferences: ValidatorPreferences,
}
```

## Optimistic Relaying

### Optimistic V1

We support standard optimistic v1 relaying with up to 64 ETH collateral. See the Optimistic Relaying page for more details.

### Optimistic V2

{% hint style="warning" %}
This endpoint is now deprecated
{% endhint %}

We support OptimisticV2 submissions. If enabled for v1, you can submit to our v2 endpoints. OptimisticV2 decouples the lightweight header from the heavier payload, allowing for faster processing. See the original proposal [here](https://frontier.tech/optimistic-relays-and-where-to-find-them).

To send a block submission with OptimisticV2, you will need to call these two new endpoints:

1. `relay/v1/builder/headers:` Contains the header and signed bid trace.
2. `relay/v1/builder/blocks_optimistic_v2:` The submission struct is identical to the block submitted with the current `relay/v1/builder/blocks` endpoint.

```rust
struct HeaderSubmission {
    bid_trace: BidTrace,
    execution_payload_header: ExecutionPayloadHeader,
    blobs_bundle: BlobsBundle,
}

struct SignedHeaderSubmission {
    message: HeaderSubmissionDeneb,
    signature: BlsSignature,
}
```

We recommend submitting v2 alongside normal block submissions for extra redundancy and because v2 is still in the testing phase. We often over-demote so it’s best if you use separate pubkeys to mitigate the impact of incorrect demotions.

*Alongside changing the submission endpoints, you must also manually track your collateral to guarantee it covers the block value and ensure a valid full block is received within 2 seconds of a valid header submission to avoid demotion.*

### Optimistic V3

{% hint style="warning" %}
This endpoint is not currently implemented
{% endhint %}

Optimistic v3 submissions are enabled at `relay/v3/builder/headers`

```rust
struct HeaderSubmissionV3 {
    url: Vec<u8>,
    tx_count: u32,
    submission: SignedHeaderSubmission,
}
```

Where `SignedHeaderSubmission` is the same as for V2. When submitting a header you need to ensure that the corresponding payload is available at `[url]/get_payload_v3` . The relay may send a request for the payload via a ssz-encoded `SignedGetPayloadV3` request:

```rust
struct GetPayloadV3 {
    /// Hash of the block header from the `SignedHeaderSubmission`.
    block_hash: B256,
    /// Timestamp (in milliseconds) when the relay made this request.
    request_ts_millis: u64,
    /// Relay's public key
    relay_pubkey: BlsPublicKey,
}


struct SignedGetPayloadV3 {
    message: GetPayloadV3,
    signature: BlsSignature,
}
```

The builder is expected to timely return the corresponding `SignedBidSubmission` , failure to do so may result in a missed slot and collateral slashing. Collateral requirements are the same as for V2 submissions.

Read more about v3 [here](https://ethresear.ch/t/introduction-to-optimistic-v3-relays/22066).

## Block deltas

To optimise bandwidth utilisation we support sending *dehydrated* payloads for V1 submissions. A builder may submit transactions and blobs only once per slot. Subsequent submissions within the same slot can reference those orders by their hash or proof, and the relay will rehydrate the payload using a local cache.

```rust
struct DehydratedBidSubmissionFulu {
    message: BidTrace,
    execution_payload: ExecutionPayload,
    blobs_bundle: DehydratedBlobsFulu,
    execution_requests: ExecutionRequests,
    signature: BlsSignature,
    tx_root: Option<B256>,
}

struct DehydratedBlobsFulu {
    /// List of commitments to re-hydrate the BlobsBundle
    commitments: Vec<KzgCommitment>,
    new_items: Vec<BlobItemFulu>,
}

struct BlobItemFulu {
    proof: Vec<KzgProof>,
    commitment: KzgCommitment,
    blob: Blob,
}
```

The transaction hashes are directly reusing the `transaction` field in the `ExecutionPayload`. To enable block deltas make sure to add a `x-hydrate` header to the submission.

You can refer to the full rehydration logic [here](https://github.com/gattaca-com/helix/blob/develop/crates/types/src/hydration.rs).

## Submission Headers

* `Content-Encoding` : optional, supported values: `gzip`, `zstd` . Default is no compression
* `Content-Type` : optional, supported value: `application/octet-stream` for SSZ encoding. Default is json encoding
* `x-api-key` : optional, if present and matching with an optimistic pubkey, signature verification will be skipped
* `x-hydrate`: optional, if present enables block deltas submissions (NB: `x-api-key` required for this!)
* `x-sequence` : optional, if present the relay will reject lower sequence numbers received for the same slot / pubkey

## TCP Bid Submissions

As an alternative to HTTP `submitBlock` for latency-sensitive builders the relay exposes a persistent TCP endpoint. Contact us directly to get access to it.

### Framing

Every message in both directions is wrapped in the same 12-byte frame header. The timestamp is recorded by the relay for latency tracking and does not affect processing.

```
[4B LE u32  payload_len]
[8B LE u64  timestamp_nanos]
[payload_len bytes  payload]
```

### Session lifecycle

A session consists of three phases: connection, registration, bid submissions. There is no teardown handshake; either side may close the connection at any time.

#### 1. Registration Message

The first frame sent after connecting must be a registration message. It identifies the builder to the relay so that subsequent submissions do not need to carry credentials. The relay validates the `(api_key, builder_pubkey)`and if validation fails the connection is dropped immediately. On success the relay is ready to accept bid submissions.

The `api_key` is the same UUID used in the HTTP `x-api-key` header. The `builder_pubkey` is the BLS public key of the builder.

**SSZ-encoded Payload**

```
[16B  api_key        — UUID, raw bytes]
[48B  builder_pubkey — BLS public key, raw bytes]
```

#### 2. Bid Submissions

Bid submission payload begins with a 6-byte header that carries metadata, followed by the block submission body — identical in format to the HTTP SSZ-encoded `submitBlock` body.

The `sequence_number` is a client-managed per-slot counter. It is echoed back in the response so that the client can match responses to submissions when multiple bids are in-flight simultaneously. It must be unique within a slot; duplicate sequence numbers are rejected.

**Payload:**

```
[6B   header]
[...  SSZ-encoded block submission (same body as HTTP submitBlock)]
```

**Header — 6 bytes:**

```
[4B BE u32  sequence_number]   — per-slot counter; must be unique per slot
[1B         merge_type]        — 0=None  1=Mergeable  2=AppendOnly
[1B         flags]             — bitmask (see below)
```

`merge_type` bit setting is not in use currently, and should be left empty.

**Flags:**

| Bit | Name               | Description                                                                       |
| --- | ------------------ | --------------------------------------------------------------------------------- |
| 0   | `IS_DEHYDRATED`    | payload is a dehydrated block                                                     |
| 1   | `WITH_ADJUSTMENTS` | payload includes bid adjustments **(not in use currently, should be left empty)** |
| 2   | `ZSTD_COMPRESSED`  | payload body is zstd-compressed                                                   |

#### 3. Responses

On success (`status=0`) `error_msg` is empty. On failure the relay populates `error_msg` with a human-readable UTF-8 description of the rejection reason, and `request_id` can be used to correlate the failure with relay-side logs.

**Payload — SSZ-encoded `BidSubmissionResponse`:**

```
[4B LE u32   sequence_number]   — echoes the submission's sequence_number
[16B         request_id]        — UUID assigned by the relay
[1B          status]            — 0=Okay  1=InvalidRequest  2=InternalError
[4B LE u32   error_msg_offset]  — SSZ variable-length offset (always 25)
[...         error_msg]         — UTF-8 string
```

### Reconnection

The relay may close the connection at slot boundaries or on internal errors. Clients should detect disconnection and reconnect, sending a fresh registration message before resuming submissions. The `sequence_number` counter should be reset to zero at the start of each slot.

## Websocket TopBid Stream

We provide a websocket stream at the endpoint `builder/top_bid` that sends real-time updates whenever a new top bid is received by the relay. Each time a new best bid is processed, a message containing the updated bid information will be pushed to connected clients. Authentication for this stream is done using an `x-api-key` header.

The structure of the `TopBidUpdate` message is as follows:

```rust
struct TopBidUpdate {
    timestamp: u64,
    slot: u64,
    block_number: u64,
    block_hash: B256,
    parent_hash: B256,
    builder_pubkey: BlsPublicKey,
    fee_recipient: Address,
    value: U256,
}
```

To access the TopBid stream, builders must meet three criteria:&#x20;

* Build ≥ 0.10% of all MevBoost blocks (weekly rolling basis)
* Submit ≥ 90% of blocks built
* Supply ≥ 0.1 ETH as optimistic collateral

## Relay Locations

* NV: `us-east-1`
* FR: `eu-central-1`
* TK: `ap-northeast-1`


# Optimistic Relaying Process

Simple guide for Builders wanting to use Optimistic Relaying

h/t to our friends at [ultrasound relay](https://relay.ultrasound.money/) for devising the Optimistic Relaying process.

### Notes

* Promoting a builder pubkey to Optimistic is a manual process - please reach out to us to have this enabled.
* Optimistic relaying will only happen if your builder pubkeys are promoted by us and the associated collateral is greater than the bid value.
* Following a demotion, Optimistic relaying will be manually re-enabled only once the underlying root cause has been identified and addressed.
* Please reach out to us to link multiple pubkeys to the same Builder ID&#x20;

## Collateral

* Collateral must be posted to `titanrelay.eth` from your primary builder fee recipient address.
* Maximum collateral per pubkey is currently `64` ETH for optimistic v1 and `32` ETH for optimistic v2 (subject to change).
* If you would like to have your collateral returned and stop optimistic relaying please reach out to us.

## Incidents

* If a proposer is the victim of an incident related to a bad bid they must be made whole by the Builder of the full bid value.
* Builders are expected to send ETH directly to the proposers fee recipient address to make them whole within 24 hours of the incident occurring.
* If proposers aren't made whole within 24 hours we may use the Builders' collateral to compensate the proposer directly.
* We reserve the right to publish a public post-mortem of any incidents relating to bad bids.

## Filtering

* While we are strongly committed to network neutrality and censorship resistance, we are also realists and understand that some proposers, particularly in the US, may face regulatory and/or reputational risks based on dynamic and/or grey area interpretations. So we provide proposers with a choice. By default their blocks are not filtered but if they opt in to filtering then they will be.
* There are 2 aspects to filtering:
  * The builder is informed via the BuilderGetValidatorsResponse that they must filter out transactions that touch a blacklisted address. This list is currently based upon the OFAC List.
  * Blocks are screened by the relay to ensure the builder has adhered the blacklist policy.
* There are 3 ways the screening on the relay side can be handled when the builder has opted in to optimistic relaying:
  * The default  approach: This disables optimistic relaying for these slots to ensure that all blocks have been fully screened before being accepted by the auctioneer.
  * The optimistic filtering approach: Builders may opt into optimistic filtering if they meet the following criteria:

    * At least 180 days of optimistic submissions
    * No demotions for submitting blocks containing blacklisted transactions in the past 90 days

    In this mode, blocks are provisionally accepted prior to full screening.\
    If a block fails screening, the builder is immediately suspended from optimistic filtering until the issue is resolved.
  * The bespoke approach: Proposers who are uncomfortable with the optimistic filtering approach can opt out by disabling optimistic relaying for their slots. In the future, they may also have the option to select trusted builders for optimistic submissions.

#### List of builders approved for optimistic filtering:

* Titan
* BuilderNet
* BobTheBuilder

{% hint style="info" %}
If your builder meets the criteria and you would like to be add contact us
{% endhint %}


# Proposers


# Registrations

This guide details how to interact with the /eth/v1/builder/validators endpoint, including optional authentication and customising validator preferences.

**NB**: If your client does not support add custom headers. Please contact us and we can manually enable the below features for your validators.

### Optional Authentication with the `x-api-key` Header

Users can obtain an api key from us and Authenticate via the `x-api-key` header. Validators registered with a valid authentication header will automatically skip any delay before `get_payload` is returned.

Example:

```
x-api-key: hcDL4sdCpIDgg6rvFkdUWdNc
```

### Customizing Validator Preferences with the `x-preferences` Header

Users can customize preferences for validators by including the `x-preferences` header with a JSON string of their settings.

Preferences include:

* `filtering:` A string indicating which filtering policy to use ("regional" or "global").&#x20;
* `trusted_builders`: Specify a list of builders whose blocks are accepted.&#x20;
* `header_delay`: If set to false, will disable any relay-level delays for the `get_header` response.

Example:

```
x-preferences: {"filtering": "global", "trusted_builders": ["Titan", "Beaver", "Rsync"], "header_delay": false}
```

### Default Preferences

In the absence of the `x-preferences` header, the following defaults apply:

* **Filtering**: `"global"` (no filtering).
* **Header Delay**: `true` (relay-level `get_header` delays enabled).
* **Trusted Builders**: `no default` (if you do not want to enforce any Trusted Builder rules, omit this key).

Specifying a single preference (e.g., `{"header_delay": false}`) overrides only that setting, with others remaining at their default values.


# Get Header

We support the following http headers for `get_header` calls:

* `X-MEVBoost-StartTimeUnixMS` / `Date-Milliseconds` : optional, should be set to the local unix timestamp in milliseconds just before the `get_header` call is started
* `x-timeout-ms` : optional, should be set to the timeout in millisecond that the client has set for the call


