Skip to content

Conversation

@dylanlott
Copy link
Contributor

@dylanlott dylanlott commented Oct 2, 2025

feat: adds a Flashbots provider and submitter

This PR adds a Flashbots provider and submit task to the Builder.

It configures the Flashbots provider from the configured relay URL and uses the builder's signer key to sign all of the bundles it submits to Flashbots.

The Flashbots rbuilder​ endpoint on Pecorino does not return a proper EthBundleHash​ when a bundle is submitted, in fact it simply returns an empty response upon success. The endpoint also does not support simulation, so the Flashbots submit task blindly sends the prepared bundle and logs any errors that are returned.

Closes ENG-1414
Closes ENG-1403

Copy link
Contributor Author

dylanlott commented Oct 2, 2025

@dylanlott dylanlott changed the base branch from dylan/update-alloy to graphite-base/158 October 7, 2025 01:15
@dylanlott dylanlott force-pushed the dylan/flashbots-provider branch from 91e0f7c to 178ed31 Compare October 7, 2025 01:15
@dylanlott dylanlott changed the base branch from graphite-base/158 to dylan/glibc October 7, 2025 01:15
@dylanlott dylanlott force-pushed the dylan/flashbots-provider branch from 178ed31 to 7f24250 Compare October 7, 2025 01:16
@dylanlott dylanlott force-pushed the dylan/flashbots-provider branch 2 times, most recently from 26149ac to d275db4 Compare October 7, 2025 01:24
@dylanlott dylanlott force-pushed the dylan/flashbots-provider branch from d275db4 to 514db31 Compare October 7, 2025 01:49
@dylanlott dylanlott force-pushed the dylan/glibc branch 2 times, most recently from a308c0a to b83f0e2 Compare October 7, 2025 21:43
@dylanlott dylanlott force-pushed the dylan/flashbots-provider branch from 514db31 to 14fa362 Compare October 7, 2025 21:43
@dylanlott dylanlott changed the base branch from dylan/glibc to graphite-base/158 October 8, 2025 09:16
@dylanlott dylanlott force-pushed the dylan/flashbots-provider branch from 14fa362 to cb97db3 Compare October 8, 2025 09:16
@graphite-app graphite-app bot changed the base branch from graphite-base/158 to main October 8, 2025 09:17
@dylanlott dylanlott force-pushed the dylan/flashbots-provider branch 2 times, most recently from 0d8762a to 017a945 Compare October 8, 2025 18:33
@dylanlott dylanlott changed the title wip: adds a flashbots provider feat: adds a flashbots provider Oct 8, 2025
@dylanlott dylanlott marked this pull request as ready for review October 8, 2025 18:41
@dylanlott dylanlott force-pushed the dylan/flashbots-provider branch from bbde89d to a6aac19 Compare October 8, 2025 19:06
- adds a Flashbots provider with the alloy MEV API extensions
- adds the logic for building Flashbots bundles in the builder
- adds the Flashbots submission task
@dylanlott dylanlott force-pushed the dylan/flashbots-provider branch from a6aac19 to bf0b272 Compare October 8, 2025 20:06
Comment on lines 145 to 155
Ok(Some(hash)) => {
tracing::info!(host_block_number = sim_result.host_block_number(), bundle_hash = ?hash, "bundle submitted to flashbots");
span_debug!(span, "bundle submitted to flashbots");
}
Ok(None) => {
tracing::info!(
host_block_number = sim_result.host_block_number(),
"bundle submitted to flashbots without error"
);
})
.inspect_err(|err| {
span_error!(span, %err, "failed to send bundle to Flashbots");
});
span_debug!(span, "bundle submitted to flashbots");
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some weirdness here because the rbuilder response doesn't adhere to the Flashbots spec and returns a completely empty response instead of a bundle hash when successfully submitted, but we also want to handle the case where the endpoint does return the expected response. So we log both.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate event

let bundle = match self.prepare(&sim_result).instrument(span.clone()).await {
Ok(b) => b,
Err(e) => {
tracing::error!(error = %e, "failed to prepare MEV bundle");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate event

Comment on lines 145 to 155
Ok(Some(hash)) => {
tracing::info!(host_block_number = sim_result.host_block_number(), bundle_hash = ?hash, "bundle submitted to flashbots");
span_debug!(span, "bundle submitted to flashbots");
}
Ok(None) => {
tracing::info!(
host_block_number = sim_result.host_block_number(),
"bundle submitted to flashbots without error"
);
})
.inspect_err(|err| {
span_error!(span, %err, "failed to send bundle to Flashbots");
});
span_debug!(span, "bundle submitted to flashbots");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate event

match response {
Ok(Some(hash)) => {
tracing::info!(host_block_number = sim_result.host_block_number(), bundle_hash = ?hash, "bundle submitted to flashbots");
span_debug!(span, "bundle submitted to flashbots");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate event

span_debug!(span, "bundle submitted to flashbots");
}
Ok(None) => {
tracing::info!(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate event

impl BuilderConfig {
/// Connect to the Builder signer.
pub async fn connect_builder_signer(&self) -> Result<LocalOrAws, SignerError> {
pub async fn connect_builder_signer(&self) -> eyre::Result<LocalOrAws> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this type changing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make it work with the error type try_join expects. The other connect_* functions return eyre::Result types, so it must match the others' return signatures.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ya makes sense

Copy link
Member

@prestwich prestwich Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ffr, you can use the FutureExt trait to map future output types in-line

https://docs.rs/futures/latest/futures/future/trait.TryFutureExt.html#method.or_else

in this case something like config.connect_builder_signer().or_else(|e| Err(e.into()))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try_join!(
   async_fn_1(),
   async_fn_2().or_else(|e| Err(e.into)),
)
 

span_debug!(span, "bundle submitted to flashbots");
}
Err(e) => {
tracing::error!(error = %e, "failed to submit MEV bundle to flashbots");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate event

@dylanlott dylanlott requested a review from prestwich October 20, 2025 18:52
@dylanlott dylanlott merged commit 9fac4e0 into main Oct 20, 2025
6 checks passed
@dylanlott dylanlott deleted the dylan/flashbots-provider branch October 20, 2025 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants