From 83a2a51221568491103b25ec3578c376c2ec1eab Mon Sep 17 00:00:00 2001 From: Bhakiyaraj Kalimuthu Date: Wed, 27 Jul 2022 12:45:09 +0200 Subject: [PATCH 001/255] update open job position link to greenhouse (#286) --- docs/joining-flashbots.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/joining-flashbots.mdx b/docs/joining-flashbots.mdx index b6110129..bbc78ddb 100644 --- a/docs/joining-flashbots.mdx +++ b/docs/joining-flashbots.mdx @@ -5,7 +5,7 @@ title: join flashbots ### Interested in joining Flashbots? We are not your typical project, we are fully remote and our principles are based on that of a [pirate hacker collective](https://www.youtube.com/watch?v=T0fAznO1wA8). If you are a self-directed individual who puts collective success above your own and are motivated by solving hard problems with asymmetric impact, you will fit right in. -* [open job positions](https://www.notion.so/flashbots/Flashbots-Job-Board-94d53cb01ef04a9484711dacf18739e3) - full-time roles we're actively recruiting for. +* [open job positions](https://boards.greenhouse.io/flashbots) - full-time roles we're actively recruiting for. * [flashbots research fellowship](https://github.com/flashbots/mev-research/blob/main/grants.md) - we issue research grants to flashbots research proposals submitters. Find out more in our research repo. * flashbots part-time contractor - become a part-time contractor in Flashbots and join one of our ongoing projects. Reach out to the team to learn more! * nothing fits in the above? reach out at jobs@flashbots.net From 3b36b23ac0204281d9f9cae97b2a65a6561f14b3 Mon Sep 17 00:00:00 2001 From: brock <2791467+zeroXbrock@users.noreply.github.com> Date: Fri, 12 Aug 2022 03:26:54 -0700 Subject: [PATCH 002/255] fix broken & missing alchemy links (#287) --- docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx | 4 +++- docs/flashbots-auction/searchers/quick-start.mdx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx b/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx index 043575ce..432e4a2a 100644 --- a/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx +++ b/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx @@ -144,7 +144,7 @@ example response: `eth_sendPrivateTransaction` is used to send a single transaction to Flashbots. Flashbots will attempt to send the transaction to miners for the next 25 blocks. See [Private Transactions](/flashbots-auction/searchers/advanced/private-transaction.mdx) for more info. -[`eth_sendPrivateTransaction`](https://docs.alchemy.com/alchemy/apis/ethereum/eth-sendPrivateTransaction/?a=fb) is also supported for free on [Alchemy](https://alchemy.com/?a=fb). +[`eth_sendPrivateTransaction`](https://docs.alchemy.com/reference/eth-sendprivatetransaction?a=fb) is also supported for free on [Alchemy](https://alchemy.com?a=fb). This method has the following JSON-RPC format: @@ -192,6 +192,8 @@ example response: The `eth_cancelPrivateTransaction` method stops private transactions from being submitted for future blocks. A transaction can only be cancelled if the request is signed by the same key as the `eth_sendPrivateTransaction` call submitting the transaction in first place. +[`eth_cancelPrivateTransaction`](https://docs.alchemy.com/reference/eth-cancelprivatetransaction?a=fb) is also supported for free on [Alchemy](https://alchemy.com?a=fb). + This method has the following JSON-RPC format: ```json diff --git a/docs/flashbots-auction/searchers/quick-start.mdx b/docs/flashbots-auction/searchers/quick-start.mdx index 43d50563..8fd528af 100644 --- a/docs/flashbots-auction/searchers/quick-start.mdx +++ b/docs/flashbots-auction/searchers/quick-start.mdx @@ -27,7 +27,7 @@ To access the Flashbots network you will need three things: 1. A private key that Flashbots can use to identify you 2. A way to interact with the Flashbots network - - [Alchemy](https://docs.alchemy.com/alchemy/apis/ethereum/eth-sendPrivateTransaction/?a=fb) offers an easy way to send single transactions to Flashbots + - [Alchemy](https://docs.alchemy.com/docs/how-to-send-a-private-transaction-on-ethereum?a=fb) offers an easy way to send single transactions to Flashbots. 3. A "bundle" for your transactions Let's begin with the private key Flashbots uses for identity. When you send bundles to Flashbots you will sign them with a private key so that we can establish identity for searchers and establish reputation for them over time. This private key **does not** store funds and is **not** the primary private key you use for executing transactions. Again, it is only used for identity, and it can be any private key. From b98ad6e9040fb687eca1e942a1518ce6bde8fe48 Mon Sep 17 00:00:00 2001 From: Bhakiyaraj Kalimuthu Date: Tue, 16 Aug 2022 11:08:07 +0200 Subject: [PATCH 003/255] update note for fast mode tx (#289) * update note for fast mode tx * update default eviction period --- docs/flashbots-protect/rpc/fast-mode.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/flashbots-protect/rpc/fast-mode.md b/docs/flashbots-protect/rpc/fast-mode.md index a8776f76..7dd37117 100644 --- a/docs/flashbots-protect/rpc/fast-mode.md +++ b/docs/flashbots-protect/rpc/fast-mode.md @@ -33,3 +33,6 @@ Please note that fast mode transactions *cannot* be cancelled using the [`eth_ca You should use fast mode if you want to be included in blocks as soon as possible and if your transactions are unlikely to revert. For example, if you are trading on a DEX that doesn't see much volume. If you think your transaction might revert, or if being at the top of the block matters a lot to you, you should use Flashbots Protect without fast mode. + +## Note +Fast mode transaction does not have 25 blocks limit, It will be sent to miner's private transaction mempool. Transaction remains there until either included or evicted, Default eviction period is 3 days but miners might have their own eviction period. From 1e7f39e9883bb9c3d091e4a9b85feda6800cc50e Mon Sep 17 00:00:00 2001 From: brock <2791467+zeroXbrock@users.noreply.github.com> Date: Fri, 26 Aug 2022 12:32:41 -0700 Subject: [PATCH 004/255] add searching post-merge questions to FAQ (#295) --- docs/flashbots-auction/searchers/faq.md | 83 ++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/docs/flashbots-auction/searchers/faq.md b/docs/flashbots-auction/searchers/faq.md index 4d5a950e..ed71dd52 100644 --- a/docs/flashbots-auction/searchers/faq.md +++ b/docs/flashbots-auction/searchers/faq.md @@ -3,7 +3,7 @@ title: FAQ --- *Check Flashbots Discord [#release](https://discord.com/invite/7hvTycdNcK) channel for the latest releases.* -Don't see your question answered? Join our dedicated [#🤖searchers](https://discord.com/invite/7hvTycdNcK) channel on Discord! +Don't see your question answered? Join our dedicated [#🤖searchers](https://discord.com/invite/7hvTycdNcK) channel on Discord and be sure to check out our [Searchers Self Support Group](https://collective.flashbots.net/c/searchers/12)! ### What is Flashbots Auction? @@ -208,4 +208,83 @@ Your previous bundle is dropped if the new bundle is more valuable. ### Where can I view the health status of Flashbots' infrastructure? -Status is reported at https://status.flashbots.net/. Please check this link for any network outages or downtime. \ No newline at end of file +Status is reported at https://status.flashbots.net/. Please check this link for any network outages or downtime. + +### How will sending bundles change in PoS Ethereum? + +Sending bundles will feel very much the same as it does with Flashbots PoW Ethereum infrastructure. You’ll still be able to send & simulate atomic bundles, and use the same bidding strategies in the blockspace/MEV auction. + +The real difference is in the backend architecture. + +`relay.flashbots.net` (where bundles are sent in PoW Ethereum) will send bundles to the Flashbots builder after the merge. On the searcher side, the method for sending bundles to flashbots doesn’t change at all. All Flashbots relay endpoints from PoW Ethereum will be the same post-merge. + +With PBS, you may want to send bundles to more builders than just Flashbots. Other builders will need to implement their own version of this bundle relay to accept bundles, but as long as other builders adhere to the same API specification as Flashbots, you can use existing Flashbots client libraries to interact with these builders. + +### How do I choose a good block builder? + +There are a few criteria to look for in a block builder: + +* Are they committed to fair and unbiased execution? + * A good builder will not front-run, sandwich or censor bundles, or otherwise engage in activities that abuse privileged data access. +* Do they connect to a trusted relay? + * Keep in mind that the relay can also see raw transactions, which gives them the ability to front-run, censor, etc. +* Does their relay connect to enough validators? + * The more validators a relay connects to, the more slots will generally be available for builders connected to that relay. When you’re targeting a specific block/slot, it’s imperative that you send your transactions to a builder which is connected to the validator responsible for proposing a block in that slot. More validators ⇒ better inclusion rates. + * Note: Any validator can [use mev-boost to connect to the Flashbots relay and other relays](https://github.com/flashbots/mev-boost#usage). + * It’s also worth considering how much collective stake the validators connected to a relay have. Generally speaking, if more than one block is proposed to the network (unusual but possible), the block with the most collective stake attesting to it will be included. This scenario is explained in greater detail in the [Ethereum docs](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#fork-choice). + +Also note that block builders have the freedom to specialize. You may find that one builder is more or less friendly to your strategy than others. Builders are competing with each other, so they are all incentivized to include your bundles in their blocks, but you may find that some builders will prioritize certain strategies over others regardless of potential profits. Builders might also censor certain bundles due to local regulations or corporate strategies and policies. There are a lot of variables in play here, so I recommend trying a few trusted builders and seeing how your mileage varies first-hand. + +Flashbots will run a builder that follows the same principles we’ve adhered to in PoW Ethereum: democratized access to MEV, fair & reliable execution, and privacy. + +### How are “relays” defined in PoS Ethereum? + +Before the merge, mev-relay (commonly referred to as "the relay") was responsible for accepting bundles from searchers and relaying them to miners. + +After the merge, the term "relay" will mean something entirely different. *These* relays are a component of PBS -- they're responsible for escrowing blocks from builders for validators. With mev-boost, validators choose the most profitable block from a number of relays. Each relay keeps the contents of a block private until the validator commits to proposing it to the network for inclusion. + +Specifically, relays do the following: + +* accept new blocks from builders +* send header of most profitable block to a validator upon request + * *the validator locks in their commitment to propose the full block by signing this header* +* send full block to validator after receiving block header signed by the validator +* perform all of this quickly and reliably, so that validators don’t miss proposal deadlines + +For a deeper explanation of mev-boost and relays, Check out @thegostep’s *[ethresear.ch post](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177)*. + +For more information about how bundles are sent post-merge, see [this forum post](https://collective.flashbots.net/t/how-will-sending-bundles-change-in-pos-ethereum/147). + +### Can I be a block builder? How? + +mev-boost provides the foundation for a competitive market of block builders, each trying to provide the most profitable block to validators. Naturally, some searchers should want to become builders themselves. We expect there to be multiple relays in the future with varying requirements on who can submit blocks to them and how those blocks can be submitted. We are currently working on the rules for how the Flashbots Relay for mev-boost will accept blocks from builders. + +If you are interested in becoming a builder or just want to learn more, check out [this issue on mev-boost](https://github.com/flashbots/mev-boost/issues/145). + +### What trust assumptions exist in proposer-builder separation (PBS)? + +In this initial implementation of PBS (mev-boost), to prevent things like front-running, censorship, and unauthorized data sharing, each party has to trust the parties to which they connect. When PBS is [built natively](https://ethresear.ch/t/two-slot-proposer-builder-separation/10980) into the Ethereum protocol, these trust assumptions will be reduced by eliminating the need for relays. + +* Searchers have to trust the builder(s) to which they send bundles. + + Builders may be the most incentivized to ~~use~~ abuse your transactions to extract additional MEV. As a searcher, you must find a builder with reputation at stake, so you can trust that they won’t take short-term profits in favor of your continued bundle submissions. + +* Builders have to trust the relay to which they send blocks. + + For background on relays, see [this post](https://collective.flashbots.net/t/how-are-relays-defined-in-pos-ethereum/148). + + Of course, block builders have to trust that relays won’t leak transaction data or use it to extract additional MEV (secretly building blocks themselves). But the other major consideration is that the relay has to respond to the validator’s requests quickly, so that the validator does not miss the chance to propose a builder’s block. If the validator misses the slot, the builder of the most profitable block which would have been proposed loses out on their profits as well. + +* Validators have to trust the relay(s) from which they receive blocks. + + A strictly rational validator won’t care if a relay abuses their transaction view and extracts unfair MEV, as this is actually more profitable for the validator. That being said, if a relay abuses its power, it won’t last for long. + + For validators, the performance of the relay is paramount. Validators must trust that the relay(s) they connect to will respond to their requests quickly and reliably. If the relay does not respond in time, a validator may miss their window to include a block in the next slot, and will not earn any rewards for their participation. + +Read more about the trust assumptions of mev-boost-enabled PBS in [Stephane’s research post](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177). + +### Will the mempool change in PoS Ethereum? + +The public mempool works the same in PoS as in PoW — anyone running an execution client (e.g. geth) can read transactions from the mempool. + +It should be noted, however, that the post-merge public mempool may not see as much activity as it does today. With PBS, users and wallets may choose to send all of their transactions to a specific builder (or builders) rather than to the public mempool. From d0a9273dd58c721f6d3e5267b5eeb83b1b846d3e Mon Sep 17 00:00:00 2001 From: Kailin <42973015+kailinr@users.noreply.github.com> Date: Mon, 5 Sep 2022 10:34:02 -0400 Subject: [PATCH 005/255] Add MEV-Boost to docs (#296) * update .env, sidebars.js outline, added initial mev-boost dir * add outline to sidebars.js * Add introduction * Add specs * Add block proposer * Add relay * Add block builder * Add block proposer * risks * getting started * troubleshooting * contributing * Add rest of outline * system requirements * Guides fixed * Update formatting and URLs * Update docs/flashbots-mev-boost/troubleshooting.md Co-authored-by: Chris Hager * Update docs/flashbots-mev-boost/troubleshooting.md Co-authored-by: Chris Hager * Update docs/flashbots-mev-boost/architecture/MEV-boost-specifications.md Co-authored-by: Chris Hager * Update docs/flashbots-mev-boost/architecture/MEV-boost-specifications.md Co-authored-by: Chris Hager * Update docs/flashbots-mev-boost/troubleshooting.md Co-authored-by: Chris Hager * Update docs/flashbots-mev-boost/architecture/block-builders.md Co-authored-by: Chris Hager * Delete LICENSE 3 * Delete README 3.md * Delete .gitignore 3 * Delete babel.config 3.js * Delete .env 3.template * Delete docusaurus.config 3.js * Delete package 3.json * Delete tsconfig 3.json * Delete yarn 3.lock * Update troubleshooting URL * Remove license * Delete license.md * Update risks.md * added usage to mainnet * mainnet relay added * vulnerabilities added * update block proposal img * update block proposer text * Update link * public link * public notion link update * relay api public URL update * relay api public URL update in relays.md * update liveness risks URL * Delete yarn 2.lock * Delete .env 2.template * Delete .env 3.template * Delete .env 4.template * Delete .env 5.template * Delete .gitignore 2 * Delete .gitignore 3 * Delete .gitignore 4 * Delete yarn 5.lock * Delete .gitignore 5 * Delete LICENSE 2 * Delete LICENSE 3 * Delete LICENSE 4 * Delete LICENSE 5 * Delete README 2.md * Delete README 3.md * Delete README 5.md * Delete babel.config 2.js * Delete babel.config 3.js * Delete babel.config 5.js * Delete yarn 4.lock * Delete yarn 3.lock * Delete docusaurus.config 2.js * Delete tsconfig 4.json * Delete docusaurus.config 5.js * Delete package 2.json * Delete package 3.json * Delete package 4.json * Delete package 5.json * Delete tsconfig 3.json * Delete tsconfig 2.json * Delete docusaurus.config 4.js * Delete docusaurus.config 3.js * relay img source link update * update luca's relayer status * Update docs/flashbots-mev-boost/getting-started/usage.md Co-authored-by: Chris Hager Co-authored-by: Chris Hager --- .env.template | 2 - docs/flashbots-mev-boost/FAQ.md | 33 ++++++++++ .../architecture/MEV-boost-block-proposal.md | 11 ++++ .../architecture/MEV-boost-specifications.md | 24 ++++++++ .../architecture/block-builders.md | 19 ++++++ .../architecture/block-proposers.md | 24 ++++++++ .../architecture/relays.md | 60 +++++++++++++++++++ .../flashbots-mev-boost/architecture/risks.md | 21 +++++++ docs/flashbots-mev-boost/community-tools.md | 5 ++ docs/flashbots-mev-boost/contributing.md | 18 ++++++ .../getting-started/installation.md | 46 ++++++++++++++ .../getting-started/system-requirements.md | 27 +++++++++ .../getting-started/usage.md | 39 ++++++++++++ docs/flashbots-mev-boost/glossary.md | 23 +++++++ docs/flashbots-mev-boost/introduction.md | 24 ++++++++ docs/flashbots-mev-boost/resources.md | 30 ++++++++++ docs/flashbots-mev-boost/security.md | 9 +++ docs/flashbots-mev-boost/troubleshooting.md | 3 + docs/sidebars.js | 29 +++++++++ 19 files changed, 445 insertions(+), 2 deletions(-) delete mode 100644 .env.template create mode 100644 docs/flashbots-mev-boost/FAQ.md create mode 100644 docs/flashbots-mev-boost/architecture/MEV-boost-block-proposal.md create mode 100644 docs/flashbots-mev-boost/architecture/MEV-boost-specifications.md create mode 100644 docs/flashbots-mev-boost/architecture/block-builders.md create mode 100644 docs/flashbots-mev-boost/architecture/block-proposers.md create mode 100644 docs/flashbots-mev-boost/architecture/relays.md create mode 100644 docs/flashbots-mev-boost/architecture/risks.md create mode 100644 docs/flashbots-mev-boost/community-tools.md create mode 100644 docs/flashbots-mev-boost/contributing.md create mode 100644 docs/flashbots-mev-boost/getting-started/installation.md create mode 100644 docs/flashbots-mev-boost/getting-started/system-requirements.md create mode 100644 docs/flashbots-mev-boost/getting-started/usage.md create mode 100644 docs/flashbots-mev-boost/glossary.md create mode 100644 docs/flashbots-mev-boost/introduction.md create mode 100644 docs/flashbots-mev-boost/resources.md create mode 100644 docs/flashbots-mev-boost/security.md create mode 100644 docs/flashbots-mev-boost/troubleshooting.md diff --git a/.env.template b/.env.template deleted file mode 100644 index 402068d5..00000000 --- a/.env.template +++ /dev/null @@ -1,2 +0,0 @@ -BASE_URL=/docs/ -TARGET_URL=https://flashbots.github.io \ No newline at end of file diff --git a/docs/flashbots-mev-boost/FAQ.md b/docs/flashbots-mev-boost/FAQ.md new file mode 100644 index 00000000..4a09a1cf --- /dev/null +++ b/docs/flashbots-mev-boost/FAQ.md @@ -0,0 +1,33 @@ +**Can I connect to multiple relays with MEV-Boost?** + +Yes. You can add multiple relays comma-separated to the `-relays` flag, +like this: `-relays https://relay1,https://relay2` + +**How should I think about running `mev-boost` vs regular block construction?** + +The alternative to running `mev-boost` would be to get blocks from your local execution client, which can only get transactions from the public mempool and is not optimized for MEV extraction, meaning your rewards are likely to be less. + +Or to implement your own builder, which is a complicated task and still leaves you with the problem of finding transactions that extract MEV and are not going through the public mempool. + +**Can I check relay status when starting MEV-Boost?** + +Yes. The `-relay-check` flag can be called to check the status of relays, will return an error if none of the configured relays are responsive. + +```json +#Example -relay-check call: + +./mev-boost -goerli -relays -relay-check https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net +``` + + +**What is the difference between a beacon node, validator, and validator client?** + +A "**node**" or “**beacon node**” follows and reads the beacon chain. **validator clients (VC)** are specialized software that stake 32 ETH as collateral within Ethereum's **consensus layer** in order to participate in consensus duties. Validator clients are responsible for executing duties, such as proposing blocks and signing of attestations within Ethereum's proof-of-stake consensus mechanism, and will fully replace proof-of-work miners after [The Merge](https://ethereum.org/en/upgrades/merge/). **validators** most often refers to a validator client instance, but can refer to an individual that physically manages a validator client. This is an optional role in which a user posts ETH as collateral to a validator client in order to verify and attest to blocks, and seek financial returns in exchange for building and securing the protocol. This is similar to proof-of-work networks in which miners provide collateral in the form of hardware/hash-power to seek returns in exchange for building and securing the protocol. [Read more here.](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/validator.md) + +**What prevents block proposers from stealing MEV from submitted builders’ blocks?** + +Slashing penalties. A builder provides the proposer with a "blind" execution layer header to incorporate into a block, and a "value" amount which will be transferred to the proposer once they create a block using this header. Once a proposer signs a block with a header, they are bound to this choice (or risk being slashed due to equivocation). Should a validator wish to steal MEV from a builder, they would need to sign a second block including the exploited MEV, which would result in a slashing penalty. This penalty is significant enough to discourage this behavior, allowing the builder to reveal the blinded transactions without the possibility of the proposer tampering with them, or stealing MEV. [Read more about slashing events here.](https://consensys.net/blog/codefi/rewards-and-penalties-on-ethereum-20-phase-0/) + +**Does MEV-Boost have knowledge about the Beacon Chain?** + +No. MEV-boost has no knowledge about the beacon chain, such as which slots were proposed, etc. \ No newline at end of file diff --git a/docs/flashbots-mev-boost/architecture/MEV-boost-block-proposal.md b/docs/flashbots-mev-boost/architecture/MEV-boost-block-proposal.md new file mode 100644 index 00000000..c1d76c1a --- /dev/null +++ b/docs/flashbots-mev-boost/architecture/MEV-boost-block-proposal.md @@ -0,0 +1,11 @@ +## MEV-Boost Block Proposal + +![MEV-Boost Block Proposal](https://raw.githubusercontent.com/flashbots/mev-boost/main/docs/block-proposal.png) + + +As depicted above and described in the [Builder — Honest Validator](https://github.com/ethereum/builder-specs/blob/main/specs/validator.md#builder----honest-validator) repository, the MEV-Boost block proposal process begins with a [registration step](https://github.com/ethereum/builder-specs/blob/main/specs/validator.md#registration-dissemination) that validators must perform ahead of proposal duties. Registration ensures builders can craft blocks for a given validator’ block proposal. Once registered, validators wait until selected to propose a block. Once selected, a block proposer building a block on top of a beacon `state` in a given `slot` must take the following actions to obtain an [execution payload](https://github.com/ethereum/consensus-specs/blob/a45ee9bf5b1fde766d69e551a6b1a21fe2531734/specs/merge/beacon-chain.md#executionpayload): + +1. Users/searchers send transactions to block builders through public or private peer-to-peer transaction pools. +2. Builders construct execution payloads using received transactions, and parameters the block proposer provided during registration. To process MEV payment, builders set their own address as the payload’s coinbase address and append a transaction to the [block proposers’ feeRecipient address ](https://flashbots.notion.site/WIP-Builder-Payments-to-Block-Proposers-530eb36c60ad417a8702dd26da810b72)at the end of their proposed block. The block is then forwarded to relays. +3. Relays verify the validity of payloads (including amount of ETH paid to the block proposers’ feeRecipient, and send an [`ExecutionPayloadHeader`](https://github.com/ethereum/consensus-specs/blob/a45ee9bf5b1fde766d69e551a6b1a21fe2531734/specs/merge/beacon-chain.md#executionpayloadheader) (execution payloads stripped of transaction content), to MEV-Boost. MEV-boost selects the most valuable payload and forwards it to the block proposer. +4. The block proposer signs the payload and passes it back to MEV-Boost via a [`submitBlindedBlock`](https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock) call, which is forwarded to the relay. Once the relay verifies the proposers’ signature, it responds with the full execution payload body for the validator to use when proposing a `SignedBeaconBlock` to the network. \ No newline at end of file diff --git a/docs/flashbots-mev-boost/architecture/MEV-boost-specifications.md b/docs/flashbots-mev-boost/architecture/MEV-boost-specifications.md new file mode 100644 index 00000000..cd36eb6e --- /dev/null +++ b/docs/flashbots-mev-boost/architecture/MEV-boost-specifications.md @@ -0,0 +1,24 @@ +## MEV-Boost Specifications + +`mev-boost` implements the latest versions of the [Ethereum Builder Specification](https://github.com/ethereum/builder-specs/blob/main/specs/builder.md). + +- The Builder API is a temporary solution for [Proposer-builder separation](https://ethresear.ch/t/proposer-block-builder-separation-friendly-fee-market-designs/9725) + (PBS), and aims to separate the roles of a validator into block proposing and block building. [You can interact with a rendered version of the Builder API here.](https://ethereum.github.io/builder-specs/#/Builder/status) + +## Fundamental Specifications + +[Ethereum Beacon APIs](https://github.com/ethereum/beacon-APIs) + +- Collection of RESTful APIs exposed by a beacon node aiming to facilitate [Phase 0](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/validator.md) of Ethereum consensus. + +[Consensus Specs](https://github.com/ethereum/consensus-specs) + +- Current Ethereum PoS consensus specifications. + +## Tooling and Related Repositories + +- [MEV-Boost](https://github.com/flashbots/mev-boost) +- [MEV-Boost Relay](https://github.com/flashbots/mev-boost-relay) +- [Go Boost Utils](https://github.com/flashbots/go-boost-utils) +- [MEV-Boost Builder](https://github.com/flashbots/boost-geth-builder) +- [Relay Status Page ](https://0xpanoramix.github.io/flashbots-boost-status/) \ No newline at end of file diff --git a/docs/flashbots-mev-boost/architecture/block-builders.md b/docs/flashbots-mev-boost/architecture/block-builders.md new file mode 100644 index 00000000..caf0c5bb --- /dev/null +++ b/docs/flashbots-mev-boost/architecture/block-builders.md @@ -0,0 +1,19 @@ +## Block Builders + +### Builder Fundamentals + +**What is a Builder?** + +Block builders are highly specialized actors who aggregate and construct blocks from transaction orderflow (bundles, private transactions, etc). + +**The Role of Builders** + +Builders run algorithms and simulations (e.g. First Come First Serve, First Price Auctions, etc.) to order bundles and TXs in a block template (technically: *execution payload*) that maximizes profit. They then bid for and buy the validators’ blockspace, with the help of one or more relays, so their execution payloads are proposed to the blockchain. + +### Boost-Geth-Builder + +[MEV-Boost Geth Builder](https://github.com/flashbots/boost-geth-builder) is a testnet-ready open-source builder reference implementation (not meant for production). + +### Builder Proposer Payment + +Details about builder payments to block proposers [can be found here.](https://flashbots.notion.site/WIP-Builder-Payments-to-Block-Proposers-530eb36c60ad417a8702dd26da810b72) \ No newline at end of file diff --git a/docs/flashbots-mev-boost/architecture/block-proposers.md b/docs/flashbots-mev-boost/architecture/block-proposers.md new file mode 100644 index 00000000..5cbd40a3 --- /dev/null +++ b/docs/flashbots-mev-boost/architecture/block-proposers.md @@ -0,0 +1,24 @@ +## Block Proposers + +### Block Proposer Fundamentals + +**What is a Block Proposer?** + +A block proposer is a validator that has been pseudorandomly selected to build a block for a given slot in an epoch (there are 32 slots per epoch). Proposers are selected from the validator set using the standard RANDAO mechanism. + +Validators not pseudo-randomly assigned to propose blocks are assigned to attest, or vote on block proposals. These assignments are known 2 epochs in advance for attesters and 1 for proposers. The block in each slot will have a single validator serving as the proposer and many validators serving as the attesters to all information in that block. Attesters get rewarded for accurately voting on current values of 3 aspects of the beacon chain: the head of the chain (LMD Ghost), the justified checkpoint and the finalized checkpoint (Casper FFG). + +**The Role of Block Proposers** + +Without MEV-Boost, the original role of block proposers consisted of two jobs: + +(1) **building** the best block from all available transactions, and + +(2) **proposing** this block to the PoS network. + +With MEV-Boost, the role of validator is simplified to **proposal** duties only, and consists of the following: + +- Receive a block from their local execution client, i.e. their local block builder, and sign / ‘propose’ it, or +- Receive an execution payload header from one or more relays and blindly sign a block without seeing the underlying execution payload (i.e. the blinded TXs escrowed by the relay). + +The Ethereum [consensus-specs](https://github.com/ethereum/consensus-specs) have well defined expectations of honest validators, the most recent standard is the [Bellatrix -- Honest Validator](https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/validator.md#bellatrix----honest-validator) specification. \ No newline at end of file diff --git a/docs/flashbots-mev-boost/architecture/relays.md b/docs/flashbots-mev-boost/architecture/relays.md new file mode 100644 index 00000000..03de4212 --- /dev/null +++ b/docs/flashbots-mev-boost/architecture/relays.md @@ -0,0 +1,60 @@ +### Relay Fundamentals + +**What is a Relay?** + +Relays are a doubly-trusted data-availability layer and communication interface between builders and validators. Relays are trusted by builders for fair payload routing, and trusted by proposers for block validity, accuracy, and data availability. They are often specialized in Denial of Service (DoS) protection and networking. + +Relays can connect to one or many builders, and we expect that there will be both variants. A relay connecting to many builders will aggregate their bids (fun fact: in a previous iteration, we called them builder aggregators or builder pools). The relay can see all the blocks submitted by the builders to confirm their validity and how much they pay to the validator. The relay then only submits the highest valid bid to the validator to sign. + +Before validators can receive any bids from relays, they need to [set up mev-boost](https://boost.flashbots.net/) and add relays to their mev-boost config. mev-boost is effectively just a relay aggregator or a local relay of relays. It will serve the validator the winning bid from all relays. A validator can connect to a small number of relays that aggregate all the builders, and many will probably do that. Other validators might connect to many relays. + +**The Role of Relays** + +A relay has several responsibilities: + +- They execute [builder-spec](https://ethereum.github.io/builder-specs/#/Builder) and data transparency API functionality. +- Handle validator registrations and block proposals in a scalable manner. +- Provide block escrow and data availability. +- Simulate and verify blocks sent by block-builders, and rate-limit as necessary. Relays simulate whether: + - the correct amount of fees are paid to recent validator feeRecipient. + - the correct block attributes and transactions exist. + - the block gas is within the gasLimit requested by validator. + +## [Relay API Specification](https://flashbots.notion.site/Relay-API-Spec-5fb0819366954962bc02e81cb33840f5) + +The current specification for the [open-source Flashbots relay](https://github.com/flashbots/mev-boost-relay). Diagram below displays the current architecture: + +![Flashbots Relay](https://flashbots.notion.site/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fc4460f24-9643-470a-a956-d886bf92e354%2FScreenshot_2022-06-22_at_17.54.56.png?table=block&id=ed097235-1a1d-497f-b3a4-f2c4673ac26e&spaceId=df6156be-4a40-4dc3-9a41-d3def62df57a&width=2000&userId=&cache=v2) + +### [Proposer API](https://flashbots.notion.site/Relay-API-Spec-5fb0819366954962bc02e81cb33840f5) + +Standard [builder spec](https://ethereum.github.io/builder-specs/#/Builder) APIs + +- [registerValidator](https://ethereum.github.io/builder-specs/#/Builder/registerValidator): `POST /eth/v1/builder/validators` +- [getHeader](https://ethereum.github.io/builder-specs/#/Builder/getHeader): `GET /eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}` - Get an execution payload header. +- [submitBlindedBlock](https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock): `POST /eth/v1/builder/blinded_blocks` - Submit a signed blinded block and get unblinded execution payload. +- [status](https://ethereum.github.io/builder-specs/#/): `GET /eth/v1/builder/status` + +### [Block Builder API](https://flashbots.notion.site/Relay-API-Spec-5fb0819366954962bc02e81cb33840f5) + +Get a list of validator registrations for the current and next epoch, submit a new block to the relay. + +### [Data API](https://flashbots.notion.site/Relay-API-Spec-5fb0819366954962bc02e81cb33840f5) + +Provides data about received blocks from builders and header/payload queries from proposers. + +note from chris: removed the data api, it’s not live and probably won’t be, it was more a discussion in progress, but now deprecated by the other data apis + +## [Relay Monitor](https://hackmd.io/@ralexstokes/SynPJN_pq) + +While relays are trusted actors, the ability to run a relay is permissionless. To mitigate potential abuses of this role, Flashbots [has suggested](https://github.com/flashbots/mev-boost/issues/142) a “relay monitor,” which uses publicly available data to form a view on the behavior and performance of the set of relays it is monitoring. More details can be found in the [relay monitor design documentation](https://hackmd.io/@ralexstokes/SynPJN_pq), [keeping MEV-Boost relays honest](https://notes.ethereum.org/@yoav/BJeOQ8rI5), and [understanding liveness risks](https://writings.flashbots.net/writings/understanding-mev-boost-liveness-risks). + +## [Circuit Breaker](https://hackmd.io/@ralexstokes/BJn9N6Thc) + +The circuit breaker is implemented by client software teams to define “circuit breaking” conditions using globally available inputs (simply, the chain) which determine whether clients should make a decision to terminate an external builder network in favor of local block production. Once the circuit breaker condition is met, the only way to reset the state is to restart the beacon node where the missing slots tally will be 0. + +Each consensus client implements different circuit breaker conditions, as an example: + +| Name | Value | Units | +| --- | --- | --- | +| MAX_ALLOWED_MISSING_SLOTS | 5 | slot(s) | \ No newline at end of file diff --git a/docs/flashbots-mev-boost/architecture/risks.md b/docs/flashbots-mev-boost/architecture/risks.md new file mode 100644 index 00000000..d7ea63b0 --- /dev/null +++ b/docs/flashbots-mev-boost/architecture/risks.md @@ -0,0 +1,21 @@ +### MEV-Boost Risks and Considerations + +**Liveness and Local Fallback** + +To prevent any risk to Ethereum **liveness,** mev-boost is implemented as a sidecar for consensus client software. Using the standard [builder specs](https://github.com/ethereum/builder-specs) ensures client diversity is maintained and validators benefit from operating in the same security model, regardless of which client is selected. Should a fault occur in the mev-boost software, the consensus nodes fall back to local block production. Check-out [understanding liveness risk](https://writings.flashbots.net/writings/understanding-mev-boost-liveness-risks), the [circuit breaker proposal](https://hackmd.io/@ralexstokes/BJn9N6Thc), and the [relay monitor specification](https://hackmd.io/@ralexstokes/SynPJN_pq) for more information. + +**Builder Centralization** + +A builder that dominates the market because of its outsized profitability gains the ability (although not the incentive) for censorship and access to exclusive transaction orderflow. It should be noted that MEV-boost doesn’t *create* the risk of builder centralization - MEV does. Encouraging competition between many builders is the primary mitigation to builder centralization, but it should be supported by techniques like [censorship resistance lists (crLists)](https://github.com/flashbots/mev-boost/issues/215) and others still in early research. + +**Builder/Relay Collusion** + +Anyone can be a relay, and they will compete on reputation and service to both builders and validators. While this is a strict improvement to the trust model compared MEV extraction in PoW Ethereum, relays can still be a risk to both builders and validators. This risk will be addressed in Stage 3 PBS (enshrined), which is getting rid of the trusted relay altogether.**** + +**Malicious Relays** + +Nothing prevents malicious relays from submitting fraudulent bids, which affects MEV-Boost’ profit switching logic. MEV-boost provides the bid with the highest value to the Beacon Node, but has no way of verifying that the value is indeed what is claimed in the bid. A Beacon Node will always be presented with a single bid. However, the [relay monitor specification](https://hackmd.io/@ralexstokes/SynPJN_pq) aims to detect and disqualify a malicious relay pretty quickly. + +**MEV Hiding** + +A risk that occurs when node operators (often managing the stake of third party customers) are incentivized to hide MEV-rewards earned in a given block. diff --git a/docs/flashbots-mev-boost/community-tools.md b/docs/flashbots-mev-boost/community-tools.md new file mode 100644 index 00000000..85fb263e --- /dev/null +++ b/docs/flashbots-mev-boost/community-tools.md @@ -0,0 +1,5 @@ +## Flashbots Relayer Status + +[Monitor Flashbots Relays](https://0xpanoramix.github.io/flashbots-boost-status/) status on various timescales, by 0xpanoramix. + +![Untitled](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F4c213924-8672-4c83-9e9f-605c5399503d%2FUntitled.png?table=block&id=5fce516f-d542-4ff1-8f46-a2f127897e49&spaceId=075d04b3-e5c0-4a97-8020-80f2e2b2206e&width=2000&userId=5d4ec963-edaf-46de-9bbd-bec711cebde4&cache=v2) \ No newline at end of file diff --git a/docs/flashbots-mev-boost/contributing.md b/docs/flashbots-mev-boost/contributing.md new file mode 100644 index 00000000..7089f512 --- /dev/null +++ b/docs/flashbots-mev-boost/contributing.md @@ -0,0 +1,18 @@ +[Flashbots](https://flashbots.net/) is a research and development collective working on mitigating the negative externalities of decentralized economies. We contribute with the larger free software community to illuminate the dark forest. + +You are welcome here <3. + +- If you would like to contribute with code, check the [CONTRIBUTING file](https://github.com/flashbots/mev-boost/blob/main/CONTRIBUTING.md) for further information. +- Please be kind and read our [code of conduct](https://github.com/flashbots/mev-boost/blob/main/CODE_OF_CONDUCT.md). + +### Report a Vulnerability + +If you find a security vulnerability on this, or any other initiative related to Flashbots, please let us know by sending an email to [security@flashbots.net](mailto:security@flashbots.net). + +### Report an Issue + +If you have a questions, feedback, bugs to report, or other topics top of mind, please [open a new Issue](https://github.com/flashbots/mev-boost/issues). + +### Propose New Features + +Please [open an issue](https://github.com/flashbots/mev-boost/issues) with ideas for new features, we’d love to hear from you! Additionally, you can explore [open questions](https://github.com/flashbots/mev-boost/wiki/Research#open-questions) the Flashbots research team is tackling now. \ No newline at end of file diff --git a/docs/flashbots-mev-boost/getting-started/installation.md b/docs/flashbots-mev-boost/getting-started/installation.md new file mode 100644 index 00000000..327f046b --- /dev/null +++ b/docs/flashbots-mev-boost/getting-started/installation.md @@ -0,0 +1,46 @@ +# Installation + +`mev-boost` can run in any machine, as long as it is reachable by the beacon client. The default port is **18550**. The most common setup is to install it in the **same machine as the beacon client.** + +## Dependencies + +- [Go 1.18+](https://go.dev/doc/install) + +## From source + +Install mev-boost with `go install`: + +```bash +go install github.com/flashbots/mev-boost@latest +mev-boost -help +``` + +Or clone the repository and build it: + +```bash +git clone https://github.com/flashbots/mev-boost.git +cd mev-boost +make build + +# Show the help +./mev-boost -help +``` + +## From Docker image + +We maintain a mev-boost Docker image at [https://hub.docker.com/r/flashbots/mev-boost](https://hub.docker.com/r/flashbots/mev-boost) + +- [Install Docker Engine](https://docs.docker.com/engine/install/) +- Pull & run the latest image: + +```bash +docker pull flashbots/mev-boost:latest +docker run flashbots/mev-boost -help +``` +| | MEV-Boost Client Guides | +| --- | --- | +| Teku | [Guide](https://hackmd.io/@StefanBratanov/BkMlo1RO9)| +| Prysm | [Guide](https://hackmd.io/@prysmaticlabs/BJeinxFsq) | +| Lighthouse | [Guide](https://lighthouse-book.sigmaprime.io/builders.html#mev-and-lighthouse) | +| Lodestar | [Guide](https://github.com/ChainSafe/lodestar/blob/unstable/docs/usage/mev-integration.md) | +| Nimbus | [Guide](https://github.com/status-im/nimbus-eth2/pull/3883) | \ No newline at end of file diff --git a/docs/flashbots-mev-boost/getting-started/system-requirements.md b/docs/flashbots-mev-boost/getting-started/system-requirements.md new file mode 100644 index 00000000..b805b816 --- /dev/null +++ b/docs/flashbots-mev-boost/getting-started/system-requirements.md @@ -0,0 +1,27 @@ +## System Requirements + +This guide assumes a pre-installed and hardened Ubuntu installation [as well as Docker](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04). Excellent introductory resources to start with are: [eth-docker](https://eth-docker.net/docs/About/Overview#node-components), [Coincashew](https://www.coincashew.com/coins/overview-eth/guide-or-security-best-practices-for-a-eth2-validator-beaconchain-node), and [Rocketpool's Securing your Node](https://docs.rocketpool.net/guides/node/securing-your-node.html#securing-your-node) + +**Execution + Beacon Requirements** + +- **Software**: Execution client, beacon node client (instructions for clients below), [curl](https://curl.se/download.html) +- **OS**: 64-bit Linux, Mac OS X 10.14+, Windows 10+ 64-bit +- **CPU**: 4+ cores @ 2.8+ GHz +- **Memory**: 16GB+ RAM +- **Storage**: SSD with at least 2TB free space +- **Network:** 8 MBit/sec broadband + +💡 There are variations in client resource usage. Please review [CoinCashew’s Client Usage Guide](https://eth-docker.net/docs/Usage/ResourceUsage) for more details! + + +**Validator Requirements** + +- **Everything above, plus...** +- **Software:** Validator client, browser-based crypto wallet (instructions below) +- **Hardware:** (Recommended) A new machine that has never been connected to the internet that you can use to securely generate your mnemonic phrase and keypair +- **32 ETH** (Mainnet) +- **32 testnet ETH** (Testnets) + +**MEV-Boost Requirements** + +- Can run on any beacon-node system, and requires almost no resources. \ No newline at end of file diff --git a/docs/flashbots-mev-boost/getting-started/usage.md b/docs/flashbots-mev-boost/getting-started/usage.md new file mode 100644 index 00000000..e80f2bc1 --- /dev/null +++ b/docs/flashbots-mev-boost/getting-started/usage.md @@ -0,0 +1,39 @@ +# Usage + +To connect to various networks, use the appropriate network flag for the specific network and relay URL, e.g. `-kiln`, `-ropsten`, `-sepolia`, `-goerli` or `-mainnet`. You can add multiple relays comma-separated to the `-relays` flag, like this: `-relays https://relay1,https://relay2` + +### **Mainnet Relay** + +Run mev-boost pointed at our [Mainnet Relay:](https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net/) + +`./mev-boost -mainnet -relay-check -relays https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net` + +### **Goerli testnet** + +Run mev-boost pointed at our [Goerli Relay](https://builder-relay-goerli.flashbots.net/): + + `./mev-boost -goerli -relay-check -relays https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net` + +### **Ropsten testnet** + +Run mev-boost pointed at our [Ropsten Relay](https://builder-relay-ropsten.flashbots.net/): + + `./mev-boost -ropsten -relay-check -relays https://0xb124d80a00b80815397b4e7f1f05377ccc83aeeceb6be87963ba3649f1e6efa32ca870a88845917ec3f26a8e2aa25c77@builder-relay-ropsten.flashbots.net` + +### **Kiln testnet** + +Run mev-boost pointed at our [Kiln Relay](https://builder-relay-kiln.flashbots.net/): + +`./mev-boost -kiln -relay-check -relays https://0xb5246e299aeb782fbc7c91b41b3284245b1ed5206134b0028b81dfb974e5900616c67847c2354479934fc4bb75519ee1@builder-relay-kiln.flashbots.net` + +### **Sepolia testnet** + +Run mev-boost pointed at our [Sepolia Relay](https://builder-relay-sepolia.flashbots.net/): + + `./mev-boost -sepolia -relay-check -relays https://0x845bd072b7cd566f02faeb0a4033ce9399e42839ced64e8b2adcfc859ed1e8e1a5a293336a49feac6d9a5edb779be53a@builder-relay-sepolia.flashbots.net` + +## CLI Commands - [Advanced] + +### **`test-cli`** + +`test-cli` is a utility to execute all proposer requests against mev-boost + relay. See also the [test-cli readme](https://github.com/flashbots/mev-boost/blob/main/cmd/test-cli/README.md). \ No newline at end of file diff --git a/docs/flashbots-mev-boost/glossary.md b/docs/flashbots-mev-boost/glossary.md new file mode 100644 index 00000000..8451f3c9 --- /dev/null +++ b/docs/flashbots-mev-boost/glossary.md @@ -0,0 +1,23 @@ +- **execution payload**: a [message](https://github.com/ethereum/consensus-specs/blob/a45ee9bf5b1fde766d69e551a6b1a21fe2531734/specs/merge/beacon-chain.md#executionpayload) containing the complete content of an unsigned execution payload (an object containing block properties in addition to transactions) that is provided by the execution layer (previous PoW nodes). +- **MEV-boost “middleware”**: a piece of software that sits between the consensus client and the execution client to outsource block construction to a market of builders. +- **block proposer (proposer)**: a validator selected to sign and submit a beacon block to the network. +- **user**: a normal Ethereum user who sends transactions for block inclusion. +- **searcher**: advanced Ethereum user specialized in detecting and extracting MEV by submitting advanced transactions in batches called bundles. +- **builder**: party specialized in MEV extraction and the construction of execution payloads. Builders are trusted by searchers and users for fair transaction inclusion. +- **relay**: party that validates and routes execution payloads from builders to proposers. Relays are trusted by builders for fair routing and block inclusion. Relays are trusted by block proposers for block validity, accuracy, and data availability. Relay actors are often specialized in Denial of Service (DoS) protection and networking. +- **stakers:** actors that submit any amount of Ethereum to be staked. +- **fork choice rule:** A function evaluated by the client that takes, as input, the set of blocks and other messages that have been produced, and outputs to the client what the 'canonical chain' is. +- **beacon node (BN):** maintains the state of the beacon chain by communicating with other beacon nodes in the Ethereum network. Conceptually, a BN does not maintain keypairs that directly participate with the beacon chain. +- **attestation:** votes (embedded in messages) describing which blocks “should” be the head of the chain. We can think of each such attestation as a “vote” to move from block A to B. Each attestation has a weight, which is the stake of the validator writing the attestation. +- **validator client (VC):** Validator clients are specialized software that let people stake 32 ETH as collateral within Ethereum's **consensus layer**. Validators are responsible for proposing blocks within Ethereum's proof-of-stake consensus mechanism, and will fully replace proof-of-work miners after [The Merge](https://ethereum.org/en/upgrades/merge/). +- **validator:** Most often refers to a validator client instance, but can also refer to an individual that is physically managing a validator client. Validators**** participate in the consensus of Ethereum through validator duties. These duties include the production of beacon blocks and signing of attestations, as executed by the validator client. +- **validator pubkey**: The validator's BLS public key, uniquely identifying them. *48-bytes, hex encoded with 0x prefix, case insensitive.* +- **committee:** a group of validators. For security, each slot has committees of at least 128 validators. An attacker has less than a one in a trillion probability of controlling 2⁄3 of a committee. +- l**iveness:** state of ethereum which is valid ****if the set of finalized blocks can grow. +- **plausible liveness:** if, regardless of any previous events (attacks, latency, etc.), it is possible for new blocks to be finalized (the alternative is to become +“deadlocked”). This is to prevent situations where honest validators cannot continue +unless someone forfeits their own stake. +- **probabilistic liveness:** if, regardless of any previous events, it is probable for new +blocks to be finalized (after probabilistic assumptions about the network latency, capabilities of attackers, etc. are made). +- **Proposer/block-builder separation (PBS)**: Proposer/block-builder separation (**PBS** +) was proposed by Ethereum researchers as a response to the risk that MEV poses to decentralization of consensus networks. PBS is a change to the base Ethereum protocol that aims to separate block building from block proposing. Instead of the block proposer (currently the miner, after PoS the validator) also trying to produce a maximally profitable block by itself, it can outsource this to a block building *marketplace.* With this model, block builders would produce bundles consisting of a complete block and a fee for the proposer. \ No newline at end of file diff --git a/docs/flashbots-mev-boost/introduction.md b/docs/flashbots-mev-boost/introduction.md new file mode 100644 index 00000000..31499153 --- /dev/null +++ b/docs/flashbots-mev-boost/introduction.md @@ -0,0 +1,24 @@ +# introduction + +## What is MEV-Boost? + +`mev-boost` is open source middleware run by validators to access a competitive block-building market. MEV-Boost was built by Flashbots as an implementation of [proposer-builder separation (PBS)](https://ethresear.ch/t/proposer-block-builder-separation-friendly-fee-market-designs/9725) for proof-of-stake (PoS) Ethereum. + +With MEV-Boost, validators can access blocks from a marketplace of builders. Builders produce blocks containing transaction orderflow and a fee for the block proposing validator. Separating the role of proposers from block builders promotes greater competition, decentralization, and censorship-resistance for Ethereum. + +## Why MEV-Boost? + +MEV is a centralizing force on Ethereum. Unattended, the competition for MEV opportunities leads to consensus instability and permissioned communication infrastructure between searchers, block producers, and validators. Access to MEV is even more important in PoS Ethereum, as the planned [reduction in block subsidies](https://hackmd.io/@flashbots/mev-in-eth2) will make MEV an even [larger share of total staking revenue](https://github.com/flashbots/eth2-research/blob/main/notebooks/mev-in-eth2/eth2-mev-calc.ipynb). + +Validators running MEV-Boost maximize their staking reward by selling their blockspace to an open market. It is estimated that validators running MEV-Boost can increase [staking rewards by over 60%](https://hackmd.io/@flashbots/mev-in-eth2). + +## How does MEV-Boost work? + +![https://raw.githubusercontent.com/flashbots/mev-boost/main/docs/mev-boost-integration-overview.png](https://raw.githubusercontent.com/flashbots/mev-boost/main/docs/mev-boost-integration-overview.png) + +PoS node operators must run three pieces of software: a validator client, consensus client, and an execution client. MEV-boost is a sidecar for the consensus client, a separate piece of open source software, which queries and outsources block-building to a network of builders. + +Block builders prepare full blocks, optimizing for MEV extraction and fair distribution of rewards, and send blocks to relays. A single MEV-boost instance can be configured to connect to **multiple** relays. + +Relays aggregate blocks from **multiple** builders and identify the most profitable block to submit to the block proposer. The proposing validators’ consensus client then propagates the most profitable block received from MEV-boost to the Ethereum network for attestation and block inclusion. + diff --git a/docs/flashbots-mev-boost/resources.md b/docs/flashbots-mev-boost/resources.md new file mode 100644 index 00000000..3677beef --- /dev/null +++ b/docs/flashbots-mev-boost/resources.md @@ -0,0 +1,30 @@ +**Proof-of-Stake Ethereum** + +- [The Hitchhiker's Guide to Ethereum](https://members.delphidigital.io/reports/the-hitchhikers-guide-to-ethereum/) +- [Combining Ghost and Casper - Vitalik Buterin et al.](https://arxiv.org/pdf/2003.03052.pdf) +- [Endgame - Vitalik Buterin](https://vitalik.ca/general/2021/12/06/endgame.html) +- [Fork Choice](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/fork-choice.md) +- [A compiled list of resources from Flashbots Research](https://github.com/flashbots/mev-boost/wiki/Research#open-questions) + +**MEV** + +- [MEV in eth2 - an early exploration](https://writings.flashbots.net/research/mev-eth2/) +- [MEV Driven Centralization in Ethereum: Part 1](https://simbro.medium.com/mev-driven-centralization-in-ethereum-ec829a214f18) + +**MEV-Boost** + +- [Beginner's Guide to mev-boost](https://writings.flashbots.net/writings/beginners-guide-mevboost/) +- [MEV-Boost: Merge ready Flashbots Architecture](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177) +- [Why Run MEV-Boost?](https://writings.flashbots.net/writings/why-run-mevboost/) +- [Removing Trusted Relays in MEV-Boost Using Threshold Encryption](https://ethresear.ch/t/removing-trusted-relays-in-mev-boost-using-threshold-encryption/13449) +- [Proposer/block builder separation-friendly fee market designs](https://ethresear.ch/t/proposer-block-builder-separation-friendly-fee-market-designs/9725) +- [Open sourcing the Flashbots Relay](https://writings.flashbots.net/writings/Flashbots-Relay-open-sourcing) +- [Understanding liveness risks from mev-boost](https://writings.flashbots.net/writings/understanding-mev-boost-liveness-risks) + +**Validator Guides** + +- [Validator Checklist - launchpad.ethereum.org](https://launchpad.ethereum.org/en/merge-readiness) +- [CoinCashew’s Client Usage Guide](https://eth-docker.net/docs/Usage/ResourceUsage) +- [eth-docker: Docker automation for Ethereum consensus and execution clients.](https://github.com/eth-educators/eth-docker) +- [Validator Slashing Prevention Tips - Prysmatic Labs](https://medium.com/prysmatic-labs/eth2-slashing-prevention-tips-f6faa5025f50) +- [Understanding Eth2 Slashing Preventative Measures](https://www.bloxstaking.com/blog/ethereum-2-0/understanding-eth2-slashing-preventative-measures/) \ No newline at end of file diff --git a/docs/flashbots-mev-boost/security.md b/docs/flashbots-mev-boost/security.md new file mode 100644 index 00000000..335f2f94 --- /dev/null +++ b/docs/flashbots-mev-boost/security.md @@ -0,0 +1,9 @@ +# Vulnerabilities +If you find a security vulnerability on this project or any other initiative related to Flashbots, please let us know sending an email to security@flashbots.net. +# Security Audits + +- [20220620](https://github.com/flashbots/mev-boost/blob/main/docs/audit-20220620.md), by [lotusbumi](https://github.com/lotusbumi). + +### Bug Bounties + +- Coming soon! \ No newline at end of file diff --git a/docs/flashbots-mev-boost/troubleshooting.md b/docs/flashbots-mev-boost/troubleshooting.md new file mode 100644 index 00000000..a959fc6b --- /dev/null +++ b/docs/flashbots-mev-boost/troubleshooting.md @@ -0,0 +1,3 @@ +## Troubleshooting + +Please refer to the [Troubleshooting Wiki](https://github.com/flashbots/mev-boost/wiki/Troubleshooting) for the most updated guidance. diff --git a/docs/sidebars.js b/docs/sidebars.js index 59102431..b92d50f7 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -124,6 +124,35 @@ module.exports = { } ], }, + { + "flashbots MEV-boost": [ + 'flashbots-mev-boost/introduction', + { + 'architecture': [ + 'flashbots-mev-boost/architecture/MEV-boost-specifications', + 'flashbots-mev-boost/architecture/MEV-boost-block-proposal', + 'flashbots-mev-boost/architecture/relays', + 'flashbots-mev-boost/architecture/block-builders', + 'flashbots-mev-boost/architecture/block-proposers', + 'flashbots-mev-boost/architecture/risks' + ] + }, + { + 'getting started':[ + 'flashbots-mev-boost/getting-started/system-requirements', + 'flashbots-mev-boost/getting-started/installation', + 'flashbots-mev-boost/getting-started/usage', + ] + }, + 'flashbots-mev-boost/troubleshooting', + 'flashbots-mev-boost/contributing', + 'flashbots-mev-boost/security', + 'flashbots-mev-boost/FAQ', + 'flashbots-mev-boost/glossary', + 'flashbots-mev-boost/resources', + 'flashbots-mev-boost/community-tools', + ], + }, { "community": [ 'community-tools', 'whitehat', From 82879b982d6212f40b3161b26ed7bc9660fc68e2 Mon Sep 17 00:00:00 2001 From: Chris Hager Date: Mon, 5 Sep 2022 16:44:07 +0200 Subject: [PATCH 006/255] minor fixes for PR 296 (#297) --- .env.template | 2 ++ docs/flashbots-mev-boost/architecture/relays.md | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 .env.template diff --git a/.env.template b/.env.template new file mode 100644 index 00000000..402068d5 --- /dev/null +++ b/.env.template @@ -0,0 +1,2 @@ +BASE_URL=/docs/ +TARGET_URL=https://flashbots.github.io \ No newline at end of file diff --git a/docs/flashbots-mev-boost/architecture/relays.md b/docs/flashbots-mev-boost/architecture/relays.md index 03de4212..40340210 100644 --- a/docs/flashbots-mev-boost/architecture/relays.md +++ b/docs/flashbots-mev-boost/architecture/relays.md @@ -41,9 +41,7 @@ Get a list of validator registrations for the current and next epoch, submit a n ### [Data API](https://flashbots.notion.site/Relay-API-Spec-5fb0819366954962bc02e81cb33840f5) -Provides data about received blocks from builders and header/payload queries from proposers. - -note from chris: removed the data api, it’s not live and probably won’t be, it was more a discussion in progress, but now deprecated by the other data apis +Provides data about received blocks from builders, payloads delivered to proposers as well as insights into validator registrations. ## [Relay Monitor](https://hackmd.io/@ralexstokes/SynPJN_pq) @@ -51,7 +49,7 @@ While relays are trusted actors, the ability to run a relay is permissionless. T ## [Circuit Breaker](https://hackmd.io/@ralexstokes/BJn9N6Thc) -The circuit breaker is implemented by client software teams to define “circuit breaking” conditions using globally available inputs (simply, the chain) which determine whether clients should make a decision to terminate an external builder network in favor of local block production. Once the circuit breaker condition is met, the only way to reset the state is to restart the beacon node where the missing slots tally will be 0. +The circuit breaker is implemented by client software teams to define “circuit breaking” conditions using globally available inputs (simply, the chain) which determine whether clients should make a decision to terminate an external builder network in favor of local block production. Once the circuit breaker condition is met, the only way to reset the state is to restart the beacon node where the missing slots tally will be 0. Each consensus client implements different circuit breaker conditions, as an example: From 2607543ab8532c456b9832f630eb444da2b48fd6 Mon Sep 17 00:00:00 2001 From: Chris Hager Date: Mon, 5 Sep 2022 16:46:29 +0200 Subject: [PATCH 007/255] minor fixes for PR 296 (#298) --- docs/flashbots-mev-boost/FAQ.md | 14 ++++++------- .../getting-started/installation.md | 4 +++- .../getting-started/usage.md | 20 ++++++++++++++----- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/docs/flashbots-mev-boost/FAQ.md b/docs/flashbots-mev-boost/FAQ.md index 4a09a1cf..100ddafd 100644 --- a/docs/flashbots-mev-boost/FAQ.md +++ b/docs/flashbots-mev-boost/FAQ.md @@ -1,6 +1,6 @@ -**Can I connect to multiple relays with MEV-Boost?** +**Can I connect to multiple relays with MEV-Boost?** -Yes. You can add multiple relays comma-separated to the `-relays` flag, +Yes. You can add multiple relays comma-separated to the `-relays` flag, like this: `-relays https://relay1,https://relay2` **How should I think about running `mev-boost` vs regular block construction?** @@ -11,16 +11,16 @@ Or to implement your own builder, which is a complicated task and still leaves y **Can I check relay status when starting MEV-Boost?** -Yes. The `-relay-check` flag can be called to check the status of relays, will return an error if none of the configured relays are responsive. +Yes. The `-relay-check` flag can be called to check the status of relays, will return an error if none of the configured relays are responsive. -```json -#Example -relay-check call: +```bash +# Example -relay-check call: ./mev-boost -goerli -relays -relay-check https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net ``` -**What is the difference between a beacon node, validator, and validator client?** +**What is the difference between a beacon node, validator, and validator client?** A "**node**" or “**beacon node**” follows and reads the beacon chain. **validator clients (VC)** are specialized software that stake 32 ETH as collateral within Ethereum's **consensus layer** in order to participate in consensus duties. Validator clients are responsible for executing duties, such as proposing blocks and signing of attestations within Ethereum's proof-of-stake consensus mechanism, and will fully replace proof-of-work miners after [The Merge](https://ethereum.org/en/upgrades/merge/). **validators** most often refers to a validator client instance, but can refer to an individual that physically manages a validator client. This is an optional role in which a user posts ETH as collateral to a validator client in order to verify and attest to blocks, and seek financial returns in exchange for building and securing the protocol. This is similar to proof-of-work networks in which miners provide collateral in the form of hardware/hash-power to seek returns in exchange for building and securing the protocol. [Read more here.](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/validator.md) @@ -28,6 +28,6 @@ A "**node**" or “**beacon node**” follows and reads the beacon chain. **vali Slashing penalties. A builder provides the proposer with a "blind" execution layer header to incorporate into a block, and a "value" amount which will be transferred to the proposer once they create a block using this header. Once a proposer signs a block with a header, they are bound to this choice (or risk being slashed due to equivocation). Should a validator wish to steal MEV from a builder, they would need to sign a second block including the exploited MEV, which would result in a slashing penalty. This penalty is significant enough to discourage this behavior, allowing the builder to reveal the blinded transactions without the possibility of the proposer tampering with them, or stealing MEV. [Read more about slashing events here.](https://consensys.net/blog/codefi/rewards-and-penalties-on-ethereum-20-phase-0/) -**Does MEV-Boost have knowledge about the Beacon Chain?** +**Does MEV-Boost have knowledge about the Beacon Chain?** No. MEV-boost has no knowledge about the beacon chain, such as which slots were proposed, etc. \ No newline at end of file diff --git a/docs/flashbots-mev-boost/getting-started/installation.md b/docs/flashbots-mev-boost/getting-started/installation.md index 327f046b..9987e27d 100644 --- a/docs/flashbots-mev-boost/getting-started/installation.md +++ b/docs/flashbots-mev-boost/getting-started/installation.md @@ -1,6 +1,6 @@ # Installation -`mev-boost` can run in any machine, as long as it is reachable by the beacon client. The default port is **18550**. The most common setup is to install it in the **same machine as the beacon client.** +`mev-boost` can run in any machine, as long as it is reachable by the beacon client. The default port is **18550**. The most common setup is to install it in the **same machine as the beacon client.** ## Dependencies @@ -33,6 +33,8 @@ We maintain a mev-boost Docker image at [https://hub.docker.com/r/flashbots/mev - [Install Docker Engine](https://docs.docker.com/engine/install/) - Pull & run the latest image: +## Consensus client configuration guides + ```bash docker pull flashbots/mev-boost:latest docker run flashbots/mev-boost -help diff --git a/docs/flashbots-mev-boost/getting-started/usage.md b/docs/flashbots-mev-boost/getting-started/usage.md index e80f2bc1..bc074a2a 100644 --- a/docs/flashbots-mev-boost/getting-started/usage.md +++ b/docs/flashbots-mev-boost/getting-started/usage.md @@ -6,31 +6,41 @@ To connect to various networks, use the appropriate network flag for the specifi Run mev-boost pointed at our [Mainnet Relay:](https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net/) -`./mev-boost -mainnet -relay-check -relays https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net` +```bash +./mev-boost -mainnet -relay-check -relays https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net +``` ### **Goerli testnet** Run mev-boost pointed at our [Goerli Relay](https://builder-relay-goerli.flashbots.net/): - `./mev-boost -goerli -relay-check -relays https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net` +```bash +./mev-boost -goerli -relay-check -relays https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net +``` ### **Ropsten testnet** Run mev-boost pointed at our [Ropsten Relay](https://builder-relay-ropsten.flashbots.net/): - `./mev-boost -ropsten -relay-check -relays https://0xb124d80a00b80815397b4e7f1f05377ccc83aeeceb6be87963ba3649f1e6efa32ca870a88845917ec3f26a8e2aa25c77@builder-relay-ropsten.flashbots.net` +```bash +./mev-boost -ropsten -relay-check -relays https://0xb124d80a00b80815397b4e7f1f05377ccc83aeeceb6be87963ba3649f1e6efa32ca870a88845917ec3f26a8e2aa25c77@builder-relay-ropsten.flashbots.net +``` ### **Kiln testnet** Run mev-boost pointed at our [Kiln Relay](https://builder-relay-kiln.flashbots.net/): -`./mev-boost -kiln -relay-check -relays https://0xb5246e299aeb782fbc7c91b41b3284245b1ed5206134b0028b81dfb974e5900616c67847c2354479934fc4bb75519ee1@builder-relay-kiln.flashbots.net` +```bash +./mev-boost -kiln -relay-check -relays https://0xb5246e299aeb782fbc7c91b41b3284245b1ed5206134b0028b81dfb974e5900616c67847c2354479934fc4bb75519ee1@builder-relay-kiln.flashbots.net +``` ### **Sepolia testnet** Run mev-boost pointed at our [Sepolia Relay](https://builder-relay-sepolia.flashbots.net/): - `./mev-boost -sepolia -relay-check -relays https://0x845bd072b7cd566f02faeb0a4033ce9399e42839ced64e8b2adcfc859ed1e8e1a5a293336a49feac6d9a5edb779be53a@builder-relay-sepolia.flashbots.net` +```bash +./mev-boost -sepolia -relay-check -relays https://0x845bd072b7cd566f02faeb0a4033ce9399e42839ced64e8b2adcfc859ed1e8e1a5a293336a49feac6d9a5edb779be53a@builder-relay-sepolia.flashbots.net +``` ## CLI Commands - [Advanced] From 4448c94ef91a4a290471f81e0529a4d26ba1ca82 Mon Sep 17 00:00:00 2001 From: Chris Hager Date: Mon, 5 Sep 2022 16:56:31 +0200 Subject: [PATCH 008/255] mev-boost usage: check if everything works (#299) --- docs/flashbots-mev-boost/getting-started/usage.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/flashbots-mev-boost/getting-started/usage.md b/docs/flashbots-mev-boost/getting-started/usage.md index bc074a2a..5052b227 100644 --- a/docs/flashbots-mev-boost/getting-started/usage.md +++ b/docs/flashbots-mev-boost/getting-started/usage.md @@ -2,6 +2,8 @@ To connect to various networks, use the appropriate network flag for the specific network and relay URL, e.g. `-kiln`, `-ropsten`, `-sepolia`, `-goerli` or `-mainnet`. You can add multiple relays comma-separated to the `-relays` flag, like this: `-relays https://relay1,https://relay2` +You can find a comprehensive list of relays at https://boost.flashbots.net + ### **Mainnet Relay** Run mev-boost pointed at our [Mainnet Relay:](https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net/) @@ -42,8 +44,8 @@ Run mev-boost pointed at our [Sepolia Relay](https://builder-relay-sepolia.flas ./mev-boost -sepolia -relay-check -relays https://0x845bd072b7cd566f02faeb0a4033ce9399e42839ced64e8b2adcfc859ed1e8e1a5a293336a49feac6d9a5edb779be53a@builder-relay-sepolia.flashbots.net ``` -## CLI Commands - [Advanced] +## Checking if everything works -### **`test-cli`** +You can check if you setup works by looking up the validator registration of your proposer using the Relay Data API: https://flashbots.notion.site/Relay-API-Spec-5fb0819366954962bc02e81cb33840f5#308368dd0b9d4eccaa1ffad1c9e68906 -`test-cli` is a utility to execute all proposer requests against mev-boost + relay. See also the [test-cli readme](https://github.com/flashbots/mev-boost/blob/main/cmd/test-cli/README.md). \ No newline at end of file +Example API URL: https://boost-relay.flashbots.net/relay/v1/data/validator_registration?pubkey=0xb606e206c2bf3b78f53ebff8be8e8d4af2f0da68646b5642c4d511b15ab5ddb122ae57b48eab614f8ca5bafbe75a5999 \ No newline at end of file From 6312fd2c1e9f44a052bc351ed413253e8c196c2c Mon Sep 17 00:00:00 2001 From: Kailin <42973015+kailinr@users.noreply.github.com> Date: Tue, 6 Sep 2022 04:14:42 -0400 Subject: [PATCH 009/255] Update risks.md (#300) --- docs/flashbots-mev-boost/architecture/risks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/flashbots-mev-boost/architecture/risks.md b/docs/flashbots-mev-boost/architecture/risks.md index d7ea63b0..5949bdbb 100644 --- a/docs/flashbots-mev-boost/architecture/risks.md +++ b/docs/flashbots-mev-boost/architecture/risks.md @@ -10,7 +10,7 @@ A builder that dominates the market because of its outsized profitability gains **Builder/Relay Collusion** -Anyone can be a relay, and they will compete on reputation and service to both builders and validators. While this is a strict improvement to the trust model compared MEV extraction in PoW Ethereum, relays can still be a risk to both builders and validators. This risk will be addressed in Stage 3 PBS (enshrined), which is getting rid of the trusted relay altogether.**** +Anyone can be a relay, and they will compete on reputation and service to both builders and validators. While this is a strict improvement to the trust model compared MEV extraction in PoW Ethereum, relays can still be a risk to both builders and validators. This risk will be addressed in Stage 3 PBS (enshrined), which is getting rid of the trusted relay altogether. **Malicious Relays** From ee40c720ab054aa1b228056a9d4162448ef3e4a6 Mon Sep 17 00:00:00 2001 From: brock <2791467+zeroXbrock@users.noreply.github.com> Date: Wed, 7 Sep 2022 13:29:21 -0700 Subject: [PATCH 010/255] alchemy sdk page (#294) * Updated the docs Per our convo with Flashbots, adding alchemy-sdk as a library here :) One of the features we have is that we have reputation management on the backened instead of having searches manage a secondary address to manage their reputation * Adding SDK resource Per our convo with Flashbots, adding alchemy-sdk (which is a superset of the ethers.js Provider library) as a file here to help get developers up and running on your awesome features! Pls lmk if you have any questions, thanks :) * Update golang.md * add page to sidebar Co-authored-by: shelleyolivia <108895606+shelleyolivia@users.noreply.github.com> --- .../searchers/libraries/alchemyprovider.md | 20 +++++++++++++++++++ docs/sidebars.js | 1 + 2 files changed, 21 insertions(+) create mode 100644 docs/flashbots-auction/searchers/libraries/alchemyprovider.md diff --git a/docs/flashbots-auction/searchers/libraries/alchemyprovider.md b/docs/flashbots-auction/searchers/libraries/alchemyprovider.md new file mode 100644 index 00000000..3512937d --- /dev/null +++ b/docs/flashbots-auction/searchers/libraries/alchemyprovider.md @@ -0,0 +1,20 @@ +--- +title: alchemy provider +--- +The Alchemy SDK makes getting started, shipping builds, and accessing support faster and more streamlined. For instance, it provides high-level access to the `eth_sendPrivateTransaction` and `eth_cancelPrivateTransaction` rpc endpoints on mev-relay. + +Benefits of the Alchemy SDK include providing: + +**1. Automatic management of your Flashbots reputation** - the SDK takes on the work of actively, and manually, managing your reputation. Learn more about reputation [here](https://docs.flashbots.net/flashbots-auction/searchers/advanced/reputation#querying-reputation) + +**2. A superset of the ethers.js Provider library plus the suite of Alchemy APIs** - the Alchemy Provider exposes the relay endpoints and makes the full JSON-RPC specification endpoints available. The Flashbots relay API can be used natively with the core EVM APIs as well as the suite of Alchemy APIs + +**3. Webhook based notifications on [mined and dropped private transactions](https://docs.alchemy.com/docs/alchemy-notify#features)** + +To get started: + +* [https://www.alchemy.com/sdk](https://www.alchemy.com/sdk) + +* [https://docs.alchemy.com/reference/eth-sendprivatetransaction](https://docs.alchemy.com/reference/eth-sendprivatetransaction) + +* [https://github.com/alchemyplatform/alchemy-sdk-js](https://github.com/alchemyplatform/alchemy-sdk-js) diff --git a/docs/sidebars.js b/docs/sidebars.js index b92d50f7..1424d963 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -36,6 +36,7 @@ module.exports = { 'flashbots-auction/searchers/libraries/golang', 'flashbots-auction/searchers/libraries/ethers-js-provider', 'flashbots-auction/searchers/libraries/web3py-provider', + 'flashbots-auction/searchers/libraries/alchemyprovider', ] }, 'flashbots-auction/other-resources' From 953ce6b856c0f3cd6587364805a74002391ba70d Mon Sep 17 00:00:00 2001 From: Kailin <42973015+kailinr@users.noreply.github.com> Date: Thu, 15 Sep 2022 14:51:59 -0400 Subject: [PATCH 011/255] update mev-boost builder docs (#304) * restructure sidebars.js docs directory ordering * Add Builder endpoints to documentation * expand builder proposer payment spec in docs * formatting cleanup * update sidebar formatting --- .../MEV-boost-block-proposal.md | 0 .../MEV-boost-specifications.md | 0 .../risks.md | 0 .../architecture/block-builders.md | 19 ----- docs/flashbots-mev-boost/block builders.md | 78 +++++++++++++++++++ .../block-proposers.md => block proposers.md} | 0 .../{architecture => }/relays.md | 0 docs/flashbots-mev-boost/security.md | 2 +- docs/sidebars.js | 15 ++-- 9 files changed, 87 insertions(+), 27 deletions(-) rename docs/flashbots-mev-boost/{architecture => architecture-overview}/MEV-boost-block-proposal.md (100%) rename docs/flashbots-mev-boost/{architecture => architecture-overview}/MEV-boost-specifications.md (100%) rename docs/flashbots-mev-boost/{architecture => architecture-overview}/risks.md (100%) delete mode 100644 docs/flashbots-mev-boost/architecture/block-builders.md create mode 100644 docs/flashbots-mev-boost/block builders.md rename docs/flashbots-mev-boost/{architecture/block-proposers.md => block proposers.md} (100%) rename docs/flashbots-mev-boost/{architecture => }/relays.md (100%) diff --git a/docs/flashbots-mev-boost/architecture/MEV-boost-block-proposal.md b/docs/flashbots-mev-boost/architecture-overview/MEV-boost-block-proposal.md similarity index 100% rename from docs/flashbots-mev-boost/architecture/MEV-boost-block-proposal.md rename to docs/flashbots-mev-boost/architecture-overview/MEV-boost-block-proposal.md diff --git a/docs/flashbots-mev-boost/architecture/MEV-boost-specifications.md b/docs/flashbots-mev-boost/architecture-overview/MEV-boost-specifications.md similarity index 100% rename from docs/flashbots-mev-boost/architecture/MEV-boost-specifications.md rename to docs/flashbots-mev-boost/architecture-overview/MEV-boost-specifications.md diff --git a/docs/flashbots-mev-boost/architecture/risks.md b/docs/flashbots-mev-boost/architecture-overview/risks.md similarity index 100% rename from docs/flashbots-mev-boost/architecture/risks.md rename to docs/flashbots-mev-boost/architecture-overview/risks.md diff --git a/docs/flashbots-mev-boost/architecture/block-builders.md b/docs/flashbots-mev-boost/architecture/block-builders.md deleted file mode 100644 index caf0c5bb..00000000 --- a/docs/flashbots-mev-boost/architecture/block-builders.md +++ /dev/null @@ -1,19 +0,0 @@ -## Block Builders - -### Builder Fundamentals - -**What is a Builder?** - -Block builders are highly specialized actors who aggregate and construct blocks from transaction orderflow (bundles, private transactions, etc). - -**The Role of Builders** - -Builders run algorithms and simulations (e.g. First Come First Serve, First Price Auctions, etc.) to order bundles and TXs in a block template (technically: *execution payload*) that maximizes profit. They then bid for and buy the validators’ blockspace, with the help of one or more relays, so their execution payloads are proposed to the blockchain. - -### Boost-Geth-Builder - -[MEV-Boost Geth Builder](https://github.com/flashbots/boost-geth-builder) is a testnet-ready open-source builder reference implementation (not meant for production). - -### Builder Proposer Payment - -Details about builder payments to block proposers [can be found here.](https://flashbots.notion.site/WIP-Builder-Payments-to-Block-Proposers-530eb36c60ad417a8702dd26da810b72) \ No newline at end of file diff --git a/docs/flashbots-mev-boost/block builders.md b/docs/flashbots-mev-boost/block builders.md new file mode 100644 index 00000000..670e08e8 --- /dev/null +++ b/docs/flashbots-mev-boost/block builders.md @@ -0,0 +1,78 @@ +## Block Builders + +### Builder Fundamentals + +**What is a Builder?** + +Block builders are highly specialized actors who aggregate and construct blocks from transaction orderflow (bundles, private transactions, etc). + +**The Role of Builders** + +Builders run algorithms and simulations (e.g. First Come First Serve, First Price Auctions, etc.) to order bundles and TXs in a block template (technically: *execution payload*) that maximizes profit. They then bid for and buy the validators’ blockspace, with the help of one or more relays, so their execution payloads are proposed to the blockchain. + + +# Builder Quickstart + +External builders can submit blocks to Goerli, Sepolia, and Mainnet Flashbots relays. + +**Mainnet relay block submission endpoints:** + +- `getValidators`: [https://boost-relay.flashbots.net/relay/v1/builder/validators](https://boost-relay.flashbots.net/relay/v1/builder/validators) (GET) - array of proposer preferences for registered validators with assigned duties in the current and next epoch +- `submitBlock`: [https://boost-relay.flashbots.net/relay/v1/builder/blocks](https://boost-relay.flashbots.net/relay/v1/builder/blocks) (POST) + +**Goerli relay block submission endpoints:** + +- `getValidators`: [https://builder-relay-goerli.flashbots.net/relay/v1/builder/validators](https://builder-relay-goerli.flashbots.net/relay/v1/builder/validators) (GET) - array of proposer preferences for registered validators with assigned duties in the current and next epoch +- `submitBlock`: [https://builder-relay-goerli.flashbots.net/relay/v1/builder/blocks](https://builder-relay-goerli.flashbots.net/relay/v1/builder/blocks) (POST) + +**Sepolia relay block submission endpoints:** + +- `getValidators`: [https://builder-relay-sepolia.flashbots.net/relay/v1/builder/validators](https://builder-relay-sepolia.flashbots.net/relay/v1/builder/validators) (GET) - array of proposer preferences for registered validators with assigned duties in the current and next epoch +- `submitBlock`: [https://builder-relay-sepolia.flashbots.net/relay/v1/builder/blocks](https://builder-relay-sepolia.flashbots.net/relay/v1/builder/blocks) (POST) + +**Rate-limits:** + +Submissions to all relays are currently rate-limited to 60 / minute. + +**See also:** + +- [Relay API documentation - Block Builder API](https://bit.ly/3BmGZ3T) +- Block Builder Self-Help Group: [https://collective.flashbots.net/c/builders/14](https://collective.flashbots.net/c/builders/14) +- Github issue about becoming block builder: [https://github.com/flashbots/mev-boost/issues/145](https://github.com/flashbots/mev-boost/issues/145) +- [https://github.com/flashbots/boost-geth-builder](https://github.com/flashbots/boost-geth-builder) - an example builder implementation +- [MEV-Boost Geth Builder](https://github.com/flashbots/boost-geth-builder) is a testnet-ready open-source builder reference implementation (not meant for production). + +## How do builders pay block proposers? + +As outlined in the original [MEV-boost architecture proposal,](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177/4) builders construct execution payloads that contain transactions and header parameters provided by validators. Builders may directly set the validator’s `feeRecipient` address as the coinbase address of the payload, which transfers all gas fees and reward payments directly to the block proposer, ***or*** builders may set their own address and include a transaction to the block proposer’s `feeRecipient` address at the end of the block. While this design has not changed since the initial spec of MEV-boost, builders had not implemented this feature and an industry standard has yet to be defined. + +In this article, we outline our preferred solution for builders to make payments to proposers, and provide a release update for payments in the Flashbots reference [boost-geth-builder](https://github.com/flashbots/boost-geth-builder) for further testing. + +### Framing the problem + +In the [Identifier for builder to proposer transaction #220 issue](https://github.com/flashbots/mev-boost/issues/220), staking providers and node operators outlined a need for an accounting mechanism for MEV payments. This mechanism unlocks a number of necessary operations, such as proving receipt of MEV rewards, fair distribution of rewards to staking customers, and preventing malicious activities, such as [MEV hiding](https://dao.rocketpool.net/t/mev-and-penalty-system/772), among others. + +To enable these operations, Flashbots proposes a standardized specification for how payments are made from builders to block proposers through the following process: + +1. The builder sets their own address as `feeRecipient` of the payload header they are constructing. +2. The builder includes a transaction which pays ETH to the proposer’s `feeRecipient` address at the end of their proposed block. + +### Further considerations + +**Withdrawals** + +Validators need to be able to withdraw from the account which receives payment. If payments are made directly to a validator’s recipient account, then the validator would be unable to withdraw anything from that account without adversely affecting the simulated value of that block. The reason is that if the profit of a block is measured by the difference in a validator’s recipient account before and after that block, then a withdraw makes the block look less profitable because it removes assets. To prevent this, validators would need to create a new recipient account for each block they produce. + +**Out of band bribes** + +Additional payment methods using transfers to the validator account, or transfers to the validator on L2s, for example, would allow for validator bribery. Further research and input is needed to address this externality. + +**Gas usage** + +Adding a transaction that calls a smart contract costs additional gas, and becomes an overhead expense on every block. + +### Seeking Feedback + +We are actively seeking input from node operators and the broader community on implications of this proposed design. We are prepared to move forward with this implementation and continue to iterate as community input is received. + +**Please provide comments, feedback, or suggest alternatives directly on this forum thread: [https://collective.flashbots.net/t/block-scoring-for-mev-boost-relays/202/5](https://collective.flashbots.net/t/block-scoring-for-mev-boost-relays/202/5)** diff --git a/docs/flashbots-mev-boost/architecture/block-proposers.md b/docs/flashbots-mev-boost/block proposers.md similarity index 100% rename from docs/flashbots-mev-boost/architecture/block-proposers.md rename to docs/flashbots-mev-boost/block proposers.md diff --git a/docs/flashbots-mev-boost/architecture/relays.md b/docs/flashbots-mev-boost/relays.md similarity index 100% rename from docs/flashbots-mev-boost/architecture/relays.md rename to docs/flashbots-mev-boost/relays.md diff --git a/docs/flashbots-mev-boost/security.md b/docs/flashbots-mev-boost/security.md index 335f2f94..7b6d5e30 100644 --- a/docs/flashbots-mev-boost/security.md +++ b/docs/flashbots-mev-boost/security.md @@ -1,4 +1,4 @@ -# Vulnerabilities +# vulnerabilities If you find a security vulnerability on this project or any other initiative related to Flashbots, please let us know sending an email to security@flashbots.net. # Security Audits diff --git a/docs/sidebars.js b/docs/sidebars.js index 1424d963..6bb956c8 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -129,15 +129,16 @@ module.exports = { "flashbots MEV-boost": [ 'flashbots-mev-boost/introduction', { - 'architecture': [ - 'flashbots-mev-boost/architecture/MEV-boost-specifications', - 'flashbots-mev-boost/architecture/MEV-boost-block-proposal', - 'flashbots-mev-boost/architecture/relays', - 'flashbots-mev-boost/architecture/block-builders', - 'flashbots-mev-boost/architecture/block-proposers', - 'flashbots-mev-boost/architecture/risks' + 'architecture overview': [ + 'flashbots-mev-boost/architecture-overview/MEV-boost-specifications', + 'flashbots-mev-boost/architecture-overview/MEV-boost-block-proposal', + 'flashbots-mev-boost/architecture-overview/risks' ] }, + + 'flashbots-mev-boost/block builders', + 'flashbots-mev-boost/block proposers', + 'flashbots-mev-boost/relays', { 'getting started':[ 'flashbots-mev-boost/getting-started/system-requirements', From 44abde82aaa4ea4bcafe6d2959d71fe416be5e7f Mon Sep 17 00:00:00 2001 From: Chris Hager Date: Fri, 16 Sep 2022 15:56:35 +0200 Subject: [PATCH 012/255] what is mev-boost: add links (#305) --- docs/flashbots-mev-boost/introduction.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/flashbots-mev-boost/introduction.md b/docs/flashbots-mev-boost/introduction.md index 31499153..ec235969 100644 --- a/docs/flashbots-mev-boost/introduction.md +++ b/docs/flashbots-mev-boost/introduction.md @@ -6,6 +6,13 @@ With MEV-Boost, validators can access blocks from a marketplace of builders. Builders produce blocks containing transaction orderflow and a fee for the block proposing validator. Separating the role of proposers from block builders promotes greater competition, decentralization, and censorship-resistance for Ethereum. +See also: +* [boost.flashbots.net](https://boost.flashbots.net/) +* [boost-relay.flashbots.net](https://boost-relay.flashbots.net/) +* [github.com/flashbots/mev-boost](https://github.com/flashbots/mev-boost/) + +--- + ## Why MEV-Boost? MEV is a centralizing force on Ethereum. Unattended, the competition for MEV opportunities leads to consensus instability and permissioned communication infrastructure between searchers, block producers, and validators. Access to MEV is even more important in PoS Ethereum, as the planned [reduction in block subsidies](https://hackmd.io/@flashbots/mev-in-eth2) will make MEV an even [larger share of total staking revenue](https://github.com/flashbots/eth2-research/blob/main/notebooks/mev-in-eth2/eth2-mev-calc.ipynb). From b0150718eac499d9751619fd14a66acc1f7b5a76 Mon Sep 17 00:00:00 2001 From: Chris Hager Date: Fri, 16 Sep 2022 15:56:55 +0200 Subject: [PATCH 013/255] mev-boost block builder docs update (#306) --- docs/flashbots-mev-boost/block builders.md | 37 +++------------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/docs/flashbots-mev-boost/block builders.md b/docs/flashbots-mev-boost/block builders.md index 670e08e8..30a8a9cc 100644 --- a/docs/flashbots-mev-boost/block builders.md +++ b/docs/flashbots-mev-boost/block builders.md @@ -13,6 +13,8 @@ Builders run algorithms and simulations (e.g. First Come First Serve, First Pric # Builder Quickstart +Take a look at our [example builder implementation](https://github.com/flashbots/boost-geth-builder), which is a good reference and in production use by some builders. + External builders can submit blocks to Goerli, Sepolia, and Mainnet Flashbots relays. **Mainnet relay block submission endpoints:** @@ -36,43 +38,14 @@ Submissions to all relays are currently rate-limited to 60 / minute. **See also:** +- [MEV-Boost Geth Builder](https://github.com/flashbots/boost-geth-builder) - an example builder implementation - [Relay API documentation - Block Builder API](https://bit.ly/3BmGZ3T) - Block Builder Self-Help Group: [https://collective.flashbots.net/c/builders/14](https://collective.flashbots.net/c/builders/14) - Github issue about becoming block builder: [https://github.com/flashbots/mev-boost/issues/145](https://github.com/flashbots/mev-boost/issues/145) -- [https://github.com/flashbots/boost-geth-builder](https://github.com/flashbots/boost-geth-builder) - an example builder implementation -- [MEV-Boost Geth Builder](https://github.com/flashbots/boost-geth-builder) is a testnet-ready open-source builder reference implementation (not meant for production). + ## How do builders pay block proposers? As outlined in the original [MEV-boost architecture proposal,](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177/4) builders construct execution payloads that contain transactions and header parameters provided by validators. Builders may directly set the validator’s `feeRecipient` address as the coinbase address of the payload, which transfers all gas fees and reward payments directly to the block proposer, ***or*** builders may set their own address and include a transaction to the block proposer’s `feeRecipient` address at the end of the block. While this design has not changed since the initial spec of MEV-boost, builders had not implemented this feature and an industry standard has yet to be defined. -In this article, we outline our preferred solution for builders to make payments to proposers, and provide a release update for payments in the Flashbots reference [boost-geth-builder](https://github.com/flashbots/boost-geth-builder) for further testing. - -### Framing the problem - -In the [Identifier for builder to proposer transaction #220 issue](https://github.com/flashbots/mev-boost/issues/220), staking providers and node operators outlined a need for an accounting mechanism for MEV payments. This mechanism unlocks a number of necessary operations, such as proving receipt of MEV rewards, fair distribution of rewards to staking customers, and preventing malicious activities, such as [MEV hiding](https://dao.rocketpool.net/t/mev-and-penalty-system/772), among others. - -To enable these operations, Flashbots proposes a standardized specification for how payments are made from builders to block proposers through the following process: - -1. The builder sets their own address as `feeRecipient` of the payload header they are constructing. -2. The builder includes a transaction which pays ETH to the proposer’s `feeRecipient` address at the end of their proposed block. - -### Further considerations - -**Withdrawals** - -Validators need to be able to withdraw from the account which receives payment. If payments are made directly to a validator’s recipient account, then the validator would be unable to withdraw anything from that account without adversely affecting the simulated value of that block. The reason is that if the profit of a block is measured by the difference in a validator’s recipient account before and after that block, then a withdraw makes the block look less profitable because it removes assets. To prevent this, validators would need to create a new recipient account for each block they produce. - -**Out of band bribes** - -Additional payment methods using transfers to the validator account, or transfers to the validator on L2s, for example, would allow for validator bribery. Further research and input is needed to address this externality. - -**Gas usage** - -Adding a transaction that calls a smart contract costs additional gas, and becomes an overhead expense on every block. - -### Seeking Feedback - -We are actively seeking input from node operators and the broader community on implications of this proposed design. We are prepared to move forward with this implementation and continue to iterate as community input is received. - -**Please provide comments, feedback, or suggest alternatives directly on this forum thread: [https://collective.flashbots.net/t/block-scoring-for-mev-boost-relays/202/5](https://collective.flashbots.net/t/block-scoring-for-mev-boost-relays/202/5)** +See this forum thread for a comprehensive discussion: [https://collective.flashbots.net/t/block-scoring-for-mev-boost-relays/202](https://collective.flashbots.net/t/block-scoring-for-mev-boost-relays/202) From 25807ff3424e57ac4502bfcc6b33d08fd8f87654 Mon Sep 17 00:00:00 2001 From: brock <2791467+zeroXbrock@users.noreply.github.com> Date: Tue, 20 Sep 2022 21:35:43 -0700 Subject: [PATCH 014/255] POS update (#303) * update Protect RPC docs w/ post-merge info * add 'future deprecation' comments for fast-mode-related response/params * clarify fast mode comments * include 'optional' in comment * update goerli URL * address Angela's feedback * update 'pending tx time' to 6 minutes instead of 3 days * update welcome & overview * update quick start * remove FAQ, direct reader to forum * update 'for searchers' section * remove 'miners' section * rename "releases" to "mev-geth releases" for clarity * update "data" section * remove Zeneth from community tools (project abandoned) * clean up stray mentions of "miners" * rename "relay.flashbots.net" to "protect.flashbots.net" * grammer and spelling and punctuation * update bundle pricing page * remove 'miner' mention in protect docs * remove last hanging 'miner' mention * fix outdated mentions of "relay" * restore 'relay.flashbots.net' urls * fix 2 more urls * map new blocks API fields to old ones * address Kailin's comments, capitalize proper nouns * fix another grammar mistake * fix instances of "mined" * remove 'Protect' from API nomenclature --- docs/community-tools.mdx | 8 - .../miners/advanced/discord-setup.md | 29 -- .../flashbots-auction/miners/advanced/ffmp.md | 95 ------ .../miners/advanced/interacting-with-relay.md | 5 - .../miners/advanced/source-code.md | 54 ---- docs/flashbots-auction/miners/demo.mdx | 10 - docs/flashbots-auction/miners/faq.mdx | 195 ------------ docs/flashbots-auction/miners/how-it-works.md | 55 ---- .../miners/mev-geth-spec/v01-rpc.mdx | 128 -------- .../miners/mev-geth-spec/v01.md | 129 -------- .../miners/mev-geth-spec/v02-rpc.mdx | 135 -------- .../miners/mev-geth-spec/v02.md | 186 ------------ .../miners/mev-geth-spec/v03-rpc.mdx | 135 -------- .../miners/mev-geth-spec/v03.md | 188 ------------ .../miners/mev-geth-spec/v04-rpc.mdx | 209 ------------- .../miners/mev-geth-spec/v04.md | 211 ------------- .../miners/mev-geth-spec/v05-rpc.mdx | 209 ------------- .../miners/mev-geth-spec/v05.md | 216 ------------- .../miners/mev-geth-spec/v06-rpc.mdx | 245 --------------- .../miners/mev-geth-spec/v06.md | 224 -------------- docs/flashbots-auction/miners/mev-relay.mdx | 154 ---------- docs/flashbots-auction/miners/quick-start.mdx | 36 --- docs/flashbots-auction/other-resources.md | 3 +- docs/flashbots-auction/overview.mdx | 104 ++++--- .../searchers/advanced/bundle-pricing.md | 38 ++- .../searchers/advanced/coinbase-payment.mdx | 10 +- .../searchers/advanced/eip1559.mdx | 7 +- .../advanced/private-transaction.mdx | 41 ++- .../searchers/advanced/reputation.md | 18 +- .../searchers/advanced/rpc-endpoint.mdx | 26 +- .../searchers/advanced/troubleshooting.mdx | 65 ++-- .../advanced/understanding-bundles.mdx | 34 +-- .../searcher-sponsored-tx.md | 4 +- docs/flashbots-auction/searchers/faq.md | 287 +----------------- .../searchers/libraries/alchemyprovider.md | 6 +- .../searchers/libraries/ethers-js-provider.md | 4 +- .../searchers/libraries/golang.md | 4 +- .../searchers/libraries/web3js-provider.md | 0 .../searchers/libraries/web3py-provider.md | 5 +- .../searchers/quick-start.mdx | 8 +- docs/flashbots-data/blockapi.md | 22 +- .../mev-inspect-py/data/arbitrages.md | 6 + .../mev-inspect-py/data/miner_payments.md | 6 + .../flashbots-data/mev-inspect-py/overview.md | 3 +- .../mev-inspect-py/quick-start.md | 2 +- docs/flashbots-protect/overview.md | 11 +- docs/flashbots-protect/rpc/bundle-cache.md | 13 +- docs/flashbots-protect/rpc/cancellations.md | 12 +- docs/flashbots-protect/rpc/fast-mode.md | 38 --- docs/flashbots-protect/rpc/quick-start.md | 29 +- docs/flashbots-protect/rpc/ratelimiting.md | 4 +- docs/flashbots-protect/rpc/status-api.md | 6 +- docs/flashbots-protect/rpc/uncle-bandits.md | 4 +- docs/sidebars.js | 39 +-- docs/welcome.mdx | 6 +- src/css/custom.css | 16 + static/img/block-builder-flow.png | Bin 0 -> 117580 bytes static/img/mevboost-searcher-bundle-flow.png | Bin 0 -> 282260 bytes static/img/relay-flow.png | Bin 0 -> 97304 bytes static/img/searcher-architecture.png | Bin 16855 -> 115108 bytes static/img/validator-flow.png | Bin 0 -> 165582 bytes 61 files changed, 333 insertions(+), 3404 deletions(-) delete mode 100644 docs/flashbots-auction/miners/advanced/discord-setup.md delete mode 100644 docs/flashbots-auction/miners/advanced/ffmp.md delete mode 100644 docs/flashbots-auction/miners/advanced/interacting-with-relay.md delete mode 100644 docs/flashbots-auction/miners/advanced/source-code.md delete mode 100644 docs/flashbots-auction/miners/demo.mdx delete mode 100644 docs/flashbots-auction/miners/faq.mdx delete mode 100644 docs/flashbots-auction/miners/how-it-works.md delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v01-rpc.mdx delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v01.md delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v02-rpc.mdx delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v02.md delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v03-rpc.mdx delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v03.md delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v04-rpc.mdx delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v04.md delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v05-rpc.mdx delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v05.md delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v06-rpc.mdx delete mode 100644 docs/flashbots-auction/miners/mev-geth-spec/v06.md delete mode 100644 docs/flashbots-auction/miners/mev-relay.mdx delete mode 100644 docs/flashbots-auction/miners/quick-start.mdx delete mode 100644 docs/flashbots-auction/searchers/libraries/web3js-provider.md delete mode 100644 docs/flashbots-protect/rpc/fast-mode.md create mode 100644 static/img/block-builder-flow.png create mode 100644 static/img/mevboost-searcher-bundle-flow.png create mode 100644 static/img/relay-flow.png create mode 100644 static/img/validator-flow.png diff --git a/docs/community-tools.mdx b/docs/community-tools.mdx index cfc7cf81..ad87e577 100644 --- a/docs/community-tools.mdx +++ b/docs/community-tools.mdx @@ -15,11 +15,3 @@ title: community tools Simple frontend to interface with https://github.com/flashbots ![Flashbots Tools](/img/flashbots-tools.png) - -### [zeneth](https://github.com/ScopeLift/zeneth) - -[![Zeneth](/img/zeneth.png)](https://youtu.be/lTivZBhqltY) - -A major UX problem in Ethereum is that most wallets are not contract wallets, but externally owned accounts (EOAs), such as MetaMask. With EOAs, you always need ETH for gas unless you happen to be interacting with a contract that supports meta-transactions. This can be problematic for user-facing applications as their new users need to acquire both ETH and often some token to user their application. For example, you don't need ETH for transaction fees on zkSync, but if I'm a new user trying to get DAI into zkSync, I need to first find ETH, use that to pay for gas to enter zkSync, then never use that ETH again. This adds a lot of friction to user onboarding. - -Zeneth fixes this. You can now bundle any sequence of transactions, send them for zero gas, and at the end use our "SwapBriber" contract which will swap some of your tokens for ETH to pay the miner. diff --git a/docs/flashbots-auction/miners/advanced/discord-setup.md b/docs/flashbots-auction/miners/advanced/discord-setup.md deleted file mode 100644 index e7ec7810..00000000 --- a/docs/flashbots-auction/miners/advanced/discord-setup.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: discord setup ---- - -Flashbots' main tool for communicating with participating miners is our Discord server. Please join us there with the invite you've been extended, and follow this quick guide to setting up your Discord effectively. - -## Notifications - -There is a lot of traffic among the many channels and channel categories in the server. In order to make sure you receive all relevant notifications, go to the notifications settings menu by pressing the arrow next to the Flashbots server name: - -![](/img/Discord_menu_location.png) - -There, select "Only @mentions" for the server notifications: - -![](/img/Discord_notifications_mentions.png) - -Then, you want to enable notifications for _all messages_ for your individual channel, as well as for the _#releases_ channel. You can do this by scrolling down in the same menu and searching for these channels, and then selecting ALL: - -![](/img/Discord_notifications_ALL.png) - -Then do the same for your individual channel. This will ensure you get only notifications that are relevant to you, pay attention to these! :D - -## Muting Channels -If you would like to have a less cluttered interface, you can _mute_ channels or channel categories, which will prevent them from being highlighted whenever they have unread messages. This can be done in the same menu, by choosing the MUTE option, or by-right clicking on each channel or category that you want to mute. Do not mute _#releases_ or your individual channels! All the rest are ok to mute. - -## TL;DR -- Set server notifications to only @mentions. -- Choose ALL for notifications in _#releases_ and your individual channel. -- Mute channels and categories that you don't want to follow. diff --git a/docs/flashbots-auction/miners/advanced/ffmp.md b/docs/flashbots-auction/miners/advanced/ffmp.md deleted file mode 100644 index 47bc96ce..00000000 --- a/docs/flashbots-auction/miners/advanced/ffmp.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: flashbots fair market principles ---- - -This document aims to define a set of key principles and best practices upon which stakeholders of the Flashbots network can hold block producers (miners in ETH 1.0) accountable for their continued participation in the Flashbots Alpha. - -Fair Market Principles for MEV is required in the Flashbots Alpha due to the technical limitations in the early stage of the project which are mitigated on the basis of trust. Flashbots aims to eliminate these trust requirements in [future releases of the system](https://ethresear.ch/t/flashbots-frontrunning-the-mev-crisis/8251). - -Block producers connected to the Flashbots Alpha are expected to act in the [best interest](https://www.investopedia.com/what-is-the-sec-s-regulation-bi-best-interest-rule-4689542) of the Flashbots network, the Ethereum network, and its various stakeholders. Namely, the Flashbots network aims to uphold the properties of fairness, efficiency, transparency, and permissionlessness. Block producers participating in the Flashbots Alpha are expected to collaborate in the development of an ecosystem for MEV extraction which reinforces the security and stability of the Ethereum network. - -In the event of a breach of these principles by one of the block producers, the Flashbots Auction devs may act on behalf of stakeholders in disabling the access to the Flashbots network until the breach is rectified. The Flashbots Auction devs aim to provide technical support to block producers on a best effort basis to help resolve any technical issues. - - -## Principles - -### Correctness - -Block producers are expected to operate an Ethereum node which complies with the latest version of the Ethereum specification and the latest version of the Flashbots Auction specification. Block producers are expected to follow the Flashbots Auction upgrade process and swiftly upgrade their nodes to meet latest requirements. - -Bad behavior includes any deviation from the specified node behavior. This includes, but is not limited to, implementation errors, intended omissions, and new "features" which change how the system operates. - -[Flashbots Auction specification](../mev-geth-spec/v02.md) - -### Fairness - -Block producers are expected never to act or enable third parties to act on sensitive information received through the Flashbots relay. - -Sensitive information includes the state of the MEV bundle queue, sealed bid, pending block, bundle simulation, bundle content, or bundle merging. Sensitive information excludes MEV bundles correctly included in a block and distributed over the public network with the intention of such block being included as a canonical block or as an uncle block. - -Bad behavior includes, but is not limited to, operating a trading bot which benefits from knowing the winning bid value of the bundle auction, operating a trading bot which steals or frontruns strategies from bundles, operating a bundle selection algorithm which prioritizes some searchers over others. - -### Finality - -Block producers are expected to contribute to the consensus stability of Ethereum. This means minimizing the uncle rate and re-organization rate in an effort to provide finality as quickly as possible. - -Bad behavior includes, but is not limited to, re-ordering chain history in an attempt to extract MEV in what is called a "time-bandit attack", and prioritizing transmission of sealed blocks to subsets of the network in what is called "selfish mining". - -In the future, we may additionally require participants in the Flashbots network to defend against such attacks actively, ensuring the long-term health of any networks supported by Flashbots and therefore the MEV ecosystem. - -### Privacy - -Block producers are expected to protect the confidentiality of the MEV bundles they receive from the Flashbots relay. - -Confidentiality includes both pre-trade privacy and failed-trade privacy: -- Pre-trade privacy: No MEV bundle received by the miner is ever disclosed to any third party before the bundle is included in a block. -- Failed-trade privacy: No MEV bundle received by the miner is ever disclosed to any third party after it has not been selected for a block. - -Bad behavior includes, but is not limited to, sending bundle information to third parties, and storing bundle information to persistent storage past their intended use. - -## Best Practices - -### Disclosure - -Block producers disclose if they are connected to the Flashbots network. - -Block producers disclose the coinbase address they are using. - -Block producers disclose how their MEV revenues are distributed to their stakeholders. - -### Reporting - -Block producers report the amount of hashrate they point to their Flashbots node. - -Block producers report the amount of revenue they received from the Flashbots network. - -### Professionalism - -Block producers are diligent in swiftly and correctly implementing the latest versions of Flashbots Auction and Ethereum without unjustified delay. - -Block producers properly secure their node infrastructure to protect the integrity of their system. This includes, but is not limited to, making use of reverse proxies, firewalls, and strict access control to prevent information leaks. - -### Incident Response - -Block producers quickly respond, mitigate, and remediate incidents causing unexpected behavior of their system. - -### Communication - -Block producers actively monitor the Flashbots Discord and mev-geth Github repository to remain up to date with latest Flashbots Auction releases and core dev communication. - -## Penalty & Remediation - -Penalties for violating the Flashbots Fair Market Principles and Best Practices can range from a simple warning to being removed from the Flashbots relay until the violations are resolved. -Warnings will be communicated to the offending block producer through the dedicated Flashbots Discord channel and are expected to be acknowledged within 24h. - -Block producers are expected to collaborate with Flashbots Auction devs to promptly resolve any issue as they arise. - -Flashbots Auction devs will provide technical support on a "best effort" basis in order to help bring the offending block producer back into compliance with the FFMP. - -## Feedback & Discussion - -Please provide feedback on the FFMPs and engage in discussion in the [Flashbots forum](https://github.com/flashbots/pm/discussions/65). - -## Disclaimer - -Flashbots Auction and Flashbots alpha is an open-source software stack, while we will attempt to provide support for any issues or test infrastructure we run, we cannot provide any guarantees associated with the use of Flashbots tools and encourage a miner-side diligence process for all network participants. diff --git a/docs/flashbots-auction/miners/advanced/interacting-with-relay.md b/docs/flashbots-auction/miners/advanced/interacting-with-relay.md deleted file mode 100644 index 073dd508..00000000 --- a/docs/flashbots-auction/miners/advanced/interacting-with-relay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: interacting with relay ---- - -In order to facilitate your interaction with MEV-Relay, we have created the [mev-proxy repository](https://github.com/flashbots/mev-proxy) as a simple example of a reserve proxy a miner can run to expose just the eth_sendBundle JSON-RPC method. diff --git a/docs/flashbots-auction/miners/advanced/source-code.md b/docs/flashbots-auction/miners/advanced/source-code.md deleted file mode 100644 index ac6803d1..00000000 --- a/docs/flashbots-auction/miners/advanced/source-code.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: source code ---- - -The entire changeset can be viewed inspecting the [diff](https://github.com/ethereum/go-ethereum/compare/master...flashbots:master). - -The entire patch can be broken down into major releases with a few commits in each: - -#### v0.1.0 - -- commits [d86f1a64416c3e6b50c333c6fd2c5f7ec58bdf5e](https://github.com/flashbots/mev-geth/commit/d86f1a64416c3e6b50c333c6fd2c5f7ec58bdf5e) and [fcc3b6d2973e5905651f66dbab99b9f790059f6f](https://github.com/flashbots/mev-geth/commit/fcc3b6d2973e5905651f66dbab99b9f790059f6f) bundle worker and `eth_sendBundle` rpc -- commit [34d4b559a24f8c43e1d4354a73bbba91b6b6b9e7](https://github.com/flashbots/mev-geth/commit/34d4b559a24f8c43e1d4354a73bbba91b6b6b9e7) profit switcher -- commit [959394df8b6b0ce868c2231e74f47bfdf89e0f72](https://github.com/flashbots/mev-geth/commit/959394df8b6b0ce868c2231e74f47bfdf89e0f72) Documentation (this file) and CI/infrastructure configuration - -#### v0.1.1 - -- commit [88247f37b97efff7da0ff722c00a8370f2b1ba95](https://github.com/flashbots/mev-geth/commit/88247f37b97efff7da0ff722c00a8370f2b1ba95) correct handling or reorgs - -#### v0.2.0-pre - -- commit [b94943ecb2e85f720a5675a6d2f95a6b96870ec0](https://github.com/flashbots/mev-geth/commit/b94943ecb2e85f720a5675a6d2f95a6b96870ec0) Change flashbots bundle pricing formula to ignore gas fees -- commit [4b7668d4d7579eecc15be65c9c7902ff7e3ad341](https://github.com/flashbots/mev-geth/commit/4b7668d4d7579eecc15be65c9c7902ff7e3ad341) Discard bundles with reverting txs - -#### v0.2.0 - -- commit [d823ec7133a0f0d21932b1d893d37ad80949819e](https://github.com/flashbots/mev-geth/commit/d823ec7133a0f0d21932b1d893d37ad80949819e) Change pricing formula to ignore gas from txs in the txpool -- commit [92463dc9c3b95a58991c36be9fddd1340b32eeb5](https://github.com/flashbots/mev-geth/commit/92463dc9c3b95a58991c36be9fddd1340b32eeb5) Use object in eth_sendBundle params and add revertingTxHashes param -- commit [5a30f876ba9725554eb8609e8f60cada5b961e57](https://github.com/flashbots/mev-geth/commit/5a30f876ba9725554eb8609e8f60cada5b961e57) Add bundle merging with multiple workers - -#### v0.2.1 - -- commit [a172ca123a3c2534573779008fbf8b3c853b4e57](https://github.com/flashbots/mev-geth/commit/a172ca123a3c2534573779008fbf8b3c853b4e57) Add floor gas price for bundle inclusion - -#### v0.2.2 - -- commit [2d05e741d42f795eecfa2f8185f1575e8e5cc1dc](https://github.com/flashbots/mev-geth/commit/2d05e741d42f795eecfa2f8185f1575e8e5cc1dc) count eth payments for txs whose nonce is in the mempool - -#### v0.3 - -- commit [68f7addad7ba100a59a280bfbdef2f556bcf8401](https://github.com/flashbots/mev-geth/commit/68f7addad7ba100a59a280bfbdef2f556bcf8401) Add flashbots support for eip-1559 - -#### v0.4 - -- commit [8677391535b221b6d129332d1adcbe3184dfc97f](https://github.com/flashbots/mev-geth/commit/8677391535b221b6d129332d1adcbe3184dfc97f) Add megabundles - -#### v0.5 - -- commit [f66aad30bcdcae3cf03d4970bc3581bd9b82caa7](https://github.com/flashbots/mev-geth/commit/f66aad30bcdcae3cf03d4970bc3581bd9b82caa7) Calculate megabundles as soon as they are received - -#### v0.6 - -- commit [16f9b7c2a9ddb70fa875a654da6c23c2e620981f](https://github.com/flashbots/mev-geth/commit/16f9b7c2a9ddb70fa875a654da6c23c2e620981f) Private transactions API - -- commit [71ab3bd774cea63f7cbd1a5b55a11b15f1aabdaf](https://github.com/flashbots/mev-geth/commit/71ab3bd774cea63f7cbd1a5b55a11b15f1aabdaf) Remove private transactions confirmed in a block \ No newline at end of file diff --git a/docs/flashbots-auction/miners/demo.mdx b/docs/flashbots-auction/miners/demo.mdx deleted file mode 100644 index ff7687da..00000000 --- a/docs/flashbots-auction/miners/demo.mdx +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: demo ---- -### Demo - -[mev-geth-demo](https://github.com/flashbots/mev-geth-demo) is a repository that launches an MEV-Geth node, and shows how a miner may profit from it by accepting MEV -bundles either via direct `block.coinbase` payments, or with extra transactions that pay -the block's coinbase if it's known ahead of time. - -Access the [`mev-geth-demo` repository here](https://github.com/flashbots/mev-geth-demo). diff --git a/docs/flashbots-auction/miners/faq.mdx b/docs/flashbots-auction/miners/faq.mdx deleted file mode 100644 index ea45e892..00000000 --- a/docs/flashbots-auction/miners/faq.mdx +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: FAQ ---- - -*Check Flashbots Discord [#release](https://discord.com/invite/7hvTycdNcK) channel for the latest releases.* - -Don't see your question answered? Join our [#⛏️miners](https://discord.com/invite/7hvTycdNcK) channel on Discord! - - -### What is MEV? -MEV stands for [Maximal Extractable Value](https://github.com/flashbots/mev-research/issues/24) (previously defined as [Miner Extractable Value](https://www.youtube.com/watch?reload=9&v=vR1v7AQ8i3k&ab_channel=IEEESymposiumonSecurityandPrivacy)). On any smart-contract blockchain, MEV is the maximal value that can be permissionlessly extracted from transaction ordering. This includes both 'basic' value such as transactions fees and block rewards, as well as 'advanced' value such as any kind of arbitrary inclusion, exclusion and re-ordering of transactions. On Ethereum today, miners have the most permissionless power with respect to transaction ordering. MEV exists on both layer 1 and layer 2 architecture, and will still exist in the future after Ethereum shifts to [2.0](https://hackmd.io/@flashbots/mev-in-eth2). - -In order to differentiate between the theoretical maximum extractable and what _is_ extracted from transaction ordering, we introduce the term REV - Realized Extractable Value to denote the value that _has been_ extracted as opposed to the theoretical maximal value (MEV) that _could have been_ extracted in a given block from the ordering of transactions. Most REV is captured today by DeFi traders, miners profit from it via the transactions fees these traders pay for their transactions to be prioritized. - -### How much MEV revenue has been extracted on Ethereum? - -According to preliminary results from our [data collection and processing efforts](https://github.com/flashbots/mev-inspect-rs), a conservative estimate of REV, the total value extracted from transaction ordering on Ethereum since February 2020 is worth over $720 million. This figure accounts for revenue captured by traders who deployed common MEV strategies on DeFi protocols, and gas fees spent on these trades that went to miners who ended up mining the blocks with such MEV strategies. More metrics can be explored through our [public dashboard](https://explore.flashbots.net). - -(_Note: As we expand our data collection efforts to further increase our coverage of major MEV-strategies, we expect REV measured to be significantly higher._) - -### What is the revenue upside from running Flashbots Alpha? - -We estimate the average MEV opportunity to be worth at least 0.25 ETH per block today, and expect it to grow as more MEV strategies get deployed and more DeFi protocols enter the space. Early Flashbots Alpha adopters will be able to enjoy first-mover advantage and capture a significant margin of the revenue generated by traders. - -MEV revenue scales with the volume of users. The more users send transaction bundles via MEV-relay to miners who run MEV-geth, the more MEV revenue will go to miner(s) and/or mining pool(s). - -**Case study transaction:** -https://etherscan.io/tx/0xf8333db853d92fd3a26a05a4b524146773ddbfe1bbc32a800efec32ea7eebb36 - -This was a 10.2 ETH arbitrage opportunity between two decentralized exchanges. [The trader](https://etherscan.io/address/0x94d6522c80fb261c147a4111ad9a49407042f9b4) paid the miner 1.8 ETH through regular transaction fees in order to be the one to secure this opportunity and profited 8.4 ETH from it. This adds up to 18% of the transaction value going to the miner and 82% to the trader. - -Our open-source arbitrage trading bot was able to identify this same opportunity and submitted a Flashbots bundle for it to a miner running MEV-geth. Unfortunately, the miner didn't win the relevant block and the strategy went to the trader mentioned above. Had the Flashbots bundle been mined and because our bot is currently set to give 100% to miners, the miner running MEV-geth would've made 10.2 ETH or 5.6x more! - -This is purely anecdotal as we don't expect Flashbots users to give 100% of their profits to miners. Yet, by having open-sourced this MEV strategy, it means anyone can replicate it anytime, thus creating more competition amongst the traders who will increase the % they give to miners in order to be included. Because transaction bundle submission on Flashbots does not incur gas fee for failed transactions, traders are incentivized to act as an MEV searcher and submit the same strategy on Flashbots as a seal-bid auction. - -### What is Flashbots? How does it plan to make money? - -Flashbots is a [research and development organization](https://github.com/flashbots/pm) formed to mitigate the negative externalities and existential risks posed by miner-extractable value (MEV) to smart-contract blockchains. We are building a permissionless, transparent, and fair ecosystem for MEV extraction to reinforce the Ethereum ideals. Read more about our organization and public commitments [here](https://medium.com/flashbots/frontrunning-the-mev-crisis-40629a613752). - -Flashbots Alpha is an open-source software that does not extract any fees. That being said, fair and sustainable MEV revenue distribution across ecosystem stakeholders is a core area of study that our [research efforts](https://github.com/flashbots/mev-research) are actively looking into. - -### Why MEV-geth? - -Transaction inclusion priority and private mempool services become more valuable every day that Ethereum’s DeFi ecosystem grows. The current method to express transaction priority is through gas. Miners are the entity that have the most permissionless control over transaction inclusion and their mempool. We believe there exists a gap between miners and users. - -MEV-geth bridges that gap. It allows miners to satisfy the user’s need, in exchange for additional revenue, on top of their pre-existing Ethereum transaction fees and block reward. This is done by outsourcing part of the mempool’s transaction selection and ordering process to third-party MEV-searchers who want to include their transactions as soon as possible (e.g. arbitrageurs). - - -### What are the benefits of running MEV-geth vs. partnering directly with a trader (bot operator)? - -From a short-to-medium term standpoint, we believe the revenue source from a diverse pool of high-quality traders will outweigh any bespoke fee-sharing deal with an individual trader both in size and in stability: - -Flashbots provides open access for anyone to become an MEV searcher to submit transaction bundles. The sealed-bid auction mechanism of Flashbots that provides pre-trade privacy is inducive to attracting sophisticated traders who are competitive in the MEV game. From the miners' perspective, this enables profiting from a broad range of high-quality MEV opportunities that cannot be conceivably covered by a single bot operator. This is not only relevant for profitability but also for stability of your revenue: DeFi trading strategies become efficient very quickly and traders will need to constantly preserve their competitive edge by finding new strategies, it is much more likely that the blended average competitive edge of our pool of traders will be consistently higher than of a single trader. - -From a longer-term standpoint, by running MEV-geth and being a market participant you are contributing to the Flashbots network effect: -more hashrate running MEV-geth leads to more MEV-search activity which leads to more MEV revenue for miners, which leads to more hashrate running MEV-geth! - - -### What are the main differences between MEV-geth vs. geth? - -MEV-geth is a fork of geth that adds an ability to include transaction bundles at the beginning of each block via a new `eth_sendBundle` RPC call. You can see a summary of the differences between MEV-geth and geth [here](https://github.com/flashbots/mev-geth/blob/master/README.md#what-is-the-difference-between-mev-geth-and-geth), and a detailed list of changes by inspecting the [diff](https://github.com/ethereum/go-ethereum/compare/master...flashbots:master#diff-c426ecd2f7d247753b9ea8c1cc003f21fa412661c1f967d203d4edf8163da344R1970). - - -### How does MEV-geth technically guarantee a net positive outcome for miners? - -MEV-geth [compares](https://github.com/flashbots/mev-geth/blob/master/miner/worker.go#L1211) a regular block template vs. a template with Flashbots transaction bundles inserted in it. It will only mine the block template that includes the bundles if it results in higher miner revenue. - -The Flashbots transaction bundles that outcompetes the least profitable transaction(s) at the bottom of a block will be included. If the Flashbots transaction bundles are not as profitable to include comparing to regular transactions, MEV-geth will default to regular block template. Thus the payout of mining on MEV-geth will be strictly more profitable than mining on geth, holding all else constant. - - -### When I run MEV-geth, how can I know for sure any additional revenue comes from MEV, rather than normal variance from mining? -The are a couple ways to see revenue that results from MEV: -* Transactions at the beginning of a block that send ETH to mining pool address; -* Searching MEV-geth logs: `grep Flashbots bundle`. - Results will look like `Flashbots bundle bundlePrice=48471302632 bundleLength=1`. - Note: the `bundlePrice` here is an adjusted gas price, not actually ETH. -* Query the [Flashbots blocks API](https://blocks.flashbots.net) to find the profit per block: -``` -> curl 'https://blocks.flashbots.net/v1/blocks?block_number=12006597' -{ - "blocks": [ - { - "block_number": 12006597, - "miner_reward": 89103402731082940, - "miner": "0xd224ca0c819e8e97ba0136b3b95ceff503b79f53", - "coinbase_transfers": 51418761731082940, - "gas_used": 374858, - "gas_price": 237699082668, - "transactions": [...] - - } - ] -} -``` -or find the most recent 100 blocks mined by an address -``` -> curl 'https://blocks.flashbots.net/v1/blocks?miner=0xd224ca0c819e8e97ba0136b3b95ceff503b79f53-```--###%20How%20does%20MEV%20revenue%20work%20with%20existing%20mining%20pool%20reward%20systems,%20in%20particular%20Pay%20Per%20Share%20(PPS)%20vs.%20Pay%20Per%20Last%20(luck)%20N%20Shares%20(PPLNS)?--Dominant%20mining%20pool%20reward%20systems%20today%20has%20emerged%20over%2010%20years%20ago%20when%20pooled%20mining%20emerged%20on%20Bitcoin%20network.-MEV%20opportunities%20present%20on%20smart%20contract%20blockchain,%20made%20available%20to%20miner(s)%20and/or%20mining%20pool(s)%20additional%20revenue%20source%20with%20different%20distribution%20from%20block%20rewards%20and%20transaction%20fees.--Incumbent%20mining%20pools%20already%20in%20operation%20may%20continue%20to%20apply%20its%20existing%20reward%20system,%20i.e.%20PPS%20or%20PPLNS,%20by%20treating%20MEV%20revenue%20as%20part%20of%20the%20transaction%20fee%20in%20paying%20out%20the%20miners.--Alternatively,%20we%20may%20see%20MEV%20mining%20pools%20forming,%20where%20distribution%20of%20MEV%20revenue%20takes%20into%20account%20the%20variance%20of%20MEV%20opportunities%20modified%20on%20top%20of%20existing%20mining%20pool%20reward%20systems.---###%20Does%20Flashbots%20run%20any%20simulation%20on%20how%20much%20money%20can%20be%20made%20by%20a%20miner%20if%20they%20were%20to%20run%20MEV-geth%20now?--Any%20miner%20listed%20on%20the%20Flashbots%20MEV-relay%20miner%20registry%20can%20track%20the%20MEV%20revenue%20on%20Flashbots%20network%20by%20examining%20the%20MEV-geth%20logs.%20Flashbots%20would%20like%20to%20work%20with%20ecosystem%20contributors%20to%20create%20open-sourced%20tooling%20and%20dashboards%20in%20order%20to%20improve%20visibility%20of%20the%20MEV%20extraction%20on%20the%20Flashbots%20ecosystem.---###%20How%20long%20will%20it%20take%20for%20me%20to%20see%20significant%20revenue%20differences%20from%20MEV%20after%20I%20try%20Flashbots%20Alpha?--MEV%20opportunities%20are%20not%20distributed%20uniformly%20within%20blocks%20and%20are%20unpredictable,%20yet%20highly%20lucrative.%20Mining%20a%20block%20with%20Flashbots%20transaction%20bundle%20is%20a%20probability%20game%20with%20different%20distribution%20on%20top%20of%20proof-of-work%20mining.--It%20depends%20on%20MEV%20searcher%20competition%20on%20Flashbots.%20The%20more%20competition%20amongst%20MEV%20searchers%20sending%20transaction%20bundles%20to%20miners%20running%20MEV-geth%20through%20MEV-relay,%20the%20more%20likely%20you%20will%20see%20significant%20revenue%20differences%20soon%20after%20you%20set%20up%20MEV-geth%20and%20join%20MEV-relay.--It%20also%20depends%20on%20%%20of%20your%20hashrate%20relative%20to%20the%20rest%20of%20the%20network.%20The%20more%20frequently%20you%20mine%20a%20block%20the%20more%20likely%20it%20is%20to%20include%20an%20MEV%20opportunity.--As%20Flashbots%20gains%20more%20users%20and%20DeFi%20continues%20to%20grow,%20you%20can%20expect%20seeing%20increased%20percentage%20of%20mining%20revenue%20coming%20from%20MEV.--###%20If%20more%20mining%20pools%20adopt%20MEV-geth,%20would%20my%20potential%20revenue%20from%20MEV%20decrease%20due%20to%20competition?--No.%20Your%20revenue%20from%20MEV%20only%20depends%20on%20mining%20blocks%20that%20include%20an%20MEV%20opportunity.%20Other%20pools%20adopting%20MEV-geth%20don't impact your revenue as long your hashrate % stays constant. - -As more miners adopt MEV-geth we can expect more searcher becoming interested in submitting transactions via Flashbots driving increased searcher competition and more revenue for mining pools. - -### What is the impact of Flashbots on gas fees collected from normal transactions? - -If the block is full, including a Flashbots transaction bundle will result in the lowest-priced transaction(s) to be pushed out of the bottom of the block. This will slightly reduce revenue component from gas but compensated by MEV revenue from the Flashbots bundle. - -Therefore, if a Flashbots transaction bundle is included, the miner revenue is always guaranteed to be higher than a regular block. - - -### Has Flashbots done any load testing of MEV-geth? Where can I see the tests/results? -Load testing results: -* 5 bundles at 12m gas each: 2-3s -* 30 bundles at 3m gas each: ~9s -* 15 bundles at 12m gas each: ~20s - -These tests were done on an AWS m5.xlarge running MEV-geth. In practice, this should not matter for miners, since Flashbots Alpha limits the bundles at the MEV-relay level. - -### Why should miner(s) and/or mining pool(s) use MEV-relay vs exposing its own MEV-geth node's RPC endpoint? - -During Flashbots Alpha phase, we suggest miner(s) and/or mining pool(s) use MEV-relay, and do not expose RPC endpoint, for three reasons: - -First, exposing your MEV-geth node's RPC endpoint without having taken the proper security measures opens you up to spam. We invest significant engineering resources into spam prevention, rate limiting, bundle simulation and queuing to ensure high reliability for the network. In the future, Flashbots plans to iterate towards a decentralized approach to solving this problem through improving the design of MEV-relay. - -Secondly, during Alpha phase bootstrapping MEV searcher activities, Flashbots is responsible for keeping the uptime guarantee for the MEV searcher network. Exposing endpoints directly will make your infrastructure susceptible to attack vectors such as DDoS and may put the entire Flashbots network at risk and breaks our obligations to the searchers, which may reduce the MEV revenue on the Flashbots network. - -Lastly, during Alpha phase, we are collecting data on Flashbots network activities to improve Flashbots infrastructure. Therefore, we would prefer if more MEV transaction bundles are submitted through MEV-relay, which in turn will help us iterate towards next version. - -_Note: continuous degraded performance of miner(s) and/or mining pool(s)' endpoint may result in its temporary exclusion from the network._ - -### Can miners/mining pools choose to include only part of a Flashbots transaction bundle submitted through Flashbots? - -No, miner(s) and/or mining pool(s) running MEV-geth without modification cannot include only part of Flashbots transaction bundle. The current MEV-geth implementation includes entire transaction bundles. - -Since miner payoff depends on MEV capture strategy success, removing a transaction from the bundle is likely to result in MEV not being captured, resulting in 0 payoff and exclusion of such bundle from the block. - -### How does Flashbots prevent malicious pool behavior in the system? - -During Alpha phase, Flashbots monitors flow of transaction bundles via MEV-relay and compares them vs. on-chain record. If malicious behavior like front-running incoming bundles or selling access to incoming bundles is detected, the miner(s) and/or mining pool(s) may be excluded from MEV-relay. - -### Why shouldn't a miner collaborate with a trader directly by sharing Flashbots transaction bundle flow with them? - -Collusion between miner(s) and mining pool(s) on sharing transaction bundle flow will provide asymmetric advantage to certain traders of the ecosystem and potentially drive the best MEV searchers away, because the auction is no-longer fair. - -From a short-to-medium term standpoint, we believe the MEV revenue sourced from a diverse set of competitive traders will outweigh any bespoke fee-sharing deal with an individual trader both in revenue amount and in stability: - -Flashbots provides open access for anyone to become an MEV searcher to submit transaction bundles. The sealed-bid auction mechanism of Flashbots that provides pre-trade privacy is inducive to attracting sophisticated traders who are competitive in the MEV game. - -From a miners' perspective, this enables you to profit from a broad range of high-quality MEV opportunities that cannot be conceivably covered by a single bot operator. - -This is not only relevant for profitability but also for stability of your revenue: DeFi trading strategies become efficient very quickly and traders will need to constantly preserve their competitive edge by finding new strategies, it is likely that the weighted average of Flashbots' traders competitive edge will be consistently higher than of a single trader. - -### Can I test mining on Ropsten? - -No, there is no Flashbots Ropsten relay. Flashbots team uses Goerli network for testing new releases. Miners are expected to test bundles behaviour against their own disconnected test node or a local test network. - -### Where can I view the health status of Flashbots' infrastructure? - -Status is reported at https://status.flashbots.net/ . Please check this link for any network outages or downtime. - -## Resources - -* Example arbitrage searcher: https://bit.ly/3hGbDtk -* Miner Proxy: https://github.com/flashbots/mev-proxy -* MEV-Relay repo (deprecated): https://github.com/flashbots/mev-relay-js -* Flashbots ethers.js provider: https://bit.ly/2MpNFXI -* Searcher FAQ: https://bit.ly/2Xb3FiI -* Ask any questions in Flashbots Discord [#⛏️miners](https://discord.com/invite/7hvTycdNcK) Channel, or email us at info@flashbots.net \ No newline at end of file diff --git a/docs/flashbots-auction/miners/how-it-works.md b/docs/flashbots-auction/miners/how-it-works.md deleted file mode 100644 index b6dc4810..00000000 --- a/docs/flashbots-auction/miners/how-it-works.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: how it works ---- - -### MEV-Geth: a proof of concept - -We have designed and implemented a proof of concept for permissionless MEV extraction called MEV-Geth. It is a sealed-bid block space auction mechanism for communicating transaction order preference. While our proof of concept has incomplete trust guarantees, we believe it's a significant improvement over the status quo. The adoption of MEV-Geth should relieve a lot of the network and chain congestion caused by frontrunning and backrunning bots. - -| Guarantee | PGA | Dark-txPool | MEV-Geth | -| -------------------- | :-: | :---------: | :------: | -| Permissionless | ✅ | ❌ | ✅ | -| Efficient | ❌ | ❌ | ✅ | -| Pre-trade privacy | ❌ | ✅ | ✅ | -| Failed trade privacy | ❌ | ❌ | ✅ | -| Complete privacy | ❌ | ❌ | ❌ | -| Finality | ❌ | ❌ | ❌ | - -### Why MEV-Geth? - -We believe that without the adoption of neutral, public, open-source infrastructure for permissionless MEV extraction, MEV risks becoming an insiders' game. We commit as an organization to releasing reference implementations for participation in fair, ethical, and politically neutral MEV extraction. By doing so, we hope to prevent the properties of Ethereum from being eroded by trust-based dark pools or proprietary channels which are key points of security weakness. We thus release MEV-Geth with the dual goal of creating an ecosystem for MEV extraction that preserves Ethereum properties, as well as starting conversations with the community around our research and development roadmap. - -### Design goals - -- **Permissionless** - A permissionless design implies there are no trusted intermediary which can censor transactions. -- **Efficient** - An efficient design implies MEV extraction is performed without causing unnecessary network or chain congestion. -- **Pre-trade privacy** - Pre-trade privacy implies transactions only become publicly known after they have been included in a block. Note, this type of privacy does not exclude privileged actors such as transaction aggregators / gateways / miners. -- **Failed trade privacy** - Failed trade privacy implies loosing bids are never included in a block, thus never exposed to the public. Failed trade privacy is tightly coupled to extraction efficiency. -- **Complete privacy** - Complete privacy implies there are no privileged actors such as transaction aggregators / gateways / miners who can observe incoming transactions. -- **Finality** - Finality implies it is infeasible for MEV extraction to be reversed once included in a block. This would protect against time-bandit chain re-org attacks. - -The MEV-Geth proof of concept relies on the fact that searchers can withhold bids from certain miners in order to disincentivize bad behavior like stealing a profitable strategy. We expect a complete privacy design to necessitate some sort of private computation solution like SGX, ZKP, or MPC to withhold the transaction content from miners until it is mined in a block. One of the core objective of the Flashbots organization is to incentivize and produce research in this direction. - -The MEV-Geth proof of concept does not provide any finality guarantees. We expect the solution to this problem to require post-trade execution privacy through private chain state or strong economic infeasibility. The design of a system with strong finality is the second core objective of the MEV-Geth research effort. - -### How it works - -MEV-Geth introduces the concepts of "searchers", "transaction bundles", and "block template" to Ethereum. Effectively, MEV-Geth provides a way for miners to delegate the task of finding and ordering transactions to third parties called "searchers". These searchers compete with each other to find the most profitable ordering and bid for its inclusion in the next block using a standardized template called a "transaction bundle". These bundles are evaluated in a sealed-bid auction hosted by miners to produce a "block template" which holds the [information about transaction order required to begin mining](https://ethereum.stackexchange.com/questions/268/ethereum-block-architecture). - -![](https://hackmd.io/_uploads/B1fWz7rcD.png) - -The MEV-Geth proof of concept is compatible with any regular Ethereum client. The Flashbots Auction devs are maintaining [a reference implementation](https://github.com/flashbots/mev-geth) for the go-ethereum client. - -### Differences between MEV-Geth and [_vanilla_ geth](https://github.com/ethereum/go-ethereum) - -You can find a detailed list of changes [here](advanced/source-code.md) - -### Moving towards version 1.0 - -We believe a sustainable solution to MEV existential risks requires complete privacy and finality, which the proof of concept does not address. We hope to engage community feedback throughout the development of this complete version of MEV-Geth. diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v01-rpc.mdx b/docs/flashbots-auction/miners/mev-geth-spec/v01-rpc.mdx deleted file mode 100644 index 445d30ce..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v01-rpc.mdx +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: v0.1 RPC ---- - -## eth_sendBundle - -### Description - -Sends a bundle of transactions to the miner. The bundle has to be executed at the beginning of the block (before any other transactions), with bundle transactions executed exactly in the same order as provided in the bundle. During the Flashbots Alpha this is only called by the Flashbots relay. - -| Name | Type | Description | Comment ---------|----------|-----------|----------- -transactions | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | a no-op in the light mode -blockNumber |`Quantity` |Exact block number at which the bundle can be included. |bundle is evicted after the block -minTimestamp |`Quantity` |Minimum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -maxTimestamp |`Quantity` |Maximum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. - -### Returns - -{`boolean`} - `true` if bundle has been accepted by the node, otherwise `false` - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendBundle", - "params": [ - [ - "f9014946843b9aca00830493e094a011e5f4ea471ee4341a135bb1a4af368155d7a280b8e40d5f2659000000000000000000000000fdd45a22dd1d606b3782f2119621e928e32743000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000", - "f86e8204d085012a05f200830c350094daf24c20717f428f00d8448d74d67a77f67ceb8287354a6ba7a18000802ea00e411bcb660dd8d47717df89078d2e8160c08e7f11cb7ad0ee935e7436eceb32a013ee00a21b7fa0a9f9c1224d11261648191875d4633aed6003543ea319f12b62" - ], - "0x12ab34", - "0x0", - "0x0" - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": true -} -``` - -## eth_callBundle - -### Description - -Simulate a bundle of transactions at the top of a block. - -After retrieving the block specified in the `blockNrOrHash` it takes the same `blockhash`, `gasLimit`, `difficulty`, same `timestamp` unless the `blockTimestamp` property is specified, and increases the block number by `1`. `eth_callBundle` will timeout after `5` seconds. - -| Name | Type | Description | -| ---- | ---- | ----------- | -| encodedTxs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | -| blockNrOrHash | `Quantity\|string\|Block Identifier` | Block number, or one of "latest", "earliest" or "pending", or a block identifier as described in {Block Identifier} | -| blockTimestamp |`Quantity` |Block timestamp to be used in replacement of the timestamp taken from the parent block. | - -### Returns - -Map<`Data`, "error|value" : `Data`> - a mapping from transaction hashes to execution results with error or output (value) for each of the transactions - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_callBundle", - "params": [ - [ - "f9014946843b9aca00830493e094a011e5f4ea471ee4341a135bb1a4af368155d7a280b8e40d5f2659000000000000000000000000fdd45a22dd1d606b3782f2119621e928e32743000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000", - "f86e8204d085012a05f200830c350094daf24c20717f428f00d8448d74d67a77f67ceb8287354a6ba7a18000802ea00e411bcb660dd8d47717df89078d2e8160c08e7f11cb7ad0ee935e7436eceb32a013ee00a21b7fa0a9f9c1224d11261648191875d4633aed6003543ea319f12b62" - ], - "0x12ab34" - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": - { - "0x22b3806fbef9532db4105475222983404783aacd4d865ea5dab76a84aa1a07eb" : { - "value" : "0x0012" - }, - "0x489e3b5493af31d55059f8e296351b267720bc4ba7dc170871c1d789e5541027" : { - "value" : "0xabcd" - } - } -} -``` - ---- - -Below type description can also be found in [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474) - -### `Quantity` - -- A `Quantity` value **MUST** be hex-encoded. -- A `Quantity` value **MUST** be "0x"-prefixed. -- A `Quantity` value **MUST** be expressed using the fewest possible hex digits per byte. -- A `Quantity` value **MUST** express zero as "0x0". - -### `Data` - -- A `Data` value **MUST** be hex-encoded. -- A `Data` value **MUST** be “0x”-prefixed. -- A `Data` value **MUST** be expressed using two hex digits per byte. - -### `Block Identifier` - -Since there is no way to clearly distinguish between a `Data` parameter and a `Quantity` parameter, [EIP-1898](https://eips.ethereum.org/EIPS/eip-1898) provides a format to specify a block either using the block hash or block number. The block identifier is a JSON `object` with the following fields: - -| Position | Name | Type | Description | -| -------- | ---- | ---- | ------------| -| 0A |blockNumber |`Quantity` |The block in the canonical chain with this number | -| 0B |blockHash |`Data` | The block uniquely identified by this hash. The blockNumber and blockHash properties are mutually exclusive; exactly one of them must be set. | -| 1B |requireCanonical |`boolean` | (optional) Whether or not to throw an error if the block is not in the canonical chain as described below. Only allowed in conjunction with the blockHash tag. Defaults to false. | - - -If the block is not found, the callee SHOULD raise a JSON-RPC error (the recommended error code is `-32001: Resource not found`. If the tag is `blockHash` and `requireCanonical` is `true`, the callee SHOULD additionally raise a JSON-RPC error if the block is not in the canonical chain (the recommended error code is `-32000: Invalid input` and in any case should be different than the error code for the block not found case so that the caller can distinguish the cases). The block-not-found check SHOULD take precedence over the block-is-canonical check, so that if the block is not found the callee raises block-not-found rather than block-not-canonical. diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v01.md b/docs/flashbots-auction/miners/mev-geth-spec/v01.md deleted file mode 100644 index 9cfdc338..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v01.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -title: v0.1 ---- - -## Simple Summary - -Defines the construction and usage of MEV bundles by the miners. Provides specification for custom implementation of required node changes so that MEV bundles can be used correctly. - -## Abstract - -`MevBundles` are stored by the node and the best bundle is added to the block in front of other transactions. `MevBundles` are sorted by their `adjusted gas price`. - -## Motivation - -We believe that without the adoption of neutral, public, open-source infrastructure for permissionless MEV extraction, MEV risks becoming an insiders' game. We commit as an organisation to releasing reference implementations for participation in fair, ethical, and politically neutral MEV extraction. - -## Specification - -The key words `MUST`, `MUST NOT`, `REQUIRED`, `SHALL`, `SHALL NOT`, `SHOULD`, `SHOULD NOT`, `RECOMMENDED`, `MAY`, and `OPTIONAL` in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt). - -### Definitions - -#### `Bundle` -A set of transactions that `MUST` be executed together and `MUST` be executed at the beginning of the block. - -#### `Unit of work` -A `transaction`, a `bundle` or a `block`. - -#### `Subunit` -A discernible `unit of work` that is a part of a bigger `unit of work`. A `transaction` is a `subunit` of a `bundle` or a `block`. A `bundle` is a `subunit` of a `block`. - -#### `Total gas used` -A sum of gas units used by each transaction from the `unit of work`. - -#### `Average gas price` -Sum of (`gas price` * `total gas used`) of all `subunits` divided by the `total gas used` of the unit. - -#### `Direct coinbase payment` -A value of a transaction with a recipient set to be the same as the `coinbase` address. - -#### `Contract coinbase payment` -A payment from a smart contract to the `coinbase` address. - -#### `Profit` -A difference between the balance of the `coinbase` account at the end and at the beginning of the execution of a `unit of work`. We can measure a `transaction profit`, a `bundle profit`, and a `block profit`. - -Balance of the `coinbase` account changes in the following way - -|Unit of work|Balance Change| -|-|-| -|Transaction| `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Bundle | `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Block | `block reward` + `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | - -#### `Adjusted gas price` -`Unit of work` `profit` divided by the `total gas used` by the `unit of work`. - -$$ -s_{v0.1} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tp_T}{\sum_{T\in U}g_T} -$$ - -$s$: adjusted gas price used to sort bundles. -$U$: ordered list of transactions $T$ -$g_{T}$: _gas used_ by transaction $T$. -$p_{T}$: _gas price_ of transaction $T$. -$\Delta_{coinbase}$: coinbase difference from direct payment. - -#### `MevBundle` -An object with four properties: - -|Property| Type|Description| -|-|-|-| -|`transactions`|`Array`|A list of transactions in the bundle. Each transaction is signed and RLP-encoded.| -|`blockNumber`|`uint64`|The exact block number at which the bundle can be executed| -|`minTimestamp`|`uint64`|Minimum block timestamp (inclusive) at which the bundle can be executed| -|`maxTimestamp`|`uint64`|Maximum block timestamp (inclusive) at which the bundle can be executed| - -### Bundle construction - -Bundle `SHOULD` contain transactions with nonces that are following the current nonces of the signing addresses or other transactions preceding them in the same bundle. - -A bundle `MUST` contain at least one transaction. There is no upper limit for the number of transactions in the bundle, however bundles that exceed the block gas limit will always be rejected. - -A bundle `MAY` include a `direct coinbase payment` or a `contract coinbase payment`. Bundles that do not contain such payments may lose comparison when their `profit` is compared with other bundles. - -The `maxTimestamp` value `MUST` be greater or equal the `minTimestamp` value. - -### Accepting bundles from the network - -Node `MUST` provide a way of exposing a JSON RPC endpoint accepting `eth_sendBundle` calls (specified [here](v01-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from `MEV-relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. - -### Bundle eligibility - -Any bundle that is correctly constructed `MUST` have a `blockNumber` field set which specifies in which block it can be included. If the node has already progressed to a later block number then such bundle `MAY` be removed from memory. - -Any bundle that is correctly constructed `MAY` have a `minTimestamp` and/or a `maxTimestamp` field set. Default values for both of these fields are `0` and the meaning of `0` is that any block timestamp value is accepted. When these values are not `0`, then `block.timestamp` is compared with them. If the current `block.timestamp` is greater than the `maxTimestamp` then the bundle `MUST NOT` be included in the block and `MAY` be removed from memory. If the `block.timestamp` is less than `minTimestamp` then the bundle `MUST NOT` be included in the block and `SHOULD NOT` be removed from memory (it awaits future blocks). - -### Block construction - -A block `MUST` either contain one bundle or no bundles. When a bundle is included it `MUST` be the bundle with the highest `adjusted gas price` among eligible bundles. The node `SHOULD` be able to compare a `block profit` in cases when a bundle is included (MEV block) and when no bundles are included (regular block) and choose a block with the highest `profit`. - -A block with a bundle `MUST` place the bundle at the beginning of the block and `MUST NOT` insert any transactions between the bundle transactions. - -### Bundle eviction - -Node `SHOULD` be able to limit the number of bundles kept in memory and apply an algorithm for selecting bundles to be evicted when too many eligible bundles have been received. - -## Rationale - -### At most one MevBundle gets included in the block - -There are two reasons for which multiple bundles in a block may cause problems: - -- two bundles may affect each other's `profit` and so the bundle creator may not be willing to accept a possibility of not being added in the front of the block -- simulating multiple bundle combinations may be very straining for the node infrastructure and introduce excessive latency into the block creation process - -Both of these problems may be addressed in the future versions. - -## Each bundle needs a blockNumber - -This allows specifying bundles to be included in the future blocks (e.g. just after some smart contracts change their state). This cannot be used to ensure a specific parent block / hash. - -## Backwards Compatibility - -This change is not affecting consensus and is fully backwards compatible. - -## Security Considerations - -`MevBundles` that are awaiting future blocks must be stored by the miner's node and it is important to ensure that there is a mechanism to ensure that the storage is limits are not exceeded (whether they are store in memory or persisted). \ No newline at end of file diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v02-rpc.mdx b/docs/flashbots-auction/miners/mev-geth-spec/v02-rpc.mdx deleted file mode 100644 index 56287f14..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v02-rpc.mdx +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: v0.2 RPC ---- - -## eth_sendBundle - -### Description - -Sends a bundle of transactions to the miner. The bundle has to be executed at the beginning of the block (before any other transactions), with bundle transactions executed exactly in the same order as provided in the bundle. During the Flashbots Alpha this is only called by the Flashbots relay. - -| Name | Type | Description | Comment ---------|----------|-----------|----------- -txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | a no-op in the light mode -blockNumber |`Quantity` |Exact block number at which the bundle can be included. |bundle is evicted after the block -minTimestamp |`Quantity` |Minimum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -maxTimestamp |`Quantity` |Maximum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -revertingTxHashes |Array<`Data`> |Array of tx hashes within the bundle that are allowed to cause the EVM execution to revert without preventing the bundle inclusion in a block. - -### Returns - -{`boolean`} - `true` if bundle has been accepted by the node, otherwise `false` - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendBundle", - "params": [ - { - "txs" : [ - "f9014946843b9aca00830493e094a011e5f4ea471ee4341a135bb1a4af368155d7a280b8e40d5f2659000000000000000000000000fdd45a22dd1d606b3782f2119621e928e32743000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000", - "f86e8204d085012a05f200830c350094daf24c20717f428f00d8448d74d67a77f67ceb8287354a6ba7a18000802ea00e411bcb660dd8d47717df89078d2e8160c08e7f11cb7ad0ee935e7436eceb32a013ee00a21b7fa0a9f9c1224d11261648191875d4633aed6003543ea319f12b62" - ], - "blockNumber" : "0x12ab34", - "minTimestamp" : 0, - "minTimestamp" : 0 - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": true -} -``` - -## eth_callBundle - -### Description - -Simulate a bundle of transactions at the top of a block. - -After retrieving the block specified in the `blockNrOrHash` it takes the same `blockhash`, `gasLimit`, `difficulty`, same `timestamp` unless the `blockTimestamp` property is specified, and increases the block number by `1`. `eth_callBundle` will timeout after `5` seconds. - -| Name | Type | Description | -| ---- | ---- | ----------- | -| txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | -| blockNumber | `Quantity` | A hex encoded block number for which this bundle is valid on | -| stateBlockNumber | `Quantity\|string\|Block Identifier` | Either a hex encoded number or a {Block Identifier} for which state to base this simulation on. -| timestamp |`Quantity` |Block timestamp to be used in replacement of the timestamp taken from the parent block. | - -### Returns - -Map<`Data`, "error|value" : `Data`> - a mapping from transaction hashes to execution results with error or output (value) for each of the transactions - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_callBundle", - "params": [ - { - "txs": [ - "f9014946843b9aca00830493e094a011e5f4ea471ee4341a135bb1a4af368155d7a280b8e40d5f2659000000000000000000000000fdd45a22dd1d606b3782f2119621e928e32743000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000", - "f86e8204d085012a05f200830c350094daf24c20717f428f00d8448d74d67a77f67ceb8287354a6ba7a18000802ea00e411bcb660dd8d47717df89078d2e8160c08e7f11cb7ad0ee935e7436eceb32a013ee00a21b7fa0a9f9c1224d11261648191875d4633aed6003543ea319f12b62" - ], - "blockNumber": "0x12ab34", - "stateBlockNumber": "0x12ab33", - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": - { - "0x22b3806fbef9532db4105475222983404783aacd4d865ea5dab76a84aa1a07eb" : { - "value" : "0x0012" - }, - "0x489e3b5493af31d55059f8e296351b267720bc4ba7dc170871c1d789e5541027" : { - "value" : "0xabcd" - } - } -} -``` - ---- - -Below type description can also be found in [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474) - -### `Quantity` - -- A `Quantity` value **MUST** be hex-encoded. -- A `Quantity` value **MUST** be "0x"-prefixed. -- A `Quantity` value **MUST** be expressed using the fewest possible hex digits per byte. -- A `Quantity` value **MUST** express zero as "0x0". - -### `Data` - -- A `Data` value **MUST** be hex-encoded. -- A `Data` value **MUST** be “0x”-prefixed. -- A `Data` value **MUST** be expressed using two hex digits per byte. - -### `Block Identifier` - -Since there is no way to clearly distinguish between a `Data` parameter and a `Quantity` parameter, [EIP-1898](https://eips.ethereum.org/EIPS/eip-1898) provides a format to specify a block either using the block hash or block number. The block identifier is a JSON `object` with the following fields: - -| Position | Name | Type | Description | -| -------- | ---- | ---- | ------------| -| 0A |blockNumber |`Quantity` |The block in the canonical chain with this number | -| 0B |blockHash |`Data` | The block uniquely identified by this hash. The blockNumber and blockHash properties are mutually exclusive; exactly one of them must be set. | -| 1B |requireCanonical |`boolean` | (optional) Whether or not to throw an error if the block is not in the canonical chain as described below. Only allowed in conjunction with the blockHash tag. Defaults to false. | - - -If the block is not found, the callee SHOULD raise a JSON-RPC error (the recommended error code is `-32001: Resource not found`. If the tag is `blockHash` and `requireCanonical` is `true`, the callee SHOULD additionally raise a JSON-RPC error if the block is not in the canonical chain (the recommended error code is `-32000: Invalid input` and in any case should be different than the error code for the block not found case so that the caller can distinguish the cases). The block-not-found check SHOULD take precedence over the block-is-canonical check, so that if the block is not found the callee raises block-not-found rather than block-not-canonical. diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v02.md b/docs/flashbots-auction/miners/mev-geth-spec/v02.md deleted file mode 100644 index 259769cf..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v02.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -title: v0.2 ---- - -## Simple Summary - -Defines the construction and usage of MEV bundles by miners. Provides a specification for custom implementations of the required node changes so that MEV bundles can be used correctly. - -## Abstract - -`MEV bundles` are stored by the node and the bundles that are providing extra profit for miners are added to the block in front of other transactions. - -## Motivation - -We believe that without the adoption of neutral, public, open-source infrastructure for permissionless MEV extraction, MEV risks becoming an insiders' game. We commit as an organisation to releasing reference implementations for participation in fair, ethical, and politically neutral MEV extraction. - -## Specification - -The key words `MUST`, `MUST NOT`, `REQUIRED`, `SHALL`, `SHALL NOT`, `SHOULD`, `SHOULD NOT`, `RECOMMENDED`, `MAY`, and `OPTIONAL` in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt). - -### Miner Configuration - -Miner `MUST` accept the following configuration options: -* miner.maxmergedbundles (int) - max number of `MEV bundles` to be included within a single block - -Miner `MAY` accept the following configuration options: -* (optional) miner.strictprofitswitch (int) - time in miliseconds to wait for a non-MEV (vanilla) block construction before selecting any of the `MEV blocks`. If value is zero then no waiting is necessary. - -### Definitions - -#### `Relay` - -An external system delivering `MEV bundles` to the node. Relay provides protection against DoS attacks. - -#### `MEV bundle` or `bundle` - -A list of transactions that `MUST` be executed together and in the same order as provided in the bundle, `MUST` be executed before any non-bundle transactions and only after other bundles that have a higher `bundle adjusted gas price`. - -Transactions in the bundle `MUST` execute without failure (return status 1 on transaction receipts) unless their hashes are included in the `revertingTxHashes` list. - -When representing a bundle in communication between the `relay` and the node we use an object with the following properties: - -|Property| Type|Description| -|-|-|-| -|`txs`|`Array`|A list of transactions in the bundle. Each transaction is signed and RLP-encoded.| -|`blockNumber`|`uint64`|The exact block number at which the bundle can be executed| -|`minTimestamp`|`uint64`|Minimum block timestamp (inclusive) at which the bundle can be executed| -|`maxTimestamp`|`uint64`|Maximum block timestamp (inclusive) at which the bundle can be executed| -|`revertingTxHashes`|`Array`|List of hashes of transactions that are allowed to return status 0 on transaction receipts| - -#### `MEV block` - -A block containing more than zero 'MEV bundles'. - -Whenever we say that a block contains a `bundle` we mean that the block includes all transactions of that bundle in the same order as in the `bundle`. - -#### `Unit of work` -A `transaction`, a `bundle` or a `block`. - -#### `Subunit` -A discernible `unit of work` that is a part of a bigger `unit of work`. A `transaction` is a `subunit` of a `bundle` or a `block`. A `bundle` is a `subunit` of a `block`. - -#### `Total gas used` -The sum of gas units used by each transaction from the `unit of work`. - -#### `Average gas price` -For a transaction it is equivalent to the transaction gas price and for other `units of work` it is a sum of (`average gas price` * `total gas used`) of all `subunits` divided by the `total gas used` by the unit. - -#### `Direct coinbase payment` -The value of a transaction with a recipient set to be the same as the `coinbase` address. - -#### `Contract coinbase payment` -A payment from a smart contract to the `coinbase` address. - -#### `Coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Eligible coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Gas fee payment` -An `average gas price` * `total gas used` within the `unit of work`. - -#### `Eligible gas fee payment` -A `gas fee payment` excluding `gas fee payments` from transactions that can be spotted by the miner in the publicly visible transaction pool. - -#### `Bundle scoring profit` -A sum of all `eligible coinbase payments` and `eligible gas payments` of a `bundle`. - -#### `Profit` -A difference between the balance of the `coinbase` account at the end and at the beginning of the execution of a `unit of work`. We can measure a `transaction profit`, a `bundle profit`, and a `block profit`. - -Balance of the `coinbase` account changes in the following way - -|Unit of work|Balance Change| -|-|-| -|Transaction| `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Bundle | `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Block | `block reward` + `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | - -#### `Adjusted gas price` -`Unit of work` `profit` divided by the `total gas used` by the `unit of work`. - -#### `Bundle adjusted gas price` -`Bundle scoring profit` divided by the `total gas used` by the `bundle`. - -$$ -s_{v0.2} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tp_T - \sum_{T\in M \cap U}g_Tp_T}{\sum_{T\in U}g_T} -$$ - -$s$: bundle $U$ _score_ used to sort bundles. -$U$: ordered list of transactions $T$ in a bundle. -$M$: set of transactions $T$ in the mempool. -$g_{T}$: _gas used_ by transaction $T$. -$p_{T}$: _gas price_ of transaction $T$. -$\Delta_{coinbase}$: coinbase difference from direct payment. - -### Bundle construction - -A bundle `SHOULD` contain transactions with nonces that are following the current nonces of the signing addresses or other transactions preceding them in the same bundle. - -A bundle `MUST` contain at least one transaction. There is no upper limit for the number of transactions in the bundle, however bundles that exceed the block gas limit will always be rejected. - -A bundle `MAY` include `eligible coinbase payments`. Bundles that do not contain such payments may be discarded when their `bundle adjusted gas price` is compared with other bundles. - -The `maxTimestamp` value `MUST` be greater or equal the `minTimestamp` value. - -### Accepting bundles from the network - -#### JSON RPC - -Node `MUST` provide a way of exposing a JSON RPC endpoint accepting `eth_sendBundle` calls (specified [here](v02-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from the `relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. - -### Bundle eligibility - -Any bundle that is correctly constructed `MUST` have a `blockNumber` field set which specifies in which block it can be included. If the node has already progressed to a later block number then such bundle `MAY` be removed from memory. - -Any bundle that is correctly constructed `MAY` have a `minTimestamp` and/or a `maxTimestamp` field set. Default values for both of these fields are `0` and the meaning of `0` is that any block timestamp value is accepted. When these values are not `0`, then `block.timestamp` is compared with them. If the current `block.timestamp` is greater than the `maxTimestamp` then the bundle `MUST NOT` be included in the block and `MAY` be removed from memory. If the `block.timestamp` is less than `minTimestamp` then the bundle `MUST NOT` be included in the block and `SHOULD NOT` be removed from memory (it awaits future blocks). - -### Block construction - -`MEV bundles` `MUST` be sorted by their `bundle adjusted gas price` first and then one by one added to the block as long as there is any gas left in the block and the number of bundles added is less or equal the `MaxMergedBundles` parameter. The remaining block gas `SHOULD` be used for non-MEV transactions. - -Block `MUST` contain between 0 and `MaxMergedBundles` bundles. - -A block with bundles `MUST` place the bundles at the beginning of the block and `MUST NOT` insert any transactions between the bundles or bundle transactions. - -When constructing the block the node should reject any bundle that has a reverting transaction unless its hash is included in the `RevertingTxHashes` list of the bundle object. - -When constructing the block each next bundle added after the first bundle needs to generate at least 99% of the `bundle adjusted gas price` from the time of the sorting (the first bundle will naturally provide 100% of this value). - -The node `SHOULD` be able to compare the `block profit` for each number of bundles between 0 and `MaxMergedBundles` and choose a block with the highest `profit`, e.g. if `MaxMergedBundles` is 3 then the node `SHOULD` build 4 different blocks - with the maximum of respectively 0, 1, 2, and 3 bundles and choose the one with the highest `profit`. - -### Bundle eviction - -Node `SHOULD` be able to limit the number of bundles kept in memory and apply an algorithm for selecting bundles to be evicted when too many eligible bundles have been received. - -## Rationale - -### Naive bundle merging - -The bundle merging process is not necessarily picking the most profitable combination of bundles but only the best guess achievable without degrading latency. The first bundle included is always the bundle with the highest `bundle adjusted gas price` - -### Using bundle adjusted gas price instead of adjusted gas price - -The `bundle adjusted gas price` is used to prevent bundle creators from artificially increasing the `adjusted gas price` by adding unrelated high gas price transactions from the publicly visible transaction pool. - -### Each bundle needs a blockNumber - -This allows specifying bundles to be included in the future blocks (e.g. just after some smart contracts change their state). This cannot be used to ensure a specific parent block / hash. - -## Future Considerations - -### Full block submission - -A proposal to allow MEV-Geth accepting fully constructed blocks as well as bundles is considered for inclusion in next versions. - -## Backwards Compatibility - -This change is not affecting consensus and is fully compatible with Ethereum specification. - -Bundle formats are not backwards compatible and the v0.2 bundles would be rejected by v0.1 MEV clients. - -## Security Considerations - -The node should ensure that `MEV bundles` that are awaiting future blocks are evicted when at risk of reaching the storage limits (memory or persistent storage). \ No newline at end of file diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v03-rpc.mdx b/docs/flashbots-auction/miners/mev-geth-spec/v03-rpc.mdx deleted file mode 100644 index 1f504921..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v03-rpc.mdx +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: v0.3 RPC ---- - -## eth_sendBundle - -### Description - -Sends a bundle of transactions to the miner. The bundle has to be executed at the beginning of the block (before any other transactions), with bundle transactions executed exactly in the same order as provided in the bundle. During the Flashbots Alpha this is only called by the Flashbots relay. - -| Name | Type | Description | Comment ---------|----------|-----------|----------- -txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | a no-op in the light mode -blockNumber |`Quantity` |Exact block number at which the bundle can be included. |bundle is evicted after the block -minTimestamp |`Quantity` |Minimum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -maxTimestamp |`Quantity` |Maximum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -revertingTxHashes |Array<`Data`> |Array of tx hashes within the bundle that are allowed to cause the EVM execution to revert without preventing the bundle inclusion in a block. - -### Returns - -{`boolean`} - `true` if bundle has been accepted by the node, otherwise `false` - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendBundle", - "params": [ - { - "txs" : [ - "f9014946843b9aca00830493e094a011e5f4ea471ee4341a135bb1a4af368155d7a280b8e40d5f2659000000000000000000000000fdd45a22dd1d606b3782f2119621e928e32743000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000", - "f86e8204d085012a05f200830c350094daf24c20717f428f00d8448d74d67a77f67ceb8287354a6ba7a18000802ea00e411bcb660dd8d47717df89078d2e8160c08e7f11cb7ad0ee935e7436eceb32a013ee00a21b7fa0a9f9c1224d11261648191875d4633aed6003543ea319f12b62" - ], - "blockNumber" : "0x12ab34", - "minTimestamp" : 0, - "maxTimestamp" : 0 - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": true -} -``` - -## eth_callBundle - -### Description - -Simulate a bundle of transactions at the top of a block. - -After retrieving the block specified in the `blockNrOrHash` it takes the same `blockhash`, `gasLimit`, `difficulty`, same `timestamp` unless the `blockTimestamp` property is specified, and increases the block number by `1`. `eth_callBundle` will timeout after `5` seconds. - -| Name | Type | Description | -| ---- | ---- | ----------- | -| txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | -| blockNumber | `Quantity` | A hex encoded block number for which this bundle is valid on | -| stateBlockNumber | `Quantity\|string\|Block Identifier` | Either a hex encoded number or a {Block Identifier} for which state to base this simulation on. -| timestamp |`Quantity` |Block timestamp to be used in replacement of the timestamp taken from the parent block. | - -### Returns - -Map<`Data`, "error|value" : `Data`> - a mapping from transaction hashes to execution results with error or output (value) for each of the transactions - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_callBundle", - "params": [ - { - "txs": [ - "f9014946843b9aca00830493e094a011e5f4ea471ee4341a135bb1a4af368155d7a280b8e40d5f2659000000000000000000000000fdd45a22dd1d606b3782f2119621e928e32743000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000", - "f86e8204d085012a05f200830c350094daf24c20717f428f00d8448d74d67a77f67ceb8287354a6ba7a18000802ea00e411bcb660dd8d47717df89078d2e8160c08e7f11cb7ad0ee935e7436eceb32a013ee00a21b7fa0a9f9c1224d11261648191875d4633aed6003543ea319f12b62" - ], - "blockNumber": "0x12ab34", - "stateBlockNumber": "0x12ab33", - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": - { - "0x22b3806fbef9532db4105475222983404783aacd4d865ea5dab76a84aa1a07eb" : { - "value" : "0x0012" - }, - "0x489e3b5493af31d55059f8e296351b267720bc4ba7dc170871c1d789e5541027" : { - "value" : "0xabcd" - } - } -} -``` - ---- - -Below type description can also be found in [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474) - -### `Quantity` - -- A `Quantity` value **MUST** be hex-encoded. -- A `Quantity` value **MUST** be "0x"-prefixed. -- A `Quantity` value **MUST** be expressed using the fewest possible hex digits per byte. -- A `Quantity` value **MUST** express zero as "0x0". - -### `Data` - -- A `Data` value **MUST** be hex-encoded. -- A `Data` value **MUST** be “0x”-prefixed. -- A `Data` value **MUST** be expressed using two hex digits per byte. - -### `Block Identifier` - -Since there is no way to clearly distinguish between a `Data` parameter and a `Quantity` parameter, [EIP-1898](https://eips.ethereum.org/EIPS/eip-1898) provides a format to specify a block either using the block hash or block number. The block identifier is a JSON `object` with the following fields: - -| Position | Name | Type | Description | -| -------- | ---- | ---- | ------------| -| 0A |blockNumber |`Quantity` |The block in the canonical chain with this number | -| 0B |blockHash |`Data` | The block uniquely identified by this hash. The blockNumber and blockHash properties are mutually exclusive; exactly one of them must be set. | -| 1B |requireCanonical |`boolean` | (optional) Whether or not to throw an error if the block is not in the canonical chain as described below. Only allowed in conjunction with the blockHash tag. Defaults to false. | - - -If the block is not found, the callee SHOULD raise a JSON-RPC error (the recommended error code is `-32001: Resource not found`. If the tag is `blockHash` and `requireCanonical` is `true`, the callee SHOULD additionally raise a JSON-RPC error if the block is not in the canonical chain (the recommended error code is `-32000: Invalid input` and in any case should be different than the error code for the block not found case so that the caller can distinguish the cases). The block-not-found check SHOULD take precedence over the block-is-canonical check, so that if the block is not found the callee raises block-not-found rather than block-not-canonical. diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v03.md b/docs/flashbots-auction/miners/mev-geth-spec/v03.md deleted file mode 100644 index 95969265..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v03.md +++ /dev/null @@ -1,188 +0,0 @@ ---- -title: v0.3 ---- - -## Simple Summary - -Defines the construction and usage of MEV bundles by miners. Provides a specification for custom implementations of the required node changes so that MEV bundles can be used correctly. - -## Abstract - -`MEV bundles` are stored by the node and the bundles that are providing extra profit for miners are added to the block in front of other transactions. - -## Motivation - -We believe that without the adoption of neutral, public, open-source infrastructure for permissionless MEV extraction, MEV risks becoming an insiders' game. We commit as an organisation to releasing reference implementations for participation in fair, ethical, and politically neutral MEV extraction. - -## Specification - -The key words `MUST`, `MUST NOT`, `REQUIRED`, `SHALL`, `SHALL NOT`, `SHOULD`, `SHOULD NOT`, `RECOMMENDED`, `MAY`, and `OPTIONAL` in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt). - -### Miner Configuration - -Miner `MUST` accept the following configuration options: -* miner.maxmergedbundles (int) - max number of `MEV bundles` to be included within a single block - -### Definitions - -#### `Relay` - -An external system delivering `MEV bundles` to the node. Relay provides protection against DoS attacks. - -#### `MEV bundle` or `bundle` - -A list of transactions that `MUST` be executed together and in the same order as provided in the bundle, `MUST` be executed before any non-bundle transactions and only after other bundles that have a higher `bundle adjusted gas price`. - -Transactions in the bundle `MUST` execute without failure (return status 1 on transaction receipts) unless their hashes are included in the `revertingTxHashes` list. - -When representing a bundle in communication between the `relay` and the node we use an object with the following properties: - -|Property| Type|Description| -|-|-|-| -|`txs`|`Array`|A list of transactions in the bundle. Each transaction is signed and RLP-encoded.| -|`blockNumber`|`uint64`|The exact block number at which the bundle can be executed| -|`minTimestamp`|`uint64`|Minimum block timestamp (inclusive) at which the bundle can be executed| -|`maxTimestamp`|`uint64`|Maximum block timestamp (inclusive) at which the bundle can be executed| -|`revertingTxHashes`|`Array`|List of hashes of transactions that are allowed to return status 0 on transaction receipts| - -#### `MEV block` - -A block containing more than zero 'MEV bundles'. - -Whenever we say that a block contains a `bundle` we mean that the block includes all transactions of that bundle in the same order as in the `bundle`. - -#### `Unit of work` -A `transaction`, a `bundle` or a `block`. - -#### `Subunit` -A discernible `unit of work` that is a part of a bigger `unit of work`. A `transaction` is a `subunit` of a `bundle` or a `block`. A `bundle` is a `subunit` of a `block`. - -#### `Total gas used` -The sum of gas units used by each transaction from the `unit of work`. - -#### `Average gas price` -For a transaction it is equivalent to the transaction _minerFee := Min(feeCapPerGas - BASEFEE, priorityFeePerGas)_ - and for other `units of work` it is a sum of (`average gas price` * `total gas used`) of all `subunits` divided by the `total gas used` by the unit. - -#### `Direct coinbase payment` -The value of a transaction with a recipient set to be the same as the `coinbase` address. - -#### `Contract coinbase payment` -A payment from a smart contract to the `coinbase` address. - -#### `Coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Eligible coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Gas fee payment` -An `average gas price` * `total gas used` within the `unit of work`. - -#### `Eligible gas fee payment` -A `gas fee payment` excluding `gas fee payments` from transactions that can be spotted by the miner in the publicly visible transaction pool. - -#### `Bundle scoring profit` -A sum of all `eligible coinbase payments` and `eligible gas payments` of a `bundle`. - -#### `Profit` -A difference between the balance of the `coinbase` account at the end and at the beginning of the execution of a `unit of work`. We can measure a `transaction profit`, a `bundle profit`, and a `block profit`. - -Balance of the `coinbase` account changes in the following way - -|Unit of work|Balance Change| -|-|-| -|Transaction| `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Bundle | `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Block | `block reward` + `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | - -#### `Adjusted gas price` -`Unit of work` `profit` divided by the `total gas used` by the `unit of work`. - -#### `Bundle adjusted gas price` -`Bundle scoring profit` divided by the `total gas used` by the `bundle`. - -$$ -s_{v0.3} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tm_T - \sum_{T\in M \cap U}g_Tm_T}{\sum_{T\in U}g_T} -$$ - -$s$: bundle $U$ _score_ used to sort bundles. -$U$: ordered list of transactions $T$ in a bundle. -$M$: set of transactions $T$ in the mempool. -$g_{T}$: _gas used_ by transaction $T$. -$c_{T}$: _fee cap per gas_ of transaction $T$. -$\delta_T$: _priority fee per gas_ of transaction $T$. -$e_{T}$: _effective fee per gas_ of transaction $T$ equal $\min$($c_{T}$, BASEFEE + $\delta_T$). -$m_{T}$: _miner fee per gas_ of transaction $T$ equal $e_{T}$ - BASEFEE. -$\Delta_{coinbase}$: coinbase difference from direct payment. - -### Bundle construction - -A bundle `SHOULD` contain transactions with nonces that are following the current nonces of the signing addresses or other transactions preceding them in the same bundle. - -A bundle `MUST` contain at least one transaction. There is no upper limit for the number of transactions in the bundle, however bundles that exceed the block gas limit will always be rejected. - -A bundle `MAY` include `eligible coinbase payments`. Bundles that do not contain such payments may be discarded when their `bundle adjusted gas price` is compared with other bundles. - -The `maxTimestamp` value `MUST` be greater or equal the `minTimestamp` value. - -### Accepting bundles from the network - -#### JSON RPC - -Node `MUST` provide a way of exposing a JSON RPC endpoint accepting `eth_sendBundle` calls (specified [here](v03-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from the `relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. - -### Bundle eligibility - -Any bundle that is correctly constructed `MUST` have a `blockNumber` field set which specifies in which block it can be included. If the node has already progressed to a later block number then such bundle `MAY` be removed from memory. - -Each transaction in the bundle `MUST` have _maxFeePerGas_ equal or greater than _block.BASEFEE_ + _1 GWei_ to be selected for the block. - -Any bundle that is correctly constructed `MAY` have a `minTimestamp` and/or a `maxTimestamp` field set. Default values for both of these fields are `0` and the meaning of `0` is that any block timestamp value is accepted. When these values are not `0`, then `block.timestamp` is compared with them. If the current `block.timestamp` is greater than the `maxTimestamp` then the bundle `MUST NOT` be included in the block and `MAY` be removed from memory. If the `block.timestamp` is less than `minTimestamp` then the bundle `MUST NOT` be included in the block and `SHOULD NOT` be removed from memory (it awaits future blocks). - -### Block construction - -`MEV bundles` `MUST` be sorted by their `bundle adjusted gas price` first and then one by one added to the block as long as there is any gas left in the block and the number of bundles added is less or equal the `MaxMergedBundles` parameter. The remaining block gas `SHOULD` be used for non-MEV transactions. - -When constructing the block each next bundle added after the first bundle `MUST` generate at least 99% of the `bundle adjusted gas price` from the time of the sorting (the first bundle will naturally provide 100% of this value). - -Block `MUST` contain between 0 and `MaxMergedBundles` bundles. - -A block with bundles `MUST` place the bundles at the beginning of the block and `MUST NOT` insert any transactions between the bundles or bundle transactions. - -When constructing the block the node should reject any bundle that has a reverting transaction unless its hash is included in the `RevertingTxHashes` list of the bundle object. - -The node `SHOULD` be able to compare the `block profit` for each number of bundles between 0 and `MaxMergedBundles` and choose a block with the highest `profit`, e.g. if `MaxMergedBundles` is 3 then the node `SHOULD` build 4 different blocks - with the maximum of respectively 0, 1, 2, and 3 bundles and choose the one with the highest `profit`. - -### Bundle eviction - -Node `SHOULD` be able to limit the number of bundles kept in memory and apply an algorithm for selecting bundles to be evicted when too many eligible bundles have been received. - -## Rationale - -### Naive bundle merging - -The bundle merging process is not necessarily picking the most profitable combination of bundles but only the best guess achievable without degrading latency. The first bundle included is always the bundle with the highest `bundle adjusted gas price` - -### Using bundle adjusted gas price instead of adjusted gas price - -The `bundle adjusted gas price` is used to prevent bundle creators from artificially increasing the `adjusted gas price` by adding unrelated high gas price transactions from the publicly visible transaction pool. - -### Each bundle needs a blockNumber - -This allows specifying bundles to be included in the future blocks (e.g. just after some smart contracts change their state). This cannot be used to ensure a specific parent block / hash. - -## Future Considerations - -### Full block submission - -A proposal to allow MEV-Geth accepting fully constructed blocks as well as bundles is considered for inclusion in next versions. - -## Backwards Compatibility - -This change is not affecting consensus and is fully compatible with Ethereum specification. - -Bundle formats are not backwards compatible and the v0.2 bundles would be rejected by v0.1 MEV clients. - -## Security Considerations - -The node should ensure that `MEV bundles` that are awaiting future blocks are evicted when at risk of reaching the storage limits (memory or persistent storage). \ No newline at end of file diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v04-rpc.mdx b/docs/flashbots-auction/miners/mev-geth-spec/v04-rpc.mdx deleted file mode 100644 index 2c1f6fa8..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v04-rpc.mdx +++ /dev/null @@ -1,209 +0,0 @@ ---- -title: v0.4 RPC ---- - -## eth_sendBundle - -### Description - -Sends a bundle of transactions to the miner. The bundle has to be executed at the beginning of the block (before any other transactions), with bundle transactions executed exactly in the same order as provided in the bundle. During the Flashbots Alpha this is only called by the Flashbots relay. - -| Name | Type | Description | Comment ---------|----------|-----------|----------- -txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | a no-op in the light mode -blockNumber |`Quantity` |Exact block number at which the bundle can be included. |bundle is evicted after the block -minTimestamp |`Quantity` |Minimum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -maxTimestamp |`Quantity` |Maximum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -revertingTxHashes |Array<`Data`> |Array of tx hashes within the bundle that are allowed to cause the EVM execution to revert without preventing the bundle inclusion in a block. - -### Returns - -{`boolean`} - `true` if bundle has been accepted by the node, otherwise `false` - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendBundle", - "params": [ - { - "txs" : [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878", - "0x02f8b30181b28502cb417800853a352944008307a12094d5281bb2d1ee94866b03a0fccdd4e900c8cb509180b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a042f32acc8631c8c1c81d3d77a637cdab162477077d5041285ea7d73313d6b02ca07b18b432f4921795f84916b3c9398e2fd65580e372b9fa7e018e543ffbc00375" - ], - "blockNumber" : "0xce7b22", - "minTimestamp" : 0, - "minTimestamp" : 0, - "revertingTxHashes": [] - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": true -} -``` - -## eth_sendMegabundle - -### Description - -Sends a megabundle to the miner. The megabundle has to be executed at the beginning of the block (before any other transactions), with bundle transactions executed exactly in the same order as provided in the bundle. Can only be called by a relay listed in the `miner.trustedrelays` config. - -| Name | Type | Description | Comment ---------|----------|-----------|----------- -txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | a no-op in the light mode -blockNumber |`Quantity` |Exact block number at which the bundle can be included. |bundle is evicted after the block -minTimestamp |`Quantity` |Minimum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -maxTimestamp |`Quantity` |Maximum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -revertingTxHashes |Array<`Data`> |Array of tx hashes within the bundle that are allowed to cause the EVM execution to revert without preventing the bundle inclusion in a block. -relaySignature |Array<`Data`> |An secp256k1 signature signed with an address from the `miner.trustedrelays`. Message signed is a Keccak hash of RLP serialized sequence that contains the following items: array of txs (a sequence of byte arrays representing RLP serialized txs); minTimestamp serialized as an int256, like in the devp2p specification; maxTimestamp serialized as an int256, like in the devp2p specification; revertingTxHashes serialized as an array of byte arrays. -### Returns - -{`boolean`} - `true` if megabundle has been accepted by the node, otherwise `false` - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendMegabundle", - "params": [ - { - "txs" : [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878", - "0x02f8b30181b28502cb417800853a352944008307a12094d5281bb2d1ee94866b03a0fccdd4e900c8cb509180b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a042f32acc8631c8c1c81d3d77a637cdab162477077d5041285ea7d73313d6b02ca07b18b432f4921795f84916b3c9398e2fd65580e372b9fa7e018e543ffbc00375" - ], - "blockNumber" : "0xce7b22", - "minTimestamp" : 0, - "minTimestamp" : 0, - "revertingTxHashes": [], - "relaySignature" : "0x2a115a51434b6f326b99bf4eefa1226f9eb88241f140545bf2d63c688eb57e9b07c5c3bb15340ecbdcdffd642c0995024bffa397cd313ec1f29c1c331e71187d1b", - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": true -} -``` - -## eth_callBundle - -### Description - -Simulate a bundle of transactions at the top of a block. - -After retrieving the block specified in the `blockNrOrHash` it takes the same `blockhash`, `gasLimit`, `difficulty`, same `timestamp` unless the `blockTimestamp` property is specified, and increases the block number by `1`. `eth_callBundle` will timeout after `5` seconds. - -| Name | Type | Description | -| ---- | ---- | ----------- | -| txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | -| blockNumber | `Quantity` | A hex encoded block number for which this bundle is valid on | -| stateBlockNumber | `Quantity\|string\|Block Identifier` | Either a hex encoded number or a {Block Identifier} for which state to base this simulation on. -| timestamp |`Quantity` |Block timestamp to be used in replacement of the timestamp taken from the parent block. | - -### Returns - -Map<`Data`, "error|value" : `Data`> - a mapping from transaction hashes to execution results with error or output (value) for each of the transactions - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_callBundle", - "params": [ - { - "txs": [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878", - "0x02f8b30181b28502cb417800853a352944008307a12094d5281bb2d1ee94866b03a0fccdd4e900c8cb509180b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a042f32acc8631c8c1c81d3d77a637cdab162477077d5041285ea7d73313d6b02ca07b18b432f4921795f84916b3c9398e2fd65580e372b9fa7e018e543ffbc00375" - ], - "blockNumber": "0xce7b22", - "stateBlockNumber": "0xce7b21" - } - ] -}' - -# Response -{ - "jsonrpc": "2.0", - "id": 1337, - "result": { - "bundleGasPrice": "12000000000", - "bundleHash": "0xa1433fce883764809a94a5320e4557102f5a3fdd98dabd8cd48773b0eca00666", - "coinbaseDiff": "707448000000000", - "ethSentToCoinbase": "0", - "gasFees": "707448000000000", - "results": [ - { - "coinbaseDiff": "354300000000000", - "ethSentToCoinbase": "0", - "fromAddress": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - "gasFees": "354300000000000", - "gasPrice": "12000000000", - "gasUsed": 29525, - "toAddress": "0xB893A8049f250b57eFA8C62D51527a22404D7c9A", - "txHash": "0x2425790f3031b66981e091cf96e2d29bdd12f47b334557462a0d482b2f057490", - "value": "0x0000000000000000000000000000000000000000000000000000000000000001" - }, - { - "coinbaseDiff": "353148000000000", - "ethSentToCoinbase": "0", - "fromAddress": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - "gasFees": "353148000000000", - "gasPrice": "12000000000", - "gasUsed": 29429, - "toAddress": "0xd5281BB2d1eE94866B03A0fcCDd4e900c8Cb5091", - "txHash": "0xf130358842db89e12d17fe1b35556adbe66497764921a92fda83571d8a2dcc72", - "value": "0x0000000000000000000000000000000000000000000000000000000000000001" - } - ], - "stateBlockNumber": 13531937, - "totalGasUsed": 58954 - } -} -``` - ---- - -Below type description can also be found in [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474) - -### `Quantity` - -- A `Quantity` value **MUST** be hex-encoded. -- A `Quantity` value **MUST** be "0x"-prefixed. -- A `Quantity` value **MUST** be expressed using the fewest possible hex digits per byte. -- A `Quantity` value **MUST** express zero as "0x0". - -### `Data` - -- A `Data` value **MUST** be hex-encoded. -- A `Data` value **MUST** be “0x”-prefixed. -- A `Data` value **MUST** be expressed using two hex digits per byte. - -### `Block Identifier` - -Since there is no way to clearly distinguish between a `Data` parameter and a `Quantity` parameter, [EIP-1898](https://eips.ethereum.org/EIPS/eip-1898) provides a format to specify a block either using the block hash or block number. The block identifier is a JSON `object` with the following fields: - -| Position | Name | Type | Description | -| -------- | ---- | ---- | ------------| -| 0A |blockNumber |`Quantity` |The block in the canonical chain with this number | -| 0B |blockHash |`Data` | The block uniquely identified by this hash. The blockNumber and blockHash properties are mutually exclusive; exactly one of them must be set. | -| 1B |requireCanonical |`boolean` | (optional) Whether or not to throw an error if the block is not in the canonical chain as described below. Only allowed in conjunction with the blockHash tag. Defaults to false. | - - -If the block is not found, the callee SHOULD raise a JSON-RPC error (the recommended error code is `-32001: Resource not found`. If the tag is `blockHash` and `requireCanonical` is `true`, the callee SHOULD additionally raise a JSON-RPC error if the block is not in the canonical chain (the recommended error code is `-32000: Invalid input` and in any case should be different than the error code for the block not found case so that the caller can distinguish the cases). The block-not-found check SHOULD take precedence over the block-is-canonical check, so that if the block is not found the callee raises block-not-found rather than block-not-canonical. diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v04.md b/docs/flashbots-auction/miners/mev-geth-spec/v04.md deleted file mode 100644 index fbcc9ac3..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v04.md +++ /dev/null @@ -1,211 +0,0 @@ ---- -title: v0.4 ---- - -## Simple Summary - -Defines the construction and usage of MEV bundles by miners. Provides a specification for custom implementations of the required node changes so that MEV bundles can be used correctly. - -## Abstract - -`MEV bundles` are stored by the node and the bundles that are providing extra profit for miners are added to the block in front of other transactions. - -## Motivation - -We believe that without the adoption of neutral, public, open-source infrastructure for permissionless MEV extraction, MEV risks becoming an insiders' game. We commit as an organisation to releasing reference implementations for participation in fair, ethical, and politically neutral MEV extraction. - -## Specification - -The key words `MUST`, `MUST NOT`, `REQUIRED`, `SHALL`, `SHALL NOT`, `SHOULD`, `SHOULD NOT`, `RECOMMENDED`, `MAY`, and `OPTIONAL` in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt). - -### Miner Configuration - -Miner `MUST` accept the following configuration options: -* miner.maxmergedbundles (int) - max number of `MEV bundles` to be included within a single block -* miner.trustedrelays (string) - comma separated, hex encoded Ethereum addresses of trusted relays that the miner will be able to accept megabundles from, being reasonably certain about DDoS safety - -### Definitions - -#### `Relay` - -An external system delivering `MEV bundles` and/or `MEV megabundles` to the node. Relay provides protection against DoS attacks. - -#### `MEV bundle` or `bundle` - -A list of transactions that `MUST` be executed together and in the same order as provided in the bundle, `MUST` be executed before any non-bundle transactions and only after other bundles that have a higher `bundle adjusted gas price`. - -Transactions in the bundle `MUST` execute without failure (return status 1 on transaction receipts) unless their hashes are included in the `revertingTxHashes` list. - -When representing a bundle in communication between the `relay` and the node we use an object with the following properties: - -|Property| Type|Description| -|-|-|-| -|`txs`|`Array`|A list of transactions in the bundle. Each transaction is signed and RLP-encoded.| -|`blockNumber`|`uint64`|The exact block number at which the bundle can be executed| -|`minTimestamp`|`uint64`|Minimum block timestamp (inclusive) at which the bundle can be executed| -|`maxTimestamp`|`uint64`|Maximum block timestamp (inclusive) at which the bundle can be executed| -|`revertingTxHashes`|`Array`|List of hashes of transactions that are allowed to return status 0 on transaction receipts| - -#### `MEV megabundle` or `megabundle` - -A pre-merged set of `bundles` coming from a `relay`. Megabundles are not mixed or merged with normal `MEV bundles` but instead used for a separate block construction. - -When representing a megabundle in communication between the `relay` and the node we use an object with the following properties: - -|Property| Type|Description| -|-|-|-| -|`txs`|`Array`|A list of transactions in the bundle. Each transaction is signed and RLP-encoded.| -|`blockNumber`|`uint64`|The exact block number at which the bundle can be executed| -|`minTimestamp`|`uint64`|Minimum block timestamp (inclusive) at which the bundle can be executed| -|`maxTimestamp`|`uint64`|Maximum block timestamp (inclusive) at which the bundle can be executed| -|`revertingTxHashes`|`Array`|List of hashes of transactions that are allowed to return status 0 on transaction receipts| -|`relaySignature` |`Array`|An secp256k1 signature signed with an address from the `miner.trustedrelays`. Message signed is a Keccak hash of RLP serialized sequence that contains the following items: array of txs (a sequence of byte arrays representing RLP serialized txs); blockNumber serialized as an uint64, minTimestamp serialized as an int256, like in the devp2p specification; maxTimestamp serialized as an int256, like in the devp2p specification; revertingTxHashes serialized as an array of byte arrays. - -#### `MEV block` - -A block containing more than zero `MEV bundles`. - -Whenever we say that a block contains a `bundle` we mean that the block includes all transactions of that bundle in the same order as in the `bundle`. - -#### `Unit of work` -A `transaction`, a `bundle`, `megabundle` or a `block`. - -#### `Subunit` -A discernible `unit of work` that is a part of a bigger `unit of work`. A `transaction` is a `subunit` of a `bundle` or a `block`. A `bundle` is a `subunit` of a `block`. - -#### `Total gas used` -The sum of gas units used by each transaction from the `unit of work`. - -#### `Average gas price` -For a transaction it is equivalent to the transaction _minerFee := Min(feeCapPerGas - BASEFEE, priorityFeePerGas)_ - and for other `units of work` it is a sum of (`average gas price` * `total gas used`) of all `subunits` divided by the `total gas used` by the unit. - -#### `Direct coinbase payment` -The value of a transaction with a recipient set to be the same as the `coinbase` address. - -#### `Contract coinbase payment` -A payment from a smart contract to the `coinbase` address. - -#### `Coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Eligible coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Gas fee payment` -An `average gas price` * `total gas used` within the `unit of work`. - -#### `Eligible gas fee payment` -A `gas fee payment` excluding `gas fee payments` from transactions that can be spotted by the miner in the publicly visible transaction pool. - -#### `Bundle scoring profit` -A sum of all `eligible coinbase payments` and `eligible gas payments` of a `bundle`. - -#### `Profit` -A difference between the balance of the `coinbase` account at the end and at the beginning of the execution of a `unit of work`. We can measure a `transaction profit`, a `bundle profit`, and a `block profit`. - -Balance of the `coinbase` account changes in the following way - -|Unit of work|Balance Change| -|-|-| -|Transaction| `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Bundle | `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Megabundle | `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Block | `block reward` + `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | - -#### `Adjusted gas price` -`Unit of work` `profit` divided by the `total gas used` by the `unit of work`. - -#### `Bundle adjusted gas price` -`Bundle scoring profit` divided by the `total gas used` by the `bundle`. - -$$ -s_{v0.4} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tm_T - \sum_{T\in M \cap U}g_Tm_T}{\sum_{T\in U}g_T} -$$ - -$s$: bundle $U$ _score_ used to sort bundles. -$U$: ordered list of transactions $T$ in a bundle. -$M$: set of transactions $T$ in the mempool. -$g_{T}$: _gas used_ by transaction $T$. -$c_{T}$: _fee cap per gas_ of transaction $T$. -$\delta_T$: _priority fee per gas_ of transaction $T$. -$e_{T}$: _effective fee per gas_ of transaction $T$ equal $\min$($c_{T}$, BASEFEE + $\delta_T$). -$m_{T}$: _miner fee per gas_ of transaction $T$ equal $e_{T}$ - BASEFEE. -$\Delta_{coinbase}$: coinbase difference from direct payment. - -### Bundle construction - -A bundle `SHOULD` contain transactions with nonces that are following the current nonces of the signing addresses or other transactions preceding them in the same bundle. - -A bundle `MUST` contain at least one transaction. There is no upper limit for the number of transactions in the bundle, however bundles that exceed the block gas limit will always be rejected. - -A bundle `MAY` include `eligible coinbase payments`. Bundles that do not contain such payments may be discarded when their `bundle adjusted gas price` is compared with other bundles. - -The `maxTimestamp` value `MUST` be greater or equal the `minTimestamp` value. - -### Accepting bundles from the network - -#### JSON RPC - -Node `MUST` provide a way of exposing a JSON RPC endpoint accepting `eth_sendBundle` calls (specified [here](v04-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from a `relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. - -Node `MUST` provide a way of exposing a JSON RPC endpoint accepting `eth_sendMegabundle` calls (specified [here](v04-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from a `relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. For each relay only the last megabundle `SHOULD` be stored in memory. - -### Bundle eligibility - -Any bundle that is correctly constructed `MUST` have a `blockNumber` field set which specifies in which block it can be included. If the node has already progressed to a later block number then such bundle `MAY` be removed from memory. - -Each transaction in the bundle `MUST` have _maxFeePerGas_ equal or greater than _block.BASEFEE_ + _1 GWei_ to be selected for the block. - -Any bundle that is correctly constructed `MAY` have a `minTimestamp` and/or a `maxTimestamp` field set. Default values for both of these fields are `0` and the meaning of `0` is that any block timestamp value is accepted. When these values are not `0`, then `block.timestamp` is compared with them. If the current `block.timestamp` is greater than the `maxTimestamp` then the bundle `MUST NOT` be included in the block and `MAY` be removed from memory. If the `block.timestamp` is less than `minTimestamp` then the bundle `MUST NOT` be included in the block and `SHOULD NOT` be removed from memory (it awaits future blocks). - -### Block construction - -In order to prevent starvation of less frequently used relays, incoming `MEV megabundles` `MUST` be given a priority value equal to the time in milliseconds since the previous `MEV megabundle` sent by the same relay and redirected to a pool of `MEV megabundle` block producers (called workers in MEV-Geth). Whenever the worker is idle and there are `MEV megabundles` available, a bundle with the highest priority `MUST` be picked for evaluation. Megabundles are never merged with other bundles and can only be combined with transactions from the mempool. - -`MEV bundles` `MUST` be sorted by their `bundle adjusted gas price` first and then one by one added to the block as long as there is any gas left in the block and the number of bundles added is less or equal the `MaxMergedBundles` parameter. The remaining block gas `SHOULD` be used for non-MEV transactions. - -When constructing a block each next bundle added after the first bundle `MUST` generate at least 99% of the `bundle adjusted gas price` from the time of the sorting (the first bundle will naturally provide 100% of this value). - -Block `MUST` contain between 0 and `MaxMergedBundles` bundles. - -A block with bundles `MUST` place the bundles at the beginning of the block and `MUST NOT` insert any transactions between the bundles or bundle transactions. - -When constructing a block the node `MUST` reject any bundle or megabundle that has a reverting transaction unless its hash is included in the `RevertingTxHashes` list of the bundle / megabundle object. - -The node `SHOULD` be able to compare the `block profit` for each number of bundles between 0 and `MaxMergedBundles` and choose a block with the highest `profit`, e.g. if `MaxMergedBundles` is 3 then the node `SHOULD` build 4 different blocks - with the maximum of respectively 0, 1, 2, and 3 bundles and choose the one with the highest `profit`. - -The node `MUST` be able to compare the `block profit` from the best `megabundles` with the `block profit` of otherwise winning block. - -### Bundle eviction - -Node `SHOULD` be able to limit the number of bundles kept in memory and apply an algorithm for selecting bundles to be evicted when too many eligible bundles have been received. - -## Rationale - -### Naive bundle merging - -The bundle merging process is not necessarily picking the most profitable combination of bundles but only the best guess achievable without degrading latency. The first bundle included is always the bundle with the highest `bundle adjusted gas price` - -### Using bundle adjusted gas price instead of adjusted gas price - -The `bundle adjusted gas price` is used to prevent bundle creators from artificially increasing the `adjusted gas price` by adding unrelated high gas price transactions from the publicly visible transaction pool. - -### Each bundle needs a blockNumber - -This allows specifying bundles to be included in the future blocks (e.g. just after some smart contracts change their state). This cannot be used to ensure a specific parent block / hash. - -## Future Considerations - -### Full block submission - -A proposal to allow MEV-Geth accepting fully constructed blocks as well as bundles is considered for inclusion in next versions. - -## Backwards Compatibility - -This change is not affecting consensus and is fully compatible with Ethereum specification. - -Bundle formats are not backwards compatible and the v0.2 bundles would be rejected by v0.1 MEV clients. - -## Security Considerations - -The node `SHOULD` ensure that `MEV bundles` and `megabundles` that are awaiting future blocks are evicted when at risk of reaching the storage limits (memory or persistent storage). diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v05-rpc.mdx b/docs/flashbots-auction/miners/mev-geth-spec/v05-rpc.mdx deleted file mode 100644 index 0ed5025b..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v05-rpc.mdx +++ /dev/null @@ -1,209 +0,0 @@ ---- -title: v0.5 RPC ---- - -## eth_sendBundle - -### Description - -Sends a bundle of transactions to the miner. The bundle has to be executed at the beginning of the block (before any other transactions), with bundle transactions executed exactly in the same order as provided in the bundle. During the Flashbots Alpha this is only called by the Flashbots relay. - -| Name | Type | Description | Comment ---------|----------|-----------|----------- -txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | a no-op in the light mode -blockNumber |`Quantity` |Exact block number at which the bundle can be included. |bundle is evicted after the block -minTimestamp |`Quantity` |Minimum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -maxTimestamp |`Quantity` |Maximum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -revertingTxHashes |Array<`Data`> |Array of tx hashes within the bundle that are allowed to cause the EVM execution to revert without preventing the bundle inclusion in a block. - -### Returns - -{`boolean`} - `true` if bundle has been accepted by the node, otherwise `false` - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendBundle", - "params": [ - { - "txs" : [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878", - "0x02f8b30181b28502cb417800853a352944008307a12094d5281bb2d1ee94866b03a0fccdd4e900c8cb509180b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a042f32acc8631c8c1c81d3d77a637cdab162477077d5041285ea7d73313d6b02ca07b18b432f4921795f84916b3c9398e2fd65580e372b9fa7e018e543ffbc00375" - ], - "blockNumber" : "0xce7b22", - "minTimestamp" : 0, - "minTimestamp" : 0, - "revertingTxHashes": [] - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": true -} -``` - -## eth_sendMegabundle - -### Description - -Sends a megabundle to the miner. The megabundle has to be executed at the beginning of the block (before any other transactions), with bundle transactions executed exactly in the same order as provided in the bundle. Can only be called by a relay listed in the `miner.trustedrelays` config. - -| Name | Type | Description | Comment ---------|----------|-----------|----------- -txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | a no-op in the light mode -blockNumber |`Quantity` |Exact block number at which the bundle can be included. |bundle is evicted after the block -minTimestamp |`Quantity` |Minimum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -maxTimestamp |`Quantity` |Maximum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -revertingTxHashes |Array<`Data`> |Array of tx hashes within the bundle that are allowed to cause the EVM execution to revert without preventing the bundle inclusion in a block. -relaySignature |Array<`Data`> |An secp256k1 signature signed with an address from the `miner.trustedrelays`. Message signed is a Keccak hash of RLP serialized sequence that contains the following items: array of txs (a sequence of byte arrays representing RLP serialized txs); minTimestamp serialized as an int256, like in the devp2p specification; maxTimestamp serialized as an int256, like in the devp2p specification; revertingTxHashes serialized as an array of byte arrays. -### Returns - -{`boolean`} - `true` if megabundle has been accepted by the node, otherwise `false` - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendMegabundle", - "params": [ - { - "txs" : [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878", - "0x02f8b30181b28502cb417800853a352944008307a12094d5281bb2d1ee94866b03a0fccdd4e900c8cb509180b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a042f32acc8631c8c1c81d3d77a637cdab162477077d5041285ea7d73313d6b02ca07b18b432f4921795f84916b3c9398e2fd65580e372b9fa7e018e543ffbc00375" - ], - "blockNumber" : "0xce7b22", - "minTimestamp" : 0, - "minTimestamp" : 0, - "revertingTxHashes": [], - "relaySignature" : "0x2a115a51434b6f326b99bf4eefa1226f9eb88241f140545bf2d63c688eb57e9b07c5c3bb15340ecbdcdffd642c0995024bffa397cd313ec1f29c1c331e71187d1b", - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": true -} -``` - -## eth_callBundle - -### Description - -Simulate a bundle of transactions at the top of a block. - -After retrieving the block specified in the `blockNrOrHash` it takes the same `blockhash`, `gasLimit`, `difficulty`, same `timestamp` unless the `blockTimestamp` property is specified, and increases the block number by `1`. `eth_callBundle` will timeout after `5` seconds. - -| Name | Type | Description | -| ---- | ---- | ----------- | -| txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | -| blockNumber | `Quantity` | A hex encoded block number for which this bundle is valid on | -| stateBlockNumber | `Quantity\|string\|Block Identifier` | Either a hex encoded number or a {Block Identifier} for which state to base this simulation on. -| timestamp |`Quantity` |Block timestamp to be used in replacement of the timestamp taken from the parent block. | - -### Returns - -Map<`Data`, "error|value" : `Data`> - a mapping from transaction hashes to execution results with error or output (value) for each of the transactions - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_callBundle", - "params": [ - { - "txs": [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878", - "0x02f8b30181b28502cb417800853a352944008307a12094d5281bb2d1ee94866b03a0fccdd4e900c8cb509180b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a042f32acc8631c8c1c81d3d77a637cdab162477077d5041285ea7d73313d6b02ca07b18b432f4921795f84916b3c9398e2fd65580e372b9fa7e018e543ffbc00375" - ], - "blockNumber": "0xce7b22", - "stateBlockNumber": "0xce7b21" - } - ] -}' - -# Response -{ - "jsonrpc": "2.0", - "id": 1337, - "result": { - "bundleGasPrice": "12000000000", - "bundleHash": "0xa1433fce883764809a94a5320e4557102f5a3fdd98dabd8cd48773b0eca00666", - "coinbaseDiff": "707448000000000", - "ethSentToCoinbase": "0", - "gasFees": "707448000000000", - "results": [ - { - "coinbaseDiff": "354300000000000", - "ethSentToCoinbase": "0", - "fromAddress": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - "gasFees": "354300000000000", - "gasPrice": "12000000000", - "gasUsed": 29525, - "toAddress": "0xB893A8049f250b57eFA8C62D51527a22404D7c9A", - "txHash": "0x2425790f3031b66981e091cf96e2d29bdd12f47b334557462a0d482b2f057490", - "value": "0x0000000000000000000000000000000000000000000000000000000000000001" - }, - { - "coinbaseDiff": "353148000000000", - "ethSentToCoinbase": "0", - "fromAddress": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - "gasFees": "353148000000000", - "gasPrice": "12000000000", - "gasUsed": 29429, - "toAddress": "0xd5281BB2d1eE94866B03A0fcCDd4e900c8Cb5091", - "txHash": "0xf130358842db89e12d17fe1b35556adbe66497764921a92fda83571d8a2dcc72", - "value": "0x0000000000000000000000000000000000000000000000000000000000000001" - } - ], - "stateBlockNumber": 13531937, - "totalGasUsed": 58954 - } -} -``` - ---- - -Below type description can also be found in [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474) - -### `Quantity` - -- A `Quantity` value **MUST** be hex-encoded. -- A `Quantity` value **MUST** be "0x"-prefixed. -- A `Quantity` value **MUST** be expressed using the fewest possible hex digits per byte. -- A `Quantity` value **MUST** express zero as "0x0". - -### `Data` - -- A `Data` value **MUST** be hex-encoded. -- A `Data` value **MUST** be “0x”-prefixed. -- A `Data` value **MUST** be expressed using two hex digits per byte. - -### `Block Identifier` - -Since there is no way to clearly distinguish between a `Data` parameter and a `Quantity` parameter, [EIP-1898](https://eips.ethereum.org/EIPS/eip-1898) provides a format to specify a block either using the block hash or block number. The block identifier is a JSON `object` with the following fields: - -| Position | Name | Type | Description | -| -------- | ---- | ---- | ------------| -| 0A |blockNumber |`Quantity` |The block in the canonical chain with this number | -| 0B |blockHash |`Data` | The block uniquely identified by this hash. The blockNumber and blockHash properties are mutually exclusive; exactly one of them must be set. | -| 1B |requireCanonical |`boolean` | (optional) Whether or not to throw an error if the block is not in the canonical chain as described below. Only allowed in conjunction with the blockHash tag. Defaults to false. | - - -If the block is not found, the callee SHOULD raise a JSON-RPC error (the recommended error code is `-32001: Resource not found`. If the tag is `blockHash` and `requireCanonical` is `true`, the callee SHOULD additionally raise a JSON-RPC error if the block is not in the canonical chain (the recommended error code is `-32000: Invalid input` and in any case should be different than the error code for the block not found case so that the caller can distinguish the cases). The block-not-found check SHOULD take precedence over the block-is-canonical check, so that if the block is not found the callee raises block-not-found rather than block-not-canonical. diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v05.md b/docs/flashbots-auction/miners/mev-geth-spec/v05.md deleted file mode 100644 index 03d9b511..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v05.md +++ /dev/null @@ -1,216 +0,0 @@ ---- -title: v0.5 ---- -_Note: v0.5 is scheduled for release on Feb 15th, 2022. Please reference the [release plan](/flashbots-auction/releases/alpha-v0.5) for information on upgrading and configuration._ - -## Simple Summary - -Defines the construction and usage of MEV bundles by miners. Provides a specification for custom implementations of the required node changes so that MEV bundles can be used correctly. - -## Abstract - -`MEV bundles` are stored by the node and the bundles that are providing extra profit for miners are added to the block in front of other transactions. - -## Motivation - -We believe that without the adoption of neutral, public, open-source infrastructure for permissionless MEV extraction, MEV risks becoming an insiders' game. We commit as an organisation to releasing reference implementations for participation in fair, ethical, and politically neutral MEV extraction. - -## Specification - -The key words `MUST`, `MUST NOT`, `REQUIRED`, `SHALL`, `SHALL NOT`, `SHOULD`, `SHOULD NOT`, `RECOMMENDED`, `MAY`, and `OPTIONAL` in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt). - -### Miner Configuration - -Miner `MUST` accept the following configuration options: -* miner.maxmergedbundles (int) - max number of `MEV bundles` to be included within a single block -* miner.trustedrelays (string) - comma separated, hex encoded Ethereum addresses of trusted relays that the miner will be able to accept megabundles from, being reasonably certain about DDoS safety - -### Definitions - -#### `Relay` - -An external system delivering `MEV bundles` and/or `MEV megabundles` to the node. Relay provides protection against DoS attacks. - -#### `MEV bundle` or `bundle` - -A list of transactions that `MUST` be executed together and in the same order as provided in the bundle, `MUST` be executed before any non-bundle transactions and only after other bundles that have a higher `bundle adjusted gas price`. - -Transactions in the bundle `MUST` execute without failure (return status 1 on transaction receipts) unless their hashes are included in the `revertingTxHashes` list. - -When representing a bundle in communication between the `relay` and the node we use an object with the following properties: - -|Property| Type|Description| -|-|-|-| -|`txs`|`Array`|A list of transactions in the bundle. Each transaction is signed and RLP-encoded.| -|`blockNumber`|`uint64`|The exact block number at which the bundle can be executed| -|`minTimestamp`|`uint64`|Minimum block timestamp (inclusive) at which the bundle can be executed| -|`maxTimestamp`|`uint64`|Maximum block timestamp (inclusive) at which the bundle can be executed| -|`revertingTxHashes`|`Array`|List of hashes of transactions that are allowed to return status 0 on transaction receipts| - -#### `MEV megabundle` or `megabundle` - -A pre-merged set of `bundles` coming from a `relay`. Megabundles are not mixed or merged with normal `MEV bundles` but instead used for a separate block construction. - -When representing a megabundle in communication between the `relay` and the node we use an object with the following properties: - -|Property| Type|Description| -|-|-|-| -|`txs`|`Array`|A list of transactions in the bundle. Each transaction is signed and RLP-encoded.| -|`blockNumber`|`uint64`|The exact block number at which the bundle can be executed| -|`minTimestamp`|`uint64`|Minimum block timestamp (inclusive) at which the bundle can be executed| -|`maxTimestamp`|`uint64`|Maximum block timestamp (inclusive) at which the bundle can be executed| -|`revertingTxHashes`|`Array`|List of hashes of transactions that are allowed to return status 0 on transaction receipts| -|`relaySignature` |`Array`|An secp256k1 signature signed with an address from the `miner.trustedrelays`. Message signed is a Keccak hash of RLP serialized sequence that contains the following items: array of txs (a sequence of byte arrays representing RLP serialized txs); blockNumber serialized as an uint64, minTimestamp serialized as an int256, like in the devp2p specification; maxTimestamp serialized as an int256, like in the devp2p specification; revertingTxHashes serialized as an array of byte arrays. - -#### `MEV block` - -A block containing more than zero `MEV bundles`. - -Whenever we say that a block contains a `bundle` we mean that the block includes all transactions of that bundle in the same order as in the `bundle`. - -#### `Unit of work` -A `transaction`, a `bundle`, `megabundle` or a `block`. - -#### `Subunit` -A discernible `unit of work` that is a part of a bigger `unit of work`. A `transaction` is a `subunit` of a `bundle` or a `block`. A `bundle` is a `subunit` of a `block`. - -#### `Total gas used` -The sum of gas units used by each transaction from the `unit of work`. - -#### `Average gas price` -For a transaction it is equivalent to the transaction _minerFee := Min(feeCapPerGas - BASEFEE, priorityFeePerGas)_ - and for other `units of work` it is a sum of (`average gas price` * `total gas used`) of all `subunits` divided by the `total gas used` by the unit. - -#### `Direct coinbase payment` -The value of a transaction with a recipient set to be the same as the `coinbase` address. - -#### `Contract coinbase payment` -A payment from a smart contract to the `coinbase` address. - -#### `Coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Eligible coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Gas fee payment` -An `average gas price` * `total gas used` within the `unit of work`. - -#### `Eligible gas fee payment` -A `gas fee payment` excluding `gas fee payments` from transactions that can be spotted by the miner in the publicly visible transaction pool. - -#### `Bundle scoring profit` -A sum of all `eligible coinbase payments` and `eligible gas payments` of a `bundle`. - -#### `Profit` -A difference between the balance of the `coinbase` account at the end and at the beginning of the execution of a `unit of work`. We can measure a `transaction profit`, a `bundle profit`, and a `block profit`. - -Balance of the `coinbase` account changes in the following way - -|Unit of work|Balance Change| -|-|-| -|Transaction| `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Bundle | `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Megabundle | `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Block | `block reward` + `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | - -#### `Adjusted gas price` -`Unit of work` `profit` divided by the `total gas used` by the `unit of work`. - -#### `Bundle adjusted gas price` -`Bundle scoring profit` divided by the `total gas used` by the `bundle`. - -$$ -s_{v0.5} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tm_T - \sum_{T\in M \cap U}g_Tm_T}{\sum_{T\in U}g_T} -$$ - -$s$: bundle $U$ _score_ used to sort bundles. -$U$: ordered list of transactions $T$ in a bundle. -$M$: set of transactions $T$ in the mempool. -$g_{T}$: _gas used_ by transaction $T$. -$c_{T}$: _fee cap per gas_ of transaction $T$. -$\delta_T$: _priority fee per gas_ of transaction $T$. -$e_{T}$: _effective fee per gas_ of transaction $T$ equal $\min$($c_{T}$, BASEFEE + $\delta_T$). -$m_{T}$: _miner fee per gas_ of transaction $T$ equal $e_{T}$ - BASEFEE. -$\Delta_{coinbase}$: coinbase difference from direct payment. - -### Bundle construction - -A bundle `SHOULD` contain transactions with nonces that are following the current nonces of the signing addresses or other transactions preceding them in the same bundle. - -A bundle `MUST` contain at least one transaction. There is no upper limit for the number of transactions in the bundle, however bundles that exceed the block gas limit will always be rejected. - -A bundle `MAY` include `eligible coinbase payments`. Bundles that do not contain such payments may be discarded when their `bundle adjusted gas price` is compared with other bundles. - -The `maxTimestamp` value `MUST` be greater or equal the `minTimestamp` value. - -### Accepting bundles from the network - -#### JSON RPC - -Node `MUST` provide a way of exposing a JSON RPC endpoint accepting `eth_sendBundle` calls (specified [here](v05-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from a `relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. - -Node `MUST` provide a way of exposing a JSON RPC endpoint accepting `eth_sendMegabundle` calls (specified [here](v05-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from a `relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. For each relay only the last megabundle `SHOULD` be stored in memory. - -### Bundle eligibility - -Any bundle that is correctly constructed `MUST` have a `blockNumber` field set which specifies in which block it can be included. If the node has already progressed to a later block number then such bundle `MAY` be removed from memory. - -Each transaction in the bundle `MUST` have _maxFeePerGas_ equal or greater than _block.BASEFEE_ + _1 GWei_ to be selected for the block. - -Any bundle that is correctly constructed `MAY` have a `minTimestamp` and/or a `maxTimestamp` field set. Default values for both of these fields are `0` and the meaning of `0` is that any block timestamp value is accepted. When these values are not `0`, then `block.timestamp` is compared with them. If the current `block.timestamp` is greater than the `maxTimestamp` then the bundle `MUST NOT` be included in the block and `MAY` be removed from memory. If the `block.timestamp` is less than `minTimestamp` then the bundle `MUST NOT` be included in the block and `SHOULD NOT` be removed from memory (it awaits future blocks). - -### Block construction - -In order to prevent starvation of less frequently used relays, incoming `MEV megabundles` `MUST` be given a priority value equal to the time in milliseconds since the previous `MEV megabundle` sent by the same relay and redirected to a pool of `MEV megabundle` block producers (called workers in MEV-Geth). Whenever the worker is idle and there are `MEV megabundles` available, a bundle with the highest priority `MUST` be picked for evaluation. Megabundles are never merged with other bundles and can only be combined with transactions from the mempool. - -When an `MEV megabundle` with higher value than previously arrives - * block construction `MUST` be initated immediately if there is no block being built at the time. - * block construction `MUST` be queued for execution immediately after the current block construction task if a block is being built at the time. - -`MEV bundles` `MUST` be sorted by their `bundle adjusted gas price` first and then one by one added to the block as long as there is any gas left in the block and the number of bundles added is less or equal the `MaxMergedBundles` parameter. The remaining block gas `SHOULD` be used for non-MEV transactions. - -When constructing a block each next bundle added after the first bundle `MUST` generate at least 99% of the `bundle adjusted gas price` from the time of the sorting (the first bundle will naturally provide 100% of this value). - -Block `MUST` contain between 0 and `MaxMergedBundles` bundles. - -A block with bundles `MUST` place the bundles at the beginning of the block and `MUST NOT` insert any transactions between the bundles or bundle transactions. - -When constructing a block the node `MUST` reject any bundle or megabundle that has a reverting transaction unless its hash is included in the `RevertingTxHashes` list of the bundle / megabundle object. - -The node `SHOULD` be able to compare the `block profit` for each number of bundles between 0 and `MaxMergedBundles` and choose a block with the highest `profit`, e.g. if `MaxMergedBundles` is 3 then the node `SHOULD` build 4 different blocks - with the maximum of respectively 0, 1, 2, and 3 bundles and choose the one with the highest `profit`. - -The node `MUST` be able to compare the `block profit` from the best `megabundles` with the `block profit` of otherwise winning block. - -### Bundle eviction - -Node `SHOULD` be able to limit the number of bundles kept in memory and apply an algorithm for selecting bundles to be evicted when too many eligible bundles have been received. - -## Rationale - -### Naive bundle merging - -The bundle merging process is not necessarily picking the most profitable combination of bundles but only the best guess achievable without degrading latency. The first bundle included is always the bundle with the highest `bundle adjusted gas price` - -### Using bundle adjusted gas price instead of adjusted gas price - -The `bundle adjusted gas price` is used to prevent bundle creators from artificially increasing the `adjusted gas price` by adding unrelated high gas price transactions from the publicly visible transaction pool. - -### Each bundle needs a blockNumber - -This allows specifying bundles to be included in the future blocks (e.g. just after some smart contracts change their state). This cannot be used to ensure a specific parent block / hash. - -## Future Considerations - -### Full block submission - -A proposal to allow MEV-Geth accepting fully constructed blocks as well as bundles is considered for inclusion in next versions. - -## Backwards Compatibility - -This change is not affecting consensus and is fully compatible with Ethereum specification. - -Bundle formats are not backwards compatible and the v0.2 bundles would be rejected by v0.1 MEV clients. - -## Security Considerations - -The node `SHOULD` ensure that `MEV bundles` and `megabundles` that are awaiting future blocks are evicted when at risk of reaching the storage limits (memory or persistent storage). diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v06-rpc.mdx b/docs/flashbots-auction/miners/mev-geth-spec/v06-rpc.mdx deleted file mode 100644 index a64d7ad6..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v06-rpc.mdx +++ /dev/null @@ -1,245 +0,0 @@ ---- -title: v0.6 RPC (current) ---- - -## eth_sendBundle - -### Description - -Sends a bundle of transactions to the miner. The bundle has to be executed at the beginning of the block (before any other transactions), with bundle transactions executed exactly in the same order as provided in the bundle. During the Flashbots Alpha this is only called by the Flashbots relay. - -| Name | Type | Description | Comment ---------|----------|-----------|----------- -txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | a no-op in the light mode -blockNumber |`Quantity` |Exact block number at which the bundle can be included. |bundle is evicted after the block -minTimestamp |`Quantity` |Minimum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -maxTimestamp |`Quantity` |Maximum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -revertingTxHashes |Array<`Data`> |Array of tx hashes within the bundle that are allowed to cause the EVM execution to revert without preventing the bundle inclusion in a block. - -### Returns - -{`boolean`} - `true` if bundle has been accepted by the node, otherwise `false` - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendBundle", - "params": [ - { - "txs" : [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878", - "0x02f8b30181b28502cb417800853a352944008307a12094d5281bb2d1ee94866b03a0fccdd4e900c8cb509180b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a042f32acc8631c8c1c81d3d77a637cdab162477077d5041285ea7d73313d6b02ca07b18b432f4921795f84916b3c9398e2fd65580e372b9fa7e018e543ffbc00375" - ], - "blockNumber" : "0xce7b22", - "minTimestamp" : 0, - "minTimestamp" : 0, - "revertingTxHashes": [] - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": true -} -``` - -## eth_sendMegabundle - -### Description - -Sends a megabundle to the miner. The megabundle has to be executed at the beginning of the block (before any other transactions), with bundle transactions executed exactly in the same order as provided in the bundle. Can only be called by a relay listed in the `miner.trustedrelays` config. - -| Name | Type | Description | Comment ---------|----------|-----------|----------- -txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | a no-op in the light mode -blockNumber |`Quantity` |Exact block number at which the bundle can be included. |bundle is evicted after the block -minTimestamp |`Quantity` |Minimum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -maxTimestamp |`Quantity` |Maximum (inclusive) block timestamp at which the bundle can be included. If this value is 0 then any timestamp is acceptable. -revertingTxHashes |Array<`Data`> |Array of tx hashes within the bundle that are allowed to cause the EVM execution to revert without preventing the bundle inclusion in a block. -relaySignature |Array<`Data`> |An secp256k1 signature signed with an address from the `miner.trustedrelays`. Message signed is a Keccak hash of RLP serialized sequence that contains the following items: array of txs (a sequence of byte arrays representing RLP serialized txs); minTimestamp serialized as an int256, like in the devp2p specification; maxTimestamp serialized as an int256, like in the devp2p specification; revertingTxHashes serialized as an array of byte arrays. -### Returns - -{`boolean`} - `true` if megabundle has been accepted by the node, otherwise `false` - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendMegabundle", - "params": [ - { - "txs" : [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878", - "0x02f8b30181b28502cb417800853a352944008307a12094d5281bb2d1ee94866b03a0fccdd4e900c8cb509180b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a042f32acc8631c8c1c81d3d77a637cdab162477077d5041285ea7d73313d6b02ca07b18b432f4921795f84916b3c9398e2fd65580e372b9fa7e018e543ffbc00375" - ], - "blockNumber" : "0xce7b22", - "minTimestamp" : 0, - "minTimestamp" : 0, - "revertingTxHashes": [], - "relaySignature" : "0x2a115a51434b6f326b99bf4eefa1226f9eb88241f140545bf2d63c688eb57e9b07c5c3bb15340ecbdcdffd642c0995024bffa397cd313ec1f29c1c331e71187d1b", - } - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": true -} -``` - -## eth_sendPrivateRawTransaction - -### Description - -Sends a raw transaction to be included for block construction. Transaction is marked as private which means that it will not be broadcast to any other node for as long as the configured `txpool.privatetxlifespan` in hours. Except for the no broadcast rule the transaction should be treated equally with all the public transaction pool transactions. - -| Name | Type | Description | -| ---- | ---- | ----------- | -| input | `Array` | Signed transaction (`eth_sendRawTransaction` style, signed and RLP-encoded) | - -### Returns - -"error|value" : `Data` - txhash or error - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_sendPrivateRawTransaction", - "params": [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878" - ] -}' - -# Response -{ - "id": 1337, - "jsonrpc": "2.0", - "result": "0xdeadbeef883764809a94a5320e4557102f5a3fdd98dabd8cd48773b0eca00666" -} -``` - - -## eth_callBundle - -### Description - -Simulate a bundle of transactions at the top of a block. - -After retrieving the block specified in the `blockNrOrHash` it takes the same `blockhash`, `gasLimit`, `difficulty`, same `timestamp` unless the `blockTimestamp` property is specified, and increases the block number by `1`. `eth_callBundle` will timeout after `5` seconds. - -| Name | Type | Description | -| ---- | ---- | ----------- | -| txs | `Array` | Array of signed transactions (`eth_sendRawTransaction` style, signed and RLP-encoded) | -| blockNumber | `Quantity` | A hex encoded block number for which this bundle is valid on | -| stateBlockNumber | `Quantity\|string\|Block Identifier` | Either a hex encoded number or a {Block Identifier} for which state to base this simulation on. -| timestamp |`Quantity` |Block timestamp to be used in replacement of the timestamp taken from the parent block. | - -### Returns - -Map<`Data`, "error|value" : `Data`> - a mapping from transaction hashes to execution results with error or output (value) for each of the transactions - -### Example - -```bash -# Request -curl -X POST -H 'Content-Type: application/json' --data '{ - "id": 1337, - "jsonrpc": "2.0", - "method": "eth_callBundle", - "params": [ - { - "txs": [ - "0x02f8b30181b18502cb417800853a352944008307a12094b893a8049f250b57efa8c62d51527a22404d7c9a80b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080a027148354c23bb016147ed68014b2aa13c43a4feef36274be88ef58d25f91e20fa05ccc423d4e9e1de88515adf3245df69db8c05b1ce345a738c75b06c87a96f878", - "0x02f8b30181b28502cb417800853a352944008307a12094d5281bb2d1ee94866b03a0fccdd4e900c8cb509180b844095ea7b300000000000000000000000093e17e368e82dd24bed931091f831b5bed3f711effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a042f32acc8631c8c1c81d3d77a637cdab162477077d5041285ea7d73313d6b02ca07b18b432f4921795f84916b3c9398e2fd65580e372b9fa7e018e543ffbc00375" - ], - "blockNumber": "0xce7b22", - "stateBlockNumber": "0xce7b21" - } - ] -}' - -# Response -{ - "jsonrpc": "2.0", - "id": 1337, - "result": { - "bundleGasPrice": "12000000000", - "bundleHash": "0xa1433fce883764809a94a5320e4557102f5a3fdd98dabd8cd48773b0eca00666", - "coinbaseDiff": "707448000000000", - "ethSentToCoinbase": "0", - "gasFees": "707448000000000", - "results": [ - { - "coinbaseDiff": "354300000000000", - "ethSentToCoinbase": "0", - "fromAddress": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - "gasFees": "354300000000000", - "gasPrice": "12000000000", - "gasUsed": 29525, - "toAddress": "0xB893A8049f250b57eFA8C62D51527a22404D7c9A", - "txHash": "0x2425790f3031b66981e091cf96e2d29bdd12f47b334557462a0d482b2f057490", - "value": "0x0000000000000000000000000000000000000000000000000000000000000001" - }, - { - "coinbaseDiff": "353148000000000", - "ethSentToCoinbase": "0", - "fromAddress": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - "gasFees": "353148000000000", - "gasPrice": "12000000000", - "gasUsed": 29429, - "toAddress": "0xd5281BB2d1eE94866B03A0fcCDd4e900c8Cb5091", - "txHash": "0xf130358842db89e12d17fe1b35556adbe66497764921a92fda83571d8a2dcc72", - "value": "0x0000000000000000000000000000000000000000000000000000000000000001" - } - ], - "stateBlockNumber": 13531937, - "totalGasUsed": 58954 - } -} -``` - ---- - -Below type description can also be found in [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474) - -### `Quantity` - -- A `Quantity` value **MUST** be hex-encoded. -- A `Quantity` value **MUST** be "0x"-prefixed. -- A `Quantity` value **MUST** be expressed using the fewest possible hex digits per byte. -- A `Quantity` value **MUST** express zero as "0x0". - -### `Data` - -- A `Data` value **MUST** be hex-encoded. -- A `Data` value **MUST** be “0x”-prefixed. -- A `Data` value **MUST** be expressed using two hex digits per byte. - -### `Block Identifier` - -Since there is no way to clearly distinguish between a `Data` parameter and a `Quantity` parameter, [EIP-1898](https://eips.ethereum.org/EIPS/eip-1898) provides a format to specify a block either using the block hash or block number. The block identifier is a JSON `object` with the following fields: - -| Position | Name | Type | Description | -| -------- | ---- | ---- | ------------| -| 0A |blockNumber |`Quantity` |The block in the canonical chain with this number | -| 0B |blockHash |`Data` | The block uniquely identified by this hash. The blockNumber and blockHash properties are mutually exclusive; exactly one of them must be set. | -| 1B |requireCanonical |`boolean` | (optional) Whether or not to throw an error if the block is not in the canonical chain as described below. Only allowed in conjunction with the blockHash tag. Defaults to false. | - - -If the block is not found, the callee SHOULD raise a JSON-RPC error (the recommended error code is `-32001: Resource not found`. If the tag is `blockHash` and `requireCanonical` is `true`, the callee SHOULD additionally raise a JSON-RPC error if the block is not in the canonical chain (the recommended error code is `-32000: Invalid input` and in any case should be different than the error code for the block not found case so that the caller can distinguish the cases). The block-not-found check SHOULD take precedence over the block-is-canonical check, so that if the block is not found the callee raises block-not-found rather than block-not-canonical. diff --git a/docs/flashbots-auction/miners/mev-geth-spec/v06.md b/docs/flashbots-auction/miners/mev-geth-spec/v06.md deleted file mode 100644 index cc7f9b1e..00000000 --- a/docs/flashbots-auction/miners/mev-geth-spec/v06.md +++ /dev/null @@ -1,224 +0,0 @@ ---- -title: v0.6 (current) ---- -_Note: v0.6 is scheduled for release on Feb 28th, 2022. Please reference the [release plan](/flashbots-auction/releases/alpha-v0.6) for information on upgrading and configuration._ - -## Simple Summary - -Defines the construction and usage of MEV bundles by miners. Provides a specification for custom implementations of the required node changes so that MEV bundles can be used correctly. - -## Abstract - -`MEV bundles` are stored by the node and the bundles that are providing extra profit for miners are added to the block in front of other transactions. - -## Motivation - -We believe that without the adoption of neutral, public, open-source infrastructure for permissionless MEV extraction, MEV risks becoming an insiders' game. We commit as an organisation to releasing reference implementations for participation in fair, ethical, and politically neutral MEV extraction. - -## Specification - -The key words `MUST`, `MUST NOT`, `REQUIRED`, `SHALL`, `SHALL NOT`, `SHOULD`, `SHOULD NOT`, `RECOMMENDED`, `MAY`, and `OPTIONAL` in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt). - -### Miner Configuration - -Miner `MUST` accept the following configuration options: -* miner.maxmergedbundles (int) - max number of `MEV bundles` to be included within a single block -* miner.trustedrelays (string) - comma separated, hex encoded Ethereum addresses of trusted relays that the miner will be able to accept megabundles from, being reasonably certain about DDoS safety - -Miner `SHOULD` accept the following configuration options: -* txpool.privatetxlifetime - time in hours while private transactions are withheld from public broadcasting - -### Definitions - -#### `Relay` - -An external system delivering `MEV bundles` and/or `MEV megabundles` to the node. Relay provides protection against DoS attacks. - -#### `MEV bundle` or `bundle` - -A list of transactions that `MUST` be executed together and in the same order as provided in the bundle, `MUST` be executed before any non-bundle transactions and only after other bundles that have a higher `bundle adjusted gas price`. - -Transactions in the bundle `MUST` execute without failure (return status 1 on transaction receipts) unless their hashes are included in the `revertingTxHashes` list. - -When representing a bundle in communication between the `relay` and the node we use an object with the following properties: - -|Property| Type|Description| -|-|-|-| -|`txs`|`Array`|A list of transactions in the bundle. Each transaction is signed and RLP-encoded.| -|`blockNumber`|`uint64`|The exact block number at which the bundle can be executed| -|`minTimestamp`|`uint64`|Minimum block timestamp (inclusive) at which the bundle can be executed| -|`maxTimestamp`|`uint64`|Maximum block timestamp (inclusive) at which the bundle can be executed| -|`revertingTxHashes`|`Array`|List of hashes of transactions that are allowed to return status 0 on transaction receipts| - -#### `MEV megabundle` or `megabundle` - -A pre-merged set of `bundles` coming from a `relay`. Megabundles are not mixed or merged with normal `MEV bundles` but instead used for a separate block construction. - -When representing a megabundle in communication between the `relay` and the node we use an object with the following properties: - -|Property| Type|Description| -|-|-|-| -|`txs`|`Array`|A list of transactions in the bundle. Each transaction is signed and RLP-encoded.| -|`blockNumber`|`uint64`|The exact block number at which the bundle can be executed| -|`minTimestamp`|`uint64`|Minimum block timestamp (inclusive) at which the bundle can be executed| -|`maxTimestamp`|`uint64`|Maximum block timestamp (inclusive) at which the bundle can be executed| -|`revertingTxHashes`|`Array`|List of hashes of transactions that are allowed to return status 0 on transaction receipts| -|`relaySignature` |`Array`|An secp256k1 signature signed with an address from the `miner.trustedrelays`. Message signed is a Keccak hash of RLP serialized sequence that contains the following items: array of txs (a sequence of byte arrays representing RLP serialized txs); blockNumber serialized as an uint64, minTimestamp serialized as an int256, like in the devp2p specification; maxTimestamp serialized as an int256, like in the devp2p specification; revertingTxHashes serialized as an array of byte arrays. - -#### `MEV block` - -A block containing more than zero `MEV bundles`. - -Whenever we say that a block contains a `bundle` we mean that the block includes all transactions of that bundle in the same order as in the `bundle`. - -#### `Unit of work` -A `transaction`, a `bundle`, `megabundle` or a `block`. - -#### `Subunit` -A discernible `unit of work` that is a part of a bigger `unit of work`. A `transaction` is a `subunit` of a `bundle` or a `block`. A `bundle` is a `subunit` of a `block`. - -#### `Total gas used` -The sum of gas units used by each transaction from the `unit of work`. - -#### `Average gas price` -For a transaction it is equivalent to the transaction _minerFee := Min(feeCapPerGas - BASEFEE, priorityFeePerGas)_ - and for other `units of work` it is a sum of (`average gas price` * `total gas used`) of all `subunits` divided by the `total gas used` by the unit. - -#### `Direct coinbase payment` -The value of a transaction with a recipient set to be the same as the `coinbase` address. - -#### `Contract coinbase payment` -A payment from a smart contract to the `coinbase` address. - -#### `Coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Eligible coinbase payment` -A sum of all `direct coinbase payments` and `contract coinbase payments` within the `unit of work`. - -#### `Gas fee payment` -An `average gas price` * `total gas used` within the `unit of work`. - -#### `Eligible gas fee payment` -A `gas fee payment` excluding `gas fee payments` from transactions that can be spotted by the miner in the publicly visible transaction pool. - -#### `Bundle scoring profit` -A sum of all `eligible coinbase payments` and `eligible gas payments` of a `bundle`. - -#### `Profit` -A difference between the balance of the `coinbase` account at the end and at the beginning of the execution of a `unit of work`. We can measure a `transaction profit`, a `bundle profit`, and a `block profit`. - -Balance of the `coinbase` account changes in the following way - -|Unit of work|Balance Change| -|-|-| -|Transaction| `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Bundle | `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Megabundle | `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | -|Block | `block reward` + `average gas price` * `total gas used` + `direct coinbase payment` + `contract coinbase payment` | - -#### `Adjusted gas price` -`Unit of work` `profit` divided by the `total gas used` by the `unit of work`. - -#### `Bundle adjusted gas price` -`Bundle scoring profit` divided by the `total gas used` by the `bundle`. - -$$ -s_{v0.6} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tm_T - \sum_{T\in M \cap U}g_Tm_T}{\sum_{T\in U}g_T} -$$ - -$s$: bundle $U$ _score_ used to sort bundles. -$U$: ordered list of transactions $T$ in a bundle. -$M$: set of transactions $T$ in the mempool. -$g_{T}$: _gas used_ by transaction $T$. -$c_{T}$: _fee cap per gas_ of transaction $T$. -$\delta_T$: _priority fee per gas_ of transaction $T$. -$e_{T}$: _effective fee per gas_ of transaction $T$ equal $\min$($c_{T}$, BASEFEE + $\delta_T$). -$m_{T}$: _miner fee per gas_ of transaction $T$ equal $e_{T}$ - BASEFEE. -$\Delta_{coinbase}$: coinbase difference from direct payment. - -#### `Private transaction` -A `transaction` that `MUST NOT` be broadcast to other nodes and `MUST` only be included in locally constructed blocks. Such a transaction `SHOULD` be kept in an isolated private transaction pool and `MUST` be evicted after `txpool.privatetxlifespan` hours. - -### Bundle construction - -A bundle `SHOULD` contain transactions with nonces that are following the current nonces of the signing addresses or other transactions preceding them in the same bundle. - -A bundle `MUST` contain at least one transaction. There is no upper limit for the number of transactions in the bundle, however bundles that exceed the block gas limit will always be rejected. - -A bundle `MAY` include `eligible coinbase payments`. Bundles that do not contain such payments may be discarded when their `bundle adjusted gas price` is compared with other bundles. - -The `maxTimestamp` value `MUST` be greater or equal the `minTimestamp` value. - -### Accepting bundles and private transactions from the network - -#### JSON RPC - -Node `MUST` provide a way of exposing a JSON RPC endpoint accepting `eth_sendBundle` calls (specified [here](v06-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from a `relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. - -Node `MUST` provide a way of exposing a JSON RPC endpoint accepting `eth_sendMegabundle` calls (specified [here](v06-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from a `relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. For each relay only the last megabundle `SHOULD` be stored in memory. - -Node `SHOULD` provide a way of exposing a JSON RPC endpoint accepting `eth_sendPrivateRawTransaction` calls (specified [here](v06-rpc.mdx)). Such endpoint `SHOULD` only be accepting calls from a `relay` but there is no requirement to restrict it through the node source code as it can be done on the infrastructure level. - -### Bundle eligibility - -Any bundle that is correctly constructed `MUST` have a `blockNumber` field set which specifies in which block it can be included. If the node has already progressed to a later block number then such bundle `MAY` be removed from memory. - -Each transaction in the bundle `MUST` have _maxFeePerGas_ equal or greater than _block.BASEFEE_ + _1 GWei_ to be selected for the block. - -Any bundle that is correctly constructed `MAY` have a `minTimestamp` and/or a `maxTimestamp` field set. Default values for both of these fields are `0` and the meaning of `0` is that any block timestamp value is accepted. When these values are not `0`, then `block.timestamp` is compared with them. If the current `block.timestamp` is greater than the `maxTimestamp` then the bundle `MUST NOT` be included in the block and `MAY` be removed from memory. If the `block.timestamp` is less than `minTimestamp` then the bundle `MUST NOT` be included in the block and `SHOULD NOT` be removed from memory (it awaits future blocks). - -### Block construction - -In order to prevent starvation of less frequently used relays, incoming `MEV megabundles` `MUST` be given a priority value equal to the time in milliseconds since the previous `MEV megabundle` sent by the same relay and redirected to a pool of `MEV megabundle` block producers (called workers in MEV-Geth). Whenever the worker is idle and there are `MEV megabundles` available, a bundle with the highest priority `MUST` be picked for evaluation. Megabundles are never merged with other bundles and can only be combined with transactions from the mempool. - -When an `MEV megabundle` with higher value than previously arrives - * block construction `MUST` be initated immediately if there is no block being built at the time. - * block construction `MUST` be queued for execution immediately after the current block construction task if a block is being built at the time. - -`MEV bundles` `MUST` be sorted by their `bundle adjusted gas price` first and then one by one added to the block as long as there is any gas left in the block and the number of bundles added is less or equal the `MaxMergedBundles` parameter. The remaining block gas `SHOULD` be used for non-MEV transactions. Both public and private transactions `MUST` be used on equal terms during the block construction (pools merged together, then sorted using standard Geth transaction sorting rules). - -When constructing a block each next bundle added after the first bundle `MUST` generate at least 99% of the `bundle adjusted gas price` from the time of the sorting (the first bundle will naturally provide 100% of this value). - -Block `MUST` contain between 0 and `MaxMergedBundles` bundles. - -A block with bundles `MUST` place the bundles at the beginning of the block and `MUST NOT` insert any transactions between the bundles or bundle transactions. - -When constructing a block the node `MUST` reject any bundle or megabundle that has a reverting transaction unless its hash is included in the `RevertingTxHashes` list of the bundle / megabundle object. - -The node `SHOULD` be able to compare the `block profit` for each number of bundles between 0 and `MaxMergedBundles` and choose a block with the highest `profit`, e.g. if `MaxMergedBundles` is 3 then the node `SHOULD` build 4 different blocks - with the maximum of respectively 0, 1, 2, and 3 bundles and choose the one with the highest `profit`. - -The node `MUST` be able to compare the `block profit` from the best `megabundles` with the `block profit` of otherwise winning block. - -### Bundle eviction - -Node `SHOULD` be able to limit the number of bundles kept in memory and apply an algorithm for selecting bundles to be evicted when too many eligible bundles have been received. - -## Rationale - -### Naive bundle merging - -The bundle merging process is not necessarily picking the most profitable combination of bundles but only the best guess achievable without degrading latency. The first bundle included is always the bundle with the highest `bundle adjusted gas price` - -### Using bundle adjusted gas price instead of adjusted gas price - -The `bundle adjusted gas price` is used to prevent bundle creators from artificially increasing the `adjusted gas price` by adding unrelated high gas price transactions from the publicly visible transaction pool. - -### Each bundle needs a blockNumber - -This allows specifying bundles to be included in the future blocks (e.g. just after some smart contracts change their state). This cannot be used to ensure a specific parent block / hash. - -## Future Considerations - -### Full block submission - -A proposal to allow MEV-Geth accepting fully constructed blocks as well as bundles is considered for inclusion in next versions. - -## Backwards Compatibility - -This change is not affecting consensus and is fully compatible with Ethereum specification. - -Bundle formats are not backwards compatible and the v0.2 bundles would be rejected by v0.1 MEV clients. - -## Security Considerations - -The node `SHOULD` ensure that `MEV bundles` and `megabundles` that are awaiting future blocks are evicted when at risk of reaching the storage limits (memory or persistent storage). diff --git a/docs/flashbots-auction/miners/mev-relay.mdx b/docs/flashbots-auction/miners/mev-relay.mdx deleted file mode 100644 index 9c4100fe..00000000 --- a/docs/flashbots-auction/miners/mev-relay.mdx +++ /dev/null @@ -1,154 +0,0 @@ ---- -title: mev relay ---- - -This repository contains a public relay for accepting transactions from searchers. It also contains an example reverse proxy for miners to run in front of their mev-geth nodes. This relay is meant only to protect participating miners from abuse via DoS attacks, but does otherwise no bundle filtering or censoring. - -## Public Relay - -TODO: add proper link -[This is the relay entrypoint](#). The public flashbots relay is available at https://relay.flashbots.net. See https://github.com/flashbots/ethers-provider-flashbots-bundle for a library to help you call this. - -The relay provides new JSON-RPC methods for interfacing with Flashbots. They are documented below: - -### eth_sendBundle - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_sendBundle", - "params": [{ txs, blockNumber, minTimestamp, maxTimestamp, revertingTxHashes }] -} -``` - -- **txs**: Array[String], A list of signed transactions to execute in an atomic bundle -- **blockNumber**: String, a hex encoded block number for which this bundle is valid on -- **minTimestamp(Optional)**: Number, the minimum timestamp for which this bundle is valid, in seconds since the unix epoch -- **maxTimestamp(Optional)**: Number, the minimum timestamp for which this bundle is valid, in seconds since the unix epoch -- **revertingTxHashes(Optional)**: Array[String], list of tx hashes within the bundle that are allowed to revert - -Example: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_sendBundle", - "params": [{["0x123abc...", "0x456def..."], "0xb63dcd", 0, 1615920932, []}] -} -``` - -### eth_callBundle - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_callBundle", - "params": [{ txs, blockNumber, stateBlockNumber, timestamp }] -} -``` - -- **txs**: Array[String], A list of signed transactions to execute in an atomic bundle -- **targetBlockNumber**: String, a hex encoded block number for which this bundle is valid on -- **stateBlockNumber**: String, either a hex encoded number or a block tag for which state to base this simulation on. Can use "latest" -- **timestamp(Optional)**: Number, the timestamp to use for this bundle simulation, in seconds since the unix epoch - -Example: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_callBundle", - "params": [["0x123abc...", "0x456def..."], "0xb63dcd", "latest", 1615920932] -} -``` - -### flashbots_getUserStats - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "flashbots_getUserStats", - "params": [blockNumber] -} -``` - -- **blockNumber**: String, a hex encoded recent block number, in order to prevent replay attacks. Must be within 20 blocks of the current chain tip. - -Returns a quick summary of how this searcher is performing in the relay: - -```json -{ - "signing_address": "0x123...", - "blocks_won_total": 283, - "bundles_submitted_total": 8503, - "bundles_error_total": 0, - "avg_gas_price_gwei": 73.43275884220039, - "blocks_won_last_7d": 283, - "bundles_submitted_last_7d": 8503, - "bundles_error_7d": 0, - "avg_gas_price_gwei_last_7d": 73.43275884220039, - "blocks_won_last_1d": 83, - "bundles_submitted_last_1d": 757, - "bundles_error_1d": 0, - "avg_gas_price_gwei_last_1d": 227.44116622595683, - "blocks_won_last_1h": 0, - "bundles_submitted_last_1h": 38, - "bundles_error_1h": 0, - "avg_gas_price_gwei_last_1h": 103.30447379959334, - "blocks_won_last_5m": 0, - "bundles_submitted_last_5m": 0, - "bundles_error_5m": 0, - "avg_gas_price_gwei_last_5m": null -} -``` - -- **blocks_won**: This number represents how many blocks were won by this user, according to the relay. This is **not** how many ended up on chain, this is just what our relay thinks would've won. -- **avg_gas_price_gwei**: The adjusted gas price, averaged over all submissions by this user. - -## Authentication - -This relay requires that all payloads are signed with an ethereum wallet. - -The signature is calculated by taking the EIP-191 hash of the json body encoded as UTF-8 bytes. Here's an example using ethers.js: - -```js -body = '{"id": 1234, "method", "eth_sendBundle", "params": [["0x123..."], "0xB84969"]}' -wallet = ethers.Wallet.createRandom() -wallet.signMessage(ethers.utils.id(body)) -``` - -or in web3py: - -```py -from web3 import Web3 -from eth_account import Account, messages - -body = '{"id": 1234, "method", "eth_sendBundle", "params": [["0x123..."], "0xB84969"]}' -message = messages.encode_defunct(text=Web3.keccak(text=body).hex()) -signed_message = Account.sign_message(message, private_key=private_key_hex) -``` - -or in go: - -```go -hashedBody := crypto.Keccak256Hash([]byte(body)).Hex() -sig, err := crypto.Sign(crypto.Keccak256([]byte("\x19Ethereum Signed Message:\n"+strconv.Itoa(len(hashedBody))+hashedBody)), pk) -signature := addr.Hex() + ":" + hexutil.Encode(sig) -``` - -Take this signature and append it to the ethereum address of the signer, separated by a colon, `:`. Then send it in the `X-Flashbots-Signature` HTTP header like so: - -``` -X-Flashbots-Signature: 0x95c622A2c597a8bdC26D371Dd3D57dA9D26052DF:0xc73d4790fed41954869625c159a4617e3374019839a8ad72de15e41371719d6873c780e00293fcdc100aa505f33dd8480e7b07551483c8c438fe8236972d26ca1c -``` - -This signer does not have to be related to the signer of your actual transactions. It is just used for authentication/rate limiting purposes, and is how `flashbots_getUserStats` determines the user. - -## Miners - -See [https://github.com/flashbots/mev-proxy](https://github.com/flashbots/mev-proxy) for an example reverse proxy that this relay can connect to. Also, take a look at [https://github.com/flashbots/mev-geth](https://github.com/flashbots/mev-geth) diff --git a/docs/flashbots-auction/miners/quick-start.mdx b/docs/flashbots-auction/miners/quick-start.mdx deleted file mode 100644 index f6e1ff0d..00000000 --- a/docs/flashbots-auction/miners/quick-start.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: onboarding ---- - -:::tip Join Flashbots - -Over 80% of the Ethereum hashrate accepts Flashbots bundles which leads to fairer access to MEV and [0.3 ETH](https://dashboard.flashbots.net/) on average on top of every block reward for miners. - -::: - -For new mining pools who would like to receive Flashbots bundles, please complete the [Miner Indication of Interest Form](https://docs.google.com/forms/d/e/1FAIpQLSdz29fKXJXJFWXkEu8hZNG-NJUeAbOz0Jvw9mnNLskJHlMUDA/viewform). - ------ - -## Running MEV-Geth - -You can choose one of the following approaches to start using MEV-Geth - -### Build and launch MEV-Geth - -You can find the MEV-Geth repository [here](https://github.com/flashbots/mev-geth). - -``` -git clone https://github.com/flashbots/mev-geth -cd mev-geth -make geth -``` - -### Implement specification - -If the Geth version that you are using contains a lot of custom code, you may want to implement required MEV-Geth changes yourself. -You can find the latest specification [here](../miners/mev-geth-spec/v02.md) and the example implementation [here](https://github.com/ethereum/go-ethereum/compare/master...flashbots:master) - -## Feature requests and bug reports - -If you are a user of MEV-Geth and have suggestions on how to make integration with your current setup easier, or would like to submit a bug report, we encourage you to open an issue in the mev-geth repository with the `enhancement` or `bug` labels respectively. If you need help getting started, please ask in the dedicated [#⛏️miners](https://discord.com/invite/7hvTycdNcK) channel in our Discord. diff --git a/docs/flashbots-auction/other-resources.md b/docs/flashbots-auction/other-resources.md index d5a0d30a..41690a1a 100644 --- a/docs/flashbots-auction/other-resources.md +++ b/docs/flashbots-auction/other-resources.md @@ -2,8 +2,9 @@ title: other resources --- -Remember you can ask any questions in the [#🤖searchers](https://discord.com/invite/7hvTycdNcK) channel on our Discord, below are a list of useful resources for searchers to wrap their heads around running Flashbots: +Remember you can ask any questions in the [#🐣newcomers or #🤖searchers](https://discord.com/invite/7hvTycdNcK) channel on our Discord, or in one of the Self Support Groups on [our forum](https://collective.flashbots.net/). +Below are a list of useful resources for searchers to wrap their heads around running Flashbots: * [Walking through simple-arbitrage](https://discord.com/channels/755466764501909692/855195699019644958/895642636206084116) by Robert Miller * [Finding & Capturing MEV 101](https://www.youtube.com/watch?v=70WtsHtFd8Y) by thegostep & Robert Miller diff --git a/docs/flashbots-auction/overview.mdx b/docs/flashbots-auction/overview.mdx index 9a9b5bc0..e4763661 100644 --- a/docs/flashbots-auction/overview.mdx +++ b/docs/flashbots-auction/overview.mdx @@ -2,14 +2,16 @@ title: overview --- -Flashbots Auction is a permissionless, transparent, and fair ecosystem for efficient MEV extraction and frontrunning protection which preserves the ideals of Ethereum. Flashbots Auction provides a private communication channel between Ethereum users and miners for efficiently communicating preferred transaction order within a block. +Flashbots Auction is a permissionless, transparent, and fair ecosystem for efficient MEV extraction and frontrunning protection which preserves the ideals of Ethereum. Flashbots Auction provides a private communication channel between Ethereum users and validators for efficiently communicating preferred transaction order within a block. -Flashbots Auction consists of [mev-geth](https://github.com/flashbots/mev-geth), a patch on top of the go-ethereum client, along with the [mev-relay](https://github.com/flashbots/mev-relay-js), a transaction bundle relayer. +Flashbots Auction started with [mev-geth](https://github.com/flashbots/mev-geth), a patch on top of the go-ethereum client, along with the [mev-relay](https://github.com/flashbots/mev-relay-js), a transaction bundle relayer. + +In PoS Ethereum, the Flashbots Auction is built on [mev-boost](https://boost.flashbots.net/), an implementation of proposer-builder separation for Ethereum. Flashbots Auction is currently in version alpha-v0.4 of the [roadmap](#roadmap). ## Why Flashbots Auction? -Throughout the second half of 2020 and begining of 2021, a spike in Ethereum usage has revealed a set of negative externalities brought by MEV. These include network congestion (i.e. p2p network load) and chain congestion (i.e. block space usage) caused by inefficient communication between PGA bot operators and miners for transaction order preference. These negative externalities create a deadweight loss which is shouldered by regular Ethereum users though high gas price volatility and artificially scarce blockspace. +Throughout the second half of 2020 and begining of 2021, a spike in Ethereum usage has revealed a set of negative externalities brought by MEV. These include network congestion (i.e. p2p network load) and chain congestion (i.e. block space usage) caused by inefficient communication between PGA bot operators and (PoW) miners for transaction order preference. These negative externalities create a deadweight loss which is shouldered by regular Ethereum users though high gas price volatility and artificially scarce blockspace. The incentives around MEV extraction pose an existential risk to Ethereum consensus security due to the incentivization of chain history re-orgs for extraction of past MEV (e.g. through [time-bandit attacks](https://arxiv.org/pdf/1904.05234.pdf)) and incentivization of transaction routing centralization for privacy, low latency, and ordering control. These risks are considered to be existential for Ethereum as they undermine the principles of finality and permissionlessness. @@ -23,31 +25,31 @@ We have observed and are concerned about the active development of permissioned - August 2021: [Flashbots Auction Alpha (v0.3)](/flashbots-auction/releases/alpha-v0.3) made available for miners and searchers to adopt. - September 2021: [Flashbots Auction Alpha (v0.4)](/flashbots-auction/releases/alpha-v0.4) made available for miners and searchers to adopt. - February 2022: [Flashbots Auction Alpha (v0.5)](/flashbots-auction/releases/alpha-v0.5) made available for miners and searchers to adopt. - +- February, 2022: [Flashbots Auction Alpha (v0.6)](/flashbots-auction/releases/alpha-v0.6) made available for miners and searchers to adopt. ## How does it work? -Flashbots Auction provides a private transaction pool + a sealed bid blockspace auction mechanism which allows block producers to trustlessly outsource the work of finding optimal block construction. +Flashbots Auction provides a private transaction pool + a sealed bid blockspace auction mechanism which allows block proposers (validators; previously "miners" in PoW) to trustlessly outsource the work of finding optimal block construction. -In the regular Ethereum transaction pool, users broadcast transactions to the public peer-to-peer network and specify a gas price which indicates how much they are willing to pay for each unit of computation on the ethereum chain. Miners receive these transactions, order them by gas price, and use a greedy algorithm to produce a block which attempts to maximise the value received through transaction fees. This mechanism is a mix between an [English auction](https://en.wikipedia.org/wiki/English_auction) and an [all-pay auction](https://en.wikipedia.org/wiki/All-pay_auction) where bidding for blockspace is performed in the open, the top bidder captures the opportunity, and all participants incur a cost. +In the regular Ethereum transaction pool, users broadcast transactions to the public peer-to-peer network and specify a gas price which indicates how much they are willing to pay for each unit of computation on the ethereum chain. Block builders receive these transactions, order them by gas price, and use a greedy algorithm to produce a block which attempts to maximise the value received through transaction fees. This mechanism is a mix between an [English auction](https://en.wikipedia.org/wiki/English_auction) and an [all-pay auction](https://en.wikipedia.org/wiki/All-pay_auction) where bidding for blockspace is performed in the open, the top bidder captures the opportunity, and all participants incur a cost. Here are the key issues with this mechanism: 1. the open nature of the regular transaction pool causes bidding wars for blockspace which create unnecessary p2p network load and volatility in gas prices, as well as disadvantages less sophisticated network participants who do not have access to advanced bidding strategies -2. the all-pay nature of the auction causes failed bids to revert on chain, thus unnecessarily consuming blockspace and causing bidders to underprice their bids due to execution risk, ultimately leading to artificial blockspace scarcity and lower miner revenues +2. the all-pay nature of the auction causes failed bids to revert on chain, thus unnecessarily consuming blockspace and causing bidders to underprice their bids due to execution risk, ultimately leading to artificial blockspace scarcity and lower validator (previously "miner") revenues 3. the reliance on gasPrice makes it impossible for bidders to express granular ordering preferences as they are restricted to bidding for the top position in the block, this leads to alternative strategies like spam to increase likelihood of winning thus further increasing deadweight loss -Instead, the Flashbots Auction infrastructure uses a [first-price sealed-bid auction](https://en.wikipedia.org/wiki/First-price_sealed-bid_auction) which allows users to privately communicate their bid and granular transaction order preference without paying for failed bids. This mechanism maximizes miner payoffs, while providing an efficient venue for price discovery on the value of a given MEV opportunity. Crucially, this mechanism eliminates frontrunning vulnerabilities. +Instead, the Flashbots Auction infrastructure uses a [first-price sealed-bid auction](https://en.wikipedia.org/wiki/First-price_sealed-bid_auction) which allows users to privately communicate their bid and granular transaction order preference without paying for failed bids. This mechanism maximizes validator payoffs, while providing an efficient venue for price discovery on the value of a given MEV opportunity. Crucially, this mechanism eliminates frontrunning vulnerabilities. ## Roadmap The Flashbots team is taking an iterative approach to decentralizing the Flashbots Auction architecture. As mentioned in our initial [ethresearch post](https://ethresear.ch/t/flashbots-frontrunning-the-mev-crisis/8251), there remain some key research questions to be answered. Ultimately, the design goals are the following: -- **Pre-trade privacy**: implies transactions only become publicly known after they have been included in a block. This excludes intermediaries such as relayers / miners. +- **Pre-trade privacy**: implies transactions only become publicly known after they have been included in a block. This excludes intermediaries such as relays & block builders. - **Failed trade privacy**: implies losing bids are never included in a block, thus never exposed to the public. - **Efficiency**: implies MEV extraction is performed without causing unnecessary network or chain congestion. - **Bundle merging**: implies it is possible to merge multiple incoming bundles without conflict. - **Finality protection**: implies it is impractical for Flashbots blocks containing Flashbots bundles to be modified once propagated to the network. This would protect against time-bandit chain re-org attacks. -- **Complete privacy**: implies intermediaries like relayers and miners cannot observe the content of transactions until mined on chain. +- **Complete privacy**: implies intermediaries like relays and validators cannot observe the content of transactions until included on chain. - **Permissionless**: implies there are no trusted intermediaries which can censor transactions. | Stage | PGA | DarkPool | ⚡🤖 v0.1 | ⚡🤖 v0.2 | ⚡🤖 v0.3 | ⚡🤖 v0.4 | ⚡🤖 v1.0 | @@ -59,13 +61,14 @@ Ultimately, the design goals are the following: | Finality protection | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | | Complete privacy | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | | Permissionless | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | + ## Technical Architecture -The Flashbots Auction architecture proposes a network with three distinct parties who specialize in performing a subset of the work required for sustaining this communication channel. +The Flashbots Auction architecture proposes a network with three distinct parties who specialize in performing a subset of the work required for sustaining this communication channel. Block builders are responsible for building full blocks which validators will propose.
-![Auction Architecture](/img/core-architecture.png) +![Auction Architecture](/img/mevboost-searcher-bundle-flow.png)
@@ -98,55 +101,88 @@ Typically, searchers will be one of the following types: 2. Ethereum users looking for frontrunning protection on their transactions (for example, Uniswap traders) 3. Ethereum Dapps with advanced use cases like account abstraction or gasless transactions (for example, tornado.cash and mistX) -
+
+ + ![Searcher Architecture](/img/searcher-architecture.png) -![Searcher Architecture](/img/searcher-architecture.png) + Searchers create bundles with information from various sources and send them to a block builder.
-By submitting bundles directly to relayers instead of through the p2p network, searchers obtain `Pre-trade privacy` as their transactions cannot be seen by the rest of the network. The searchers express their bids for inclusion through their ethereum transactions as either gas price, or direct eth transfer to the coinbase address. Using direct payments instead of gas price allows users to make payments conditional on their transaction succeeding, thus avoiding having to pay for failed bids. +By submitting bundles directly to block builders instead of through the p2p network, searchers obtain `Pre-trade privacy` as their transactions cannot be seen by the rest of the network. The searchers express their bids for inclusion through their Ethereum transactions as either gas price, or direct eth transfer to the coinbase address. Using direct payments instead of gas price allows users to make payments conditional on their transaction succeeding, thus avoiding having to pay for failed bids. See the [searcher quick-start guide](/flashbots-auction/searchers/quick-start) to learn how to get started. -### Relayers -A relayer is a bundle propagation service which receives bundles from searchers and forwards them to miners. +### Block Builders -
+Block builders ("builders") are specialists who accept transactions from users and searchers, and try to build the most profitable block possible from those transactions. These blocks are then sent via an mev-boost relay to validators. See [Relays](#relays) for a deeper explanation of what relays do. Searchers send bundles to one or more builders. -![Relay Architecture](/img/relay-architecture.png) +
-
+ ![Block Builder Flow](/img/block-builder-flow.png) + + Block builders create blocks using bundles from searchers and transactions (not shown here) from the mempool. -A relayer is in charge of validating and routing Flashbots bundles. Since searchers no longer need to pay for failed bids, this opens up the ability for them to spam the network with invalid bundles, thus creating a denial of service attack against other network participants. Since Ethereum nodes are ill-equiped to deal with this level of load on their own, relayers primarily serve as a mitigation to this DOS threat. Relayers may also provide additional services like bundle merging and execution services which allow searchers to specialize. +
-Solving for spam protection and relayer privacy are the two main challenges the Flashbots Auction architecture must solve in order to become fully permissionless / decentralized. +⚠️ Not all builders can be trusted ⚠️ -For the time being, the Flashbots organization operate a relay called mev-relay which follows the [Flashbots Fair Market Principles](https://hackmd.io/@flashbots/fair-market-principles). +Builders have full view of incoming transactions, which gives them the power to frontrun, censor, etc. When choosing a builder, there are a few criteria to look for: -⚠️ Not all relayers can be trusted ⚠️ +* Are they committed to fair and unbiased execution? + * A good builder will not front-run, sandwich or censor bundles, or otherwise engage in activities that abuse privileged data access. +* Do they connect to a trusted relay (or relays)? + * Keep in mind that the relay can also see raw transactions, which gives them the ability to front-run, censor, etc. +* Do their relays connect to enough validators? + * The more validators a relay connects to, the more slots will generally be available for builders connected to that relay. When you're targeting a specific block/slot, it's imperative that you send your transactions to a builder which is connected to the validator responsible for proposing a block in that slot. More validators ⇒ better inclusion rates. + * Note: Any validator can [use mev-boost to connect to the Flashbots relay and other relays](https://github.com/flashbots/mev-boost#usage). + * It's also worth considering how much collective stake the validators connected to a relay have. Generally speaking, if more than one block is proposed to the network (unusual but possible), the block with the most collective stake attesting to it will be included. This scenario is explained in greater detail in the [Ethereum docs](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#fork-choice). -Relayers have full access to bundle content and can arbitrarily reorder / steal / censor bundles sent to them by searchers and can DOS miners by sending invalid bundles. It is discouraged for searchers and miners to integrate with relayers other than Flashbots until the system is fully decentralized, as it introduces systemic risk and prevents Flashbots from being able to monitor network health. +Also note that block builders have the freedom to specialize. You may find that one builder is more or less friendly to your strategy than others. Builders are competing with each other, so they are all incentivized to include your bundles in their blocks, but you may find that some builders will prioritize certain strategies over others regardless of potential profits. Builders might also censor certain bundles due to local regulations or corporate strategies and policies. There are a lot of variables in play here, so I recommend trying a few trustworthy builders and seeing how your mileage varies first-hand. Learn more about the [trust assumptions of the Flashbots Alpha](#trust-assumptions). -### Miners -A miner is the party who ultimately collects all the bundles and produces a block. Miners traditionally run the go-ethereum client and order transactions by gas price. However, miners connected to the Flashbots network run a version of the [mev-geth client](https://github.com/flashbots/mev-geth) maintained by Flashbots. +### Relays -
+Relays are a component of PBS which are responsible for escrowing blocks from builders for validators. + +
-![Miner Architecture](/img/miner-architecture.png) + ![Relay Flow](/img/relay-flow.png) + + Relay selects most profitable block from its builders and escrows it for the validator.
-The mev-geth nodes evaluate incoming bundles using the first-price sealed-bid auction and pick the most profitable ones to place at the top of the block. The node then compares the Flashbots block with a vanilla block and begins mining on the most profitable. +With mev-boost, validators choose the most profitable block from a number of relays. Each relay keeps the contents of a block private until the validator commits to proposing it to the network for inclusion. + +Specifically, relays do the following: + +* accept new blocks from builders +* send header of most profitable block to a validator upon request + * the validator locks in their commitment to propose the full block by signing this header +* send full block to validator after receiving block header signed by the validator +* perform all of this quickly and reliably, so that validators don't miss proposal deadlines -The information contained in the Flashbots bundle allows the searcher to express their blockspace preference relative to the state of the chain as well as the state of the transaction pool. This enables price discovery for discrete MEV opportunities instead of competition for priority along a single dimension. The miner can evaluate all the bundles received and combine those which do not conflict in order to produce the most profitable block possible. +For a deeper explanation of mev-boost and relays, Check out @thegostep's [ethresear.ch post](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177). + +For more information about how bundles are sent post-merge, see [this forum post](https://collective.flashbots.net/t/how-will-sending-bundles-change-in-pos-ethereum/147). + +Learn more about the [trust assumptions of the Flashbots Alpha](#trust-assumptions). -The ability for searchers to clearly express preferences is what enables an efficient auction which avoids negative externalities on the rest of the network. +### Validators -⚠️ Not all miners can be trusted ⚠️ +Validators (AKA "proposers") in PoS Ethereum are responsible for proposing blocks to the network, and appending blocks to the chain. You can learn more about validators in the [Ethereum docs](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#validators). + +
+ + ![Validator Flow](/img/validator-flow.png) + + Validator uses mev-boost to choose the most profitable block to propose from multiple relays. + +
-Miners have full access to bundle content and can arbitrarily reorder / steal / censor bundles sent to them by searchers and relayers. For the duration of the Alpha, it is discouraged for searchers to integrate directly with miners as Flashbots is unable to monitor their behavior. +When builders include MEV-yielding transactions, the blocks they produce will be more profitable on average. By sourcing the most profitable blocks from these builders, validators earn more profit just by using mev-boost. You can learn more about mev-boost at [boost.flashbots.net](https://boost.flashbots.net). Learn more about the [trust assumptions of the Flashbots Alpha](#trust-assumptions). diff --git a/docs/flashbots-auction/searchers/advanced/bundle-pricing.md b/docs/flashbots-auction/searchers/advanced/bundle-pricing.md index bd95f1d9..aaf4d2ed 100644 --- a/docs/flashbots-auction/searchers/advanced/bundle-pricing.md +++ b/docs/flashbots-auction/searchers/advanced/bundle-pricing.md @@ -6,32 +6,28 @@ title: bundle pricing Searchers submit a huge amount of bundles every block, but the amount of blockspace is limited. So what decides what can be included in a block or not? To understand the answer we will first review some context. -At a high level Flashbots is designed such that miners include the most profitable transactions possible in their blocks, and it achieves that by inserting searcher's bundles at the *top of block* and removing transactions at the *tail of the block*. Measured by gas price, these transactions at the tail of a block are the *least profitable* for a miner to mine. That means that for a Flashbots bundle to be considered profitable it must have a higher effective gas price than the transactions it displaces at the tail of the block. +At a high level _the Flashbots block builder is designed to include the most profitable transactions possible in the blocks it builds_. -It is important to remember that searchers can pay miners through normal gas fees or directly to the block's coinbase address (the miner). When calculating the *effective* gas price of a bundle, Flashbots takes into account both payments directly to coinbase as well as gas fees. +In **PoW Ethereum**, this was achieved by inserting searcher's bundles at the _top of block_ and removing transactions at the _tail of the block_. Measured by gas price, these transactions at the tail of a block were the _least profitable_ for a miner to mine. That meant that for a Flashbots bundle to be considered profitable it must have a higher effective gas price than the transactions it displaces at the tail of the block. -### Bundle pricing formula +In **PoS Ethereum**, the rule of thumb for bundle pricing on Flashbots is practically the same; more profitable transactions will generally be favored by the block-building algorithm. Bundle/transaction profitability is determined by fee per gas used, priority fee, and direct validator payments. -Here is the formula for how bundle gas pricing is calculated: +The most notable difference in PoS is that instead of all bundles being placed at the top of the block, bundles may be placed anywhere in a block. This might mean that other transactions (e.g. from the mempool) are placed between bundles. Bundles are still atomic, though -- no transactions will be placed in-between bundle transactions, only in-between separate bundles. -$$s_{v0.3-4} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tm_T - \sum_{T\in M \cap U}g_Tm_T}{\sum_{T\in U}g_T}$$ +### Bundle ordering formula -$s$: bundle $U$ _score_ used to sort bundles. -$U$: ordered list of transactions $T$ in a bundle. -$M$: set of transactions $T$ in the mempool. -$g_{T}$: _gas used_ by transaction $T$. -$p_{T}$: _gas price_ of transaction $T$. -$c_{T}$: _fee cap per gas_ of transaction $T$. -$\delta_T$: _priority fee per gas_ of transaction $T$. -$e_{T}$: _effective fee per gas_ of transaction $T$ equal $\min$($c_{T}$, BASEFEE + $\delta_T$). -$m_{T}$: _miner fee per gas_ of transaction $T$ equal $e_{T}$ - BASEFEE. -$\Delta_{coinbase}$: coinbase difference from direct payment. +The Flashbots builder uses a new algorithm designed to produce the most profitable block possible. This design introduces some important changes for searchers to be aware of: -### Explanation - -This formula derives the effective gas price of the bundle by summing up all payments to coinbase as well as gas fees *except* for the gas fees of transactions that have been seen in the mempool. - -The gas fees of mempool transactions are deducted to prevent "stuffing" bundles with high gas price transactions from the mempool to inflate the effective gas price. +* Instead of ranking and including bundles based off of effective gas price the algorithm now optimizes for overall block profit. +* Top-of-block execution is no longer a guarantee. +* Bundle ordering by effective gas price is no longer a guarantee. +* Other transactions (e.g. from the mempool) may land between bundles (not between transactions in bundles, but between two different bundles). + * For example: + * If you have a bundle comprised of transactions `[B1, B2]` + * and someone else has a bundle comprised of transactions `[C1, C2]` + * and there are transactions in the mempool `[t1, t2, ...]`, + * then the block may be built such that: + * `BLOCK_TXS = [..., B1, B2, t1, t2, C1, C2, ...]`. ### Why aren't my bundles being included? @@ -39,4 +35,4 @@ There are three reasons to examine. First, your bundles may not be paying a high Second, you may be competing with other searchers to capture the same opportunities, and they may be paying a higher gas price than you. Again, check the gas price that your bundles are paying by simulating them first and logging how much you are paying for a particular opportunity in a particular block. Then if your bundle is not included you can use the [blocks API](https://blocks.flashbots.net/) to see what bundle was included in your target block and how much they paid. -Third, bundles below 42,000 gas used are rejected by the relay. This is to mitigate spam bundles that do nothing meaningful on chain. +Third, bundles below 42,000 gas used are rejected by the Flashbots builder. This is to mitigate spam bundles that do nothing meaningful on chain. diff --git a/docs/flashbots-auction/searchers/advanced/coinbase-payment.mdx b/docs/flashbots-auction/searchers/advanced/coinbase-payment.mdx index 3216a9f4..1a4a2071 100644 --- a/docs/flashbots-auction/searchers/advanced/coinbase-payment.mdx +++ b/docs/flashbots-auction/searchers/advanced/coinbase-payment.mdx @@ -2,8 +2,8 @@ title: coinbase.transfer() --- -Flashbots allows you to pay miners for your transactions through a smart contract by using `block.coinbase.transfer(AMOUNT_TO_TRANSFER)`. This smart contract function transfers Ethereum from the contract to the coinbase address of the miner who mines that block. Miners running MEV-Geth will treat fees through coinbase transfers in the same way they do normal transaction fees, which is to say that 1 wei of coinbase payments is equivalent to 1 wei paid through transaction fees. This provides significant benefits to Flashbots users: -* You can condition payment to the miner on some criteria being met +Flashbots allows you to pay validators for your transactions through a smart contract by using `block.coinbase.transfer(AMOUNT_TO_TRANSFER)`. This smart contract function transfers Ethereum from the contract to the address of the validator who proposes a block. The Flashbots builder will treat fees through coinbase transfers in the same way they do normal transaction fees, which is to say that 1 wei of coinbase payments is equivalent to 1 wei paid through transaction fees. This provides significant benefits to Flashbots users: +* You can condition payment to the validator on some criteria being met * Related, you can only pay for successful transactions, not failures * You can pay for a transaction from account X with ETH from account Y (see: searcher sponsored transaction repo [here](https://github.com/flashbots/searcher-sponsored-tx)) @@ -31,14 +31,14 @@ function uniswapWeth(uint256 _wethAmountToFirstMarket, uint256 _ethAmountToCoinb } ``` -The above smart contract code will attempt to capitalize on arbitrage opportunities. If it does not make money doing so then the transaction will fail. Moreover, since the searcher is paying the miner via `block.coinbase.transfer()` on the last line then the searcher won't pay any transaction fees. +The above smart contract code will attempt to capitalize on arbitrage opportunities. If it does not make money doing so then the transaction will fail. For more information on how coinbase transfers are priced see the [bundle pricing page](/flashbots-auction/searchers/advanced/bundle-pricing). ## Managing payments to coinbase.address when it is a contract -Miners will occasionally have a smart contract listed as their block.coinbase address. This changes the expected behavior of the making payments to block.coinbase. Specifically it costs more gas to transfer ETH to block.coinbase if it is a contract than if it is an EOA, and as such many searchers will underestimate their gas consumption and their bundles will fail for miners who use contracts instead. +Validators will occasionally have a smart contract listed as their block.coinbase address. This changes the expected behavior of making payments to block.coinbase. Specifically it costs more gas to transfer ETH to block.coinbase if it is a contract than if it is an EOA, and as such many searchers will underestimate their gas consumption and their bundles will fail for validators who use contracts instead. -To handle this edge case searchers can up their gas limit to accomodate the additional payment to miners and call block.coinbase in the following way: +To handle this edge case searchers can up their gas limit to accomodate the additional payment to validators and call block.coinbase in the following way: ```solidity block.coinbase.call{value: _ethAmountToCoinbase}(new bytes(0)); diff --git a/docs/flashbots-auction/searchers/advanced/eip1559.mdx b/docs/flashbots-auction/searchers/advanced/eip1559.mdx index a50913c2..52d5caf5 100644 --- a/docs/flashbots-auction/searchers/advanced/eip1559.mdx +++ b/docs/flashbots-auction/searchers/advanced/eip1559.mdx @@ -2,9 +2,8 @@ title: eip-1559 support --- -Flashbots supports EIP-1559 transactions as of [mev-geth v1.10.5-mev-0.3.0](https://github.com/flashbots/mev-geth/releases/tag/v1.10.5-mev0.3.0). This support -requires no configuration changes for a searcher who is looking to use legacy transactions, but a block's `base fee` is a major change that will require transaction-level changes for any searcher using 0-gas-price transactions. -Searchers are still able to pay the miner for priority via a direct transfer to the coinbase or via gas price in excess of the 1559 base fee, but their transaction MUST include an Ethereum gasPrice at least equal to base fee +Flashbots supports EIP-1559 transactions as of [mev-geth v1.10.5-mev-0.3.0](https://github.com/flashbots/mev-geth/releases/tag/v1.10.5-mev0.3.0). This support requires no configuration changes for a searcher who is looking to use legacy transactions, but a block's `base fee` is a major change that will require transaction-level changes for any searcher using 0-gas-price transactions. +Searchers are still able to pay for priority via a direct transfer to the coinbase or via gas price in excess of the 1559 base fee, but their transaction MUST include an Ethereum gasPrice at least equal to base fee. **Note: For searchers using legacy transactions, passing `gasPrice` is equivalent to passing `maxFeePerGas` equal to `gasPrice` and including tip. Using a legacy transaction does not bypass the gasPrice >= baseFee requirement** @@ -50,7 +49,7 @@ const signedTransactions = await flashbotsProvider.signBundle([ No, all transactions must have maxFeePerGas greater than or equal to `block.baseFeePerGas`, or they are not eligible for inclusion in a block. ### Can a transaction specify `maxPriorityFeePerGas=0` -Absolutely, although the miner will need some incentive to include this transaction. With a Flashbots bundle, you can incentivize a miner with `block.coinbase.transfer()` payments _OR_ via `maxPriorityFeePerGas`. You can also use both at the same time; the incentive is cumulative. +Absolutely, although the builder will need some incentive to include this transaction. With a Flashbots bundle, you can incentivize a builder/validator to include your transactions with `block.coinbase.transfer()` payments _OR_ via `maxPriorityFeePerGas`. You can also use both at the same time; the incentive is cumulative. ### Will reverting transactions still be discarded? Flashbots still uses the same reverting transactions logic after EIP-1559: Unless specified in `revertingTxHashes` in `eth_sendBundle`, a transaction that reverts invalidates an entire bundle. However, as searchers are now required to use gas prices as a result of the requirement for `base fee` gas payments, searcher transactions may appear in the mempool more often as a result of block re-organizations. When using `gasPrice=0`, re-organized transactions are quickly dropped from gossip and are unlikely to appear in a future block, unless done so by another searcher. Transactions paying at least base fee will stay in the mempool and are likely to appear in future blocks, which could violate expectations around reverting transactions. diff --git a/docs/flashbots-auction/searchers/advanced/private-transaction.mdx b/docs/flashbots-auction/searchers/advanced/private-transaction.mdx index ba7dcdb2..b731de64 100644 --- a/docs/flashbots-auction/searchers/advanced/private-transaction.mdx +++ b/docs/flashbots-auction/searchers/advanced/private-transaction.mdx @@ -7,20 +7,21 @@ import TabItem from '@theme/TabItem'; ## How to send a single transaction to Flashbots -If you want to send a single transaction to Flashbots, without sending it as a bundle, you can use the `eth_sendPrivateTransaction` method. +If you want to send a single transaction to Flashbots without sending it as a bundle, you can use the `eth_sendPrivateTransaction` method. -This method attempts to send your transaction to miners on every block for a maximum of 25 blocks. No need to listen for the next block and re-send yourself. +This method sends your transaction to the Flashbots builder on every block for a maximum of 25 blocks. No need to listen for the next block and re-send yourself. -Private transactions can be cancelled with the `eth_cancelPrivateTransaction` method. Once a transaction is submitted from the relay to a miner we cannot "recall" it. However, we can cancel submitting transactions for future blocks. +Private transactions can be cancelled with the `eth_cancelPrivateTransaction` method. Once a transaction is included in a block and received by proposers, we cannot "recall" it. However, we can stop including transactions in future blocks. See [RPC endpoint](/flashbots-auction/searchers/advanced/rpc-endpoint) for JSON-RPC definitions of the methods. -These methods are currently implemented in the [ethers-provider-flashbots-bundle](/flashbots-auction/searchers/libraries/ethers-js-provider) library. More languages coming soon. +These methods are currently implemented in [ethers-provider-flashbots-bundle.js](/flashbots-auction/searchers/libraries/ethers-js-provider) and [web3-flashbots.py](/flashbots-auction/searchers/libraries/web3py-provider). @@ -42,16 +43,42 @@ const res = await flashbotsProvider.sendPrivateTransaction({ transaction, signer, }, { - maxBlockNumber: (await provider.getBlockNumber()) + 5, // only allow tx to be mined for the next 5 blocks + maxBlockNumber: (await provider.getBlockNumber()) + 5, // only allow tx to be included for the next 5 blocks }); const waitRes = await res.wait(); if (waitRes === FlashbotsTransactionResolution.TransactionIncluded) { - console.log("Private transaction successfully mined.") + console.log("Private transaction successfully included on-chain.") } else if (waitRes === FlashbotsTransactionResolution.TransactionDropped) { - console.log("Private transaction was not mined and has been removed from the system.") + console.log("Private transaction was not included in a block and has been removed from the system.") } ``` + + + +```python +web3 = Web3(HTTPProvider("http://localhost:8545/")) +flashbot(w3, signer) +signer: LocalAccount = Account.from_key("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") +nonce = web3.eth.get_transaction_count(signer.address) + +tx1: TxParams = { + "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "value": Web3.toWei(1, "ether"), + "data": "0xd0e30db0", + "gas": 21000, + "maxFeePerGas": Web3.toWei(100, "gwei"), + "maxPriorityFeePerGas": Web3.toWei(10, "gwei"), + "nonce": nonce, + "chainId": 1, + "type": 2, +} +web3.flashbots.send_private_transaction({ + "signer": signer, + "transaction": tx1, +}) +``` + diff --git a/docs/flashbots-auction/searchers/advanced/reputation.md b/docs/flashbots-auction/searchers/advanced/reputation.md index 99b44d81..0bdf37f6 100644 --- a/docs/flashbots-auction/searchers/advanced/reputation.md +++ b/docs/flashbots-auction/searchers/advanced/reputation.md @@ -2,33 +2,33 @@ title: searcher reputation --- -In order to maintain reliable Flashbots relay performance, we've introduced searcher reputation to provide consistent access to the relay for searchers with a good performance track record during periods of heavy load. Reputation is one of many solutions currently being explored to make the relay robust against sophisticated Layer 7 attacks. The system described on this page is likely to change and we encourage you to participate in defining the direction it will take by engaging in the [discussion board](https://github.com/flashbots/pm/discussions/79). +In order to maintain reliable performance, we've introduced searcher reputation to provide consistent access to the Flashbots block builder for searchers with a good performance track record during periods of heavy load. Reputation is one of many solutions currently being explored to make Flashbots infrastructure resilient against sophisticated Layer 7 attacks. The system described on this page is likely to change and we encourage you to participate in defining the direction it will take by engaging in the [discussion board](https://github.com/flashbots/pm/discussions/79). ## Reputation queues -The current reputation system is designed to classify searchers into a high reputation and low reputation queue. The high reputation queue is designed to filter out searchers who use an excessive amount of computation resources on the relay. Otherwise, both queues are identical. +The current reputation system is designed to classify searchers into a high reputation and low reputation queue. The high reputation queue is designed to filter out searchers who use an excessive amount of computation resources. Otherwise, both queues are identical. ## Reputation scoring -To determine in which queue a searcher belongs, Flashbots looks at their history of submissions to the relay. Specifically, Flashbots uses the following scoring function: +To determine which queue a searcher belongs to, Flashbots looks at their history of submissions to the builder. Specifically, Flashbots uses the following scoring function: $$r(U) = \frac{\sum_{T\in H_U}\Delta_{coinbase_T} + g_Tp_T}{\sum_{T\in S_U}g_T}$$ $r$: searcher reputation score. -$H_U$: set of all transactions $T$ submitted by searcher $U$ to the flashbots relay `eth_sendBundle` RPC and successfully landed on chain. -$S_U$: set of all transactions $T$ submitted by searcher $U$ to the flashbots relay `eth_sendBundle` and `eth_callBundle` RPC. +$H_U$: set of all transactions $T$ submitted by searcher $U$ to `eth_sendBundle` RPC and successfully landed on chain. +$S_U$: set of all transactions $T$ submitted by searcher $U$ to `eth_sendBundle` and `eth_callBundle` RPC. $g_{T}$: _gas used_ by transaction $T$. $p_{T}$: _gas price_ of transaction $T$. $\Delta_{coinbase_T}$: coinbase difference from direct payment in transaction $T$. ## Querying reputation -Flashbots uses a dynamic threshold to classify users between the high reputation and low reputation queue. The dynamic variables are: 1) the historical time period considered to calculate reputation, 2) the cutoff reputation score which classifies a searcher as "high reputation". Using a dynamic threshold allows the relay to adapt in periods of high demand and maintain high reliability for top searchers. +Flashbots uses a dynamic threshold to classify users between the high reputation and low reputation queue. The dynamic variables are: 1) the historical time period considered to calculate reputation, 2) the cutoff reputation score which classifies a searcher as "high reputation". Using a dynamic threshold allows the builder to adapt in periods of high demand and maintain high reliability for top searchers. -A searcher can query their current reputation status using the [`flashbots_getUserStats` RPC method](https://docs.flashbots.net/flashbots-auction/miners/mev-relay#flashbots_getuserstats). +A searcher can query their current reputation status using the [`flashbots_getUserStats` RPC method](/flashbots-auction/searchers/advanced/rpc-endpoint#flashbots_getuserstats). ## Building reputation -Searcher reputation is associated with the signing key used to authenticate with the relay. That is, the ethereum address associated with the `X-Flashbots-Signature` field of your bundle submission. +Searcher reputation is associated with the signing key used to authenticate with Flashbots. That is, the ethereum address associated with the `X-Flashbots-Signature` field of your bundle submission. -As a searcher, the best way to improve your score is to only submit transactions to the relay which have a high likelihood of landing on chain. +As a searcher, the best way to improve your score is to only submit bundles/transactions which have a high likelihood of landing on chain. diff --git a/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx b/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx index 432e4a2a..9ccb28d4 100644 --- a/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx +++ b/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx @@ -7,11 +7,11 @@ import TabItem from "@theme/TabItem"; ## How to interact directly with the Flashbots RPC endpoint -For advanced users, you can interact with the relay's RPC endpoint at `relay.flashbots.net`. The relay provides new JSON-RPC methods for interfacing with Flashbots which are documented below: +Advanced users can interact with the RPC endpoint at `relay.flashbots.net`. The API provides JSON-RPC methods for interfacing with Flashbots which are documented below: ### eth_sendBundle -`eth_sendBundle` can be used to send your bundles to the relay. The `eth_sendBundle` RPC has the following payload format: +`eth_sendBundle` can be used to send your bundles to the Flashbots builder. The `eth_sendBundle` RPC has the following payload format: ```json { @@ -142,7 +142,7 @@ example response: ### eth_sendPrivateTransaction -`eth_sendPrivateTransaction` is used to send a single transaction to Flashbots. Flashbots will attempt to send the transaction to miners for the next 25 blocks. See [Private Transactions](/flashbots-auction/searchers/advanced/private-transaction.mdx) for more info. +`eth_sendPrivateTransaction` is used to send a single transaction to Flashbots. Flashbots will attempt to build a block including the transaction for the next 25 blocks. See [Private Transactions](/flashbots-auction/searchers/advanced/private-transaction.mdx) for more info. [`eth_sendPrivateTransaction`](https://docs.alchemy.com/reference/eth-sendprivatetransaction?a=fb) is also supported for free on [Alchemy](https://alchemy.com?a=fb). @@ -156,7 +156,7 @@ This method has the following JSON-RPC format: "params": [{ tx, // String, raw signed transaction maxBlockNumber, // Hex-encoded number string, optional. Highest block number in which the transaction should be included. - preferences: { fast: boolean } // optional, see https://docs.flashbots.net/flashbots-protect/rpc/fast-mode + preferences: { fast: boolean } // optional. "fast" left for backwards compatibility; may be removed in a future version }] } ``` @@ -172,7 +172,7 @@ example request: { "tx": "0x123abc...", "maxBlockNumber": "0xcd23a0", - "preferences": { "fast": true } // optional, see https://docs.flashbots.net/flashbots-protect/rpc/fast-mode + "preferences": { "fast": true } // "fast" left for backwards compatibility; may be removed in a future version } ] } @@ -234,7 +234,7 @@ example response: ### flashbots_getUserStats -The `flashbots_getUserStats` JSON-RPC method returns a quick summary of how a searcher is performing in the relay, including their [reputation-based priority](/flashbots-auction/searchers/advanced/reputation). It is currently updated once every hour and has the following payload format: +The `flashbots_getUserStats` JSON-RPC method returns a quick summary of how a searcher is performing in the Flashbots ecosystem, including their [reputation-based priority](/flashbots-auction/searchers/advanced/reputation). It is currently updated once every hour and has the following payload format: ```json { @@ -264,8 +264,14 @@ example response: where - `is_high_priority`: boolean representing if this searcher has a high enough reputation to be in the high priority queue -- `all_time_miner_payments`: the total amount paid to miners over all time -- `all_time_gas_simulated`: the total amount of gas simulated across all bundles submitted to the relay. This is the actual gas used in simulations, not gas limit +- `all_time_miner_payments`: the total amount paid to validators over all time +- `all_time_gas_simulated`: the total amount of gas simulated across all bundles submitted to Flashbots. This is the actual gas used in simulations, not gas limit + +:::note + +Parameters with `miner` in the name are retrofitted with Flashbots block builder data to maintain backwards compatibility. This nomenclature will be changed in a future release to accurately reflect PoS Ethereum architecture. + +::: ### flashbots_getBundleStats @@ -300,13 +306,13 @@ example response: ### Authentication -To authenticate your request, the relay requires you sign the payload and include the signed payload in the `X-Flashbots-Signature` header of your request. +To authenticate your request, Flashbots endpoints require you to sign the payload and include the signed payload in the `X-Flashbots-Signature` header of your request. ```curl curl -X POST -H "Content-Type: application/json" -H "X-Flashbots-Signature: 0x1234:0xabcd" --data '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}' https://relay.flashbots.net ``` -Any valid Ethereum key can be used to sign the payload. The Ethereum address associated with this key will be used by the relay to keep track of your requests over time and provide user statistics. You can change the key you use at any time. +Any valid Ethereum key can be used to sign the payload. The Ethereum address associated with this key will be used by Flashbots to keep track of your requests over time and provide user statistics. You can change the key you use at any time. The signature is calculated by taking the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) hash of the json body encoded as UTF-8 bytes. Here's an example using ethers.js: diff --git a/docs/flashbots-auction/searchers/advanced/troubleshooting.mdx b/docs/flashbots-auction/searchers/advanced/troubleshooting.mdx index 1d23fbb3..ff4d10c7 100644 --- a/docs/flashbots-auction/searchers/advanced/troubleshooting.mdx +++ b/docs/flashbots-auction/searchers/advanced/troubleshooting.mdx @@ -4,16 +4,16 @@ title: bundle inclusion troubleshooting ## How to troubleshoot your Flashbots bundle not landing on-chain -Unlike broadcasting a transaction which lands on-chain (even if the transaction fails), troubleshooting Flashbots bundles is considerably more challenging, since any of the following circumstances will prevent your bundle from landing on chain: +Unlike broadcasting a transaction which lands on-chain even if the transaction fails, troubleshooting Flashbots bundles is considerably more challenging, since any of the following circumstances will prevent your bundle from landing on chain: ``` 1. Transaction failure (ANY within the bundle) 2. Incentives (gas price + coinbase transfers) not high enough to offset value of block space 3. Competitors paying more for same opportunity 4. Bundle received too late to appear in target block -5. A miner for target block not running Flashbots +5. A validator for target slot not running mev-boost ``` -While you might normally rely on [Etherscan](https://etherscan.io) to investigate how your transaction executed, landed on-chain, and compared to competitors, that won't work with Flashbots, a system that keeps your [losing] transactions from hitting the chain. As a part of debugging we _strongly_ recommend that you simulate your transactions, log the output, as well as keep a record of all the data you submit including your entire bundle and its signed transactions. +While you might normally rely on [Etherscan](https://etherscan.io) to investigate how your transaction executed, landed on-chain, and compared to competitors, that won't work with Flashbots, a system that keeps failed transactions from hitting the chain. As a part of debugging we _strongly_ recommend that you simulate your transactions, log the output, as well as keep a record of all the data you submit including your entire bundle and its signed transactions. The above possibilities are specified in the order they should be considered, so let's walk through each issue and demonstrate how one might discover and resolve each one. The following assumes you are using the [Flashbots Ethers Provider](https://github.com/flashbots/ethers-provider-flashbots-bundle), but the [RPC calls are standard](https://docs.flashbots.net/flashbots-auction/searchers/advanced/rpc-endpoint) and the strategies should be easy to implement in [other providers](https://docs.flashbots.net/flashbots-auction/searchers/libraries/golang). @@ -25,19 +25,19 @@ Covers: ``` These two issues are lumped together since their cause, investigation, and resolutions are very similar. Flashbots will not include a bundle with -1. A reverting transaction (unless specified via [optional argument revertingTxHashes](https://docs.flashbots.net/flashbots-auction/miners/mev-relay/#eth_sendbundle) or uncle'd) +1. A reverting transaction (unless specified via [optional argument `revertingTxHashes`](/flashbots-auction/searchers/advanced/rpc-endpoint#eth_sendbundle) or uncled) 2. [Gas price below base fee](https://docs.flashbots.net/flashbots-auction/searchers/advanced/eip1559#faq) (would create an invalid block if included) -3. Effective priority fee not high enough to offset opportunity cost of using that block space for other unrelated transactions _(e.g. your bundle is paying 1 Gwei priority fee, while the cheapest transaction in the block is paying 2 Gwei, it is in the miner's best interest to discard your bundle in favor of standard pending transactions)_ +3. Effective priority fee not high enough to offset opportunity cost of using that block space for other unrelated transactions _(e.g. your bundle is paying 1 Gwei priority fee, while the cheapest transaction in the block is paying 2 Gwei, it is in the builder's best interest to discard your bundle in favor of standard pending transactions)_ -As any of these conditions result in your bundle not appearing in a block, troubleshooting these issues requires `simulation` using `eth_callBundle` RPC call. `eth_callBundle` is similar to an `eth_call` you might already be familiar with, but offers these key benefits: +As any of these conditions result in your bundle not appearing in a block, troubleshooting these issues requires _simulation_ using `eth_callBundle` RPC call. `eth_callBundle` is similar to an `eth_call` you might already be familiar with, but offers these key benefits: 1. Operates on an array of *signed* transactions, instead of a single [unsigned] transaction description. These transactions are executed in sequence starting at the top of the specified block. Simulating with signed transactions leaves very little difference between how your system creates transactions and how they will be processed on-chain (e.g. you can never use an incorrect `from` field when simulating a signed transaction) 2. Returns gas used and coinbase transfer, per transaction. (Coinbase transfer factors into effective gas price) -3. Allows specifying the exact values for the following values, allowing more accurate simulation: +3. Allows specifying the exact values for the following arguments, allowing more accurate simulation: - State block number (what values are read from SLOADs) - EVM block number (what value is returned from `block.number`) - EVM timestamp (what value is returned from `block.timestamp`) -Flashbots ethers.js provider exposes `eth_callBundle` via the [simulate() method](https://github.com/flashbots/ethers-provider-flashbots-bundle#simulate-and-send). This only operates on a pre-signed bundle, so you must sign your bundle transactions manually. +The Flashbots ethers.js provider exposes `eth_callBundle` via the [simulate() method](https://github.com/flashbots/ethers-provider-flashbots-bundle#simulate-and-send). This only operates on a pre-signed bundle, so you must sign your bundle transactions manually. ``` const signedTransactions = await flashbotsProvider.signBundle(transactionBundle) const simulation = await flashbotsProvider.simulate(signedTransactions, targetBlockNumber, targetBlockNumber + 1) @@ -68,15 +68,15 @@ Output: } ``` -To resolve, ensure the response from eth_callBundle does not revert and matches your expectations for bundle profitability. Compare your bundle's effective gas price against the profit of the conflicting bundle. +To resolve, ensure the response from `eth_callBundle` does not revert and matches your expectations for bundle profitability. Compare your bundle's effective gas price against the profit of the conflicting bundle. -## Is you bundle paying enough to be competitive? +## Is your bundle paying enough to be competitive? Covers: ``` 3. Competitors paying more ``` -[Flashbots bundles adhere to a "blind" auction](https://docs.flashbots.net/flashbots-auction/overview), where bundle pricing is not released by Flashbots prior to landing in a block. Only after the block containing winning bundles is propagated the winning "bids" are revealed (via the transactions themselves and blocks-api for recognizing which set of transactions belong to a bundle). +[Flashbots bundles adhere to a "blind" auction](https://docs.flashbots.net/flashbots-auction/overview), where bundle pricing is not released by Flashbots prior to landing on-chain. The winning "bids" are revealed _only_ after the block containing winning bundles is propagated (via the transactions themselves and blocks-api for recognizing which set of transactions belong to a bundle). While you cannot see a competitor's bid in real time, it is possible to look AFTER the fact to: 1. Identify the exact bundle (if any) that conflicted with yours @@ -91,7 +91,7 @@ There are numerous reasons why two bundles might conflict. Consider that the bas A conflict occurs when a bundle simulates one way at the top of the block, and a different [worse] way when placed after another bundle. Here is a list of the ways a bundle could conflict: 1. **Nonce collision** - The target bundle includes a transaction from account `A` and nonce `B`. The conflicting bundle also includes a transaction from account `A` and nonce `B`. The most common case for nonce collision is from including the exact same transaction, but it doesn't have to be; the conflicting bundle only needs to increment an account's nonce via any transaction. 2. **Revert** - The target bundle has no reverting transactions when simulated at the top of the block, but reverts when placed after a conflicting bundle that appears first -3. **Effective Priority Fee** - A bundle cannot significantly reduce its priority fee between simulating at the top of the block and when it is selected for inclusion. This commonly occurs when a bundle is operating on an arbitrage for which it pays a % of the profit to the miner, with an earlier bundle taking part, but not all, of the arbitrage opportunity. +3. **Effective Priority Fee** - A bundle cannot significantly reduce its priority fee between simulating at the top of the block and when it is selected for inclusion. This commonly occurs when a bundle is operating on an arbitrage for which it pays a % of the profit to the validator, with an earlier bundle taking part, but not all, of the arbitrage opportunity. ### Detecting If a block you targeted contained Flashbots bundles, but yours did not appear, the next step is to determine which bundles conflicted with yours and, if present, calculate their `effective priority fee`. This can be accomplished through several iterations of simulations, using this strategy: @@ -161,7 +161,14 @@ Output: } ``` -To resolve, first determine if you have an issue of competitors paying more and, if so, increase your `effective priority fee`. This can be accomplished either by paying more to the miner _or_ using less gas to accomplish the same opportunity. +:::note + +Parameters with `miner` in the name are retrofitted with Flashbots block builder data to maintain backwards compatibility. This nomenclature will be changed in a future release to accurately reflect PoS Ethereum architecture. + +::: + +To resolve, first determine if you have an issue of competitors paying more and, if so, increase your `effective priority fee`. This can be accomplished either by paying more to the builder or validator, _or_ using less gas to accomplish the same opportunity. + If your bundles are not outbid by a conflicting bundle, check to see if your bundles are being received too late: ## Is your bundle received too late? @@ -171,16 +178,16 @@ Covers: ``` Each bundle submission targets only a specific block number, so it is important that the bundle is received as early as possible to ensure the bundle has time to: -1. Hit the relay -2. Pass relay simulation -3. Reach miners -4. Be present during the miner's next block re-formation +1. Reach the builder +2. Pass simulation +3. Get included in a block +4. Reach the validator via an mev-boost relay -All this must occur prior to the targeted block being mined. If you are targeting `blockNumber +1`, as most bundles do, it is important to get your bundle to the relay (step 1) as fast as possible. +All this must occur prior to the targeted block being proposed. If you are targeting `blockNumber +1`, as most bundles do, it is important to get your bundle to your builder(s) as fast as possible. -Keep in mind there is a period of time, for every block, when your local perspective of block height is `X`, while `X+1` has already been found and propagated to part of the network, without reaching your local node yet. During this period of partial propagation, submitting a bundle targeting `X+1`, while seemingly valid from your perspective of the network, is futile as miners have already begun work on solving X+2. This is the most extreme case, but the same logic also holds true of targeting `X+1` moments BEFORE it is found as steps 1 through 5 all take time (on the order of about 1-2 seconds). +Keep in mind there is a period of time, for every block, when your local perspective of block height is `X`, while `X+1` has already been found and propagated to part of the network, without reaching your local node yet. During this period of partial propagation, submitting a bundle targeting `X+1`, while seemingly valid from your perspective of the network, can be futile as builders may have already begun work on solving X+2. This is the most extreme case, but the same logic also holds true of targeting `X+1` moments BEFORE it is found as steps 1 through 5 all take time (on the order of about 1-2 seconds). -To see how much time elapsed between your bundle being submitted to relay, forwarded to miners, and the next block being found, Flashbots offers an RPC endpoint `eth_getBundleStats` which will return timing to you, based on a previously-submitted bundle. All submitted bundles have a bundleHash [which is easy to calculate](https://github.com/flashbots/ethers-provider-flashbots-bundle/blob/0d404bb041b82c12789bd62b18e218304a095b6f/src/index.ts#L266-L269) and target block number which uniquely identify them for later retrieval. +To see how much time elapsed between your bundle being submitted to Flashbots, forwarded to relays (previously bundles were sent directly to miners), and the next block being proposed, Flashbots offers an RPC endpoint `eth_getBundleStats` which will return timing to you, based on a previously-submitted bundle. All submitted bundles have a bundleHash [which is easy to calculate](https://github.com/flashbots/ethers-provider-flashbots-bundle/blob/0d404bb041b82c12789bd62b18e218304a095b6f/src/index.ts#L266-L269) and target block number which uniquely identify them for later retrieval. ``` console.log( @@ -201,18 +208,28 @@ Output: } ``` +:::note + +Parameters with `miner` in the name are retrofitted with Flashbots block builder data to maintain backwards compatibility. This nomenclature will be changed in a future release to accurately reflect PoS Ethereum architecture. + +::: + Compare the above times to the times you witness the targeted block propagated to your node. - If the amount of time is short, get your processing time and network latency down. - If the amount of time between `sentToMinersAt` and witnessing the target block is large, continue to the next section -## Is the miner for a particular block running Flashbots? +## Is the validator for a particular block/slot running mev-boost? ``` -5. A miner for target block not running Flashbots +5. A validator for target slot not running mev-boost ``` -Flashbots is a system that requires miner active participation, running a custom ethereum node and choosing to receive bundles from the Flashbots relay. While most Ethereum hash rate is currently running Flashbots (as of late 2021), not all blocks are mined with Flashbots bundles. +mev-boost is an opt-in system that runs alongside a validator's consensus client. Unless every validator on Ethereum runs mev-boost, some slots cannot be targeted with Flashbots. Additionally, your builder must be connected to the same relay as the proposer for the target slot. + +If no bundles are detected in the blocks-api response, check if other blocks from the same validator ever have Flashbots bundles. If no blocks from a particular validator contain Flashbots bundles, it is possible your bundle was not seen by the validator who proposed the block for the target block height. + +## New Blocks API fields -If no bundles are detected in the blocks-api response, check if other blocks from the same miner ever have Flashbots bundles. If no blocks from a particular miner contain Flashbots bundles, it is possible your bundle was not seen by the miner who created the block at the target block height. +New fields have been added to the blocks API to align the API with PoS Ethereum nomenclature. Details can be found in the [Blocks API page](/flashbots-data/blockapi). ## Everything checks out, what's next? Once you have validated the above issues are not affecting your bundle submission, consider filling out the Flashbots searcher support form: diff --git a/docs/flashbots-auction/searchers/advanced/understanding-bundles.mdx b/docs/flashbots-auction/searchers/advanced/understanding-bundles.mdx index 7ecf6b3d..42021da1 100644 --- a/docs/flashbots-auction/searchers/advanced/understanding-bundles.mdx +++ b/docs/flashbots-auction/searchers/advanced/understanding-bundles.mdx @@ -2,32 +2,30 @@ title: understanding bundles --- -Searchers use Flashbots to submit bundles to miners for inclusion in blocks. Bundles are one or more transactions that are grouped together and executed in the order they are provided. In addition to the searcher's transaction(s) a bundle can also potentially contain other users' pending transactions from the mempool, and bundles can target specific blocks for inclusion as well. Here's an example: +Searchers use Flashbots to submit bundles to block builders for inclusion in blocks. Bundles are one or more transactions that are grouped together and executed in the order they are provided. In addition to the searcher's transaction(s) a bundle can also potentially contain other users' pending transactions from the mempool, and bundles can target specific blocks for inclusion as well. Here's an example: ```js const blockNumber = await provider.getBlockNumber() const minTimestamp = (await provider.getBlock(blockNumber)).timestamp const maxTimestamp = minTimestamp + 120 const signedBundle = flashbotsProvider.signBundle( - [ - { - signedTransaction: SIGNED_ORACLE_UPDATE_FROM_PENDING_POOL // serialized signed transaction hex - }, - { - signer: wallet, // ethers signer - transaction: transaction // ethers populated transaction object - } - ]) -const bundleReceipt = await flashbotsProvider.sendRawBundle( - signedBundle, // bundle we signed above - targetBlockNumber, // block number at which this bundle is valid + [ + { + signedTransaction: SIGNED_ORACLE_UPDATE_FROM_PENDING_POOL // serialized signed transaction hex + }, { - minTimestamp, // optional minimum timestamp at which this bundle is valid (inclusive) - maxTimestamp, // optional maximum timestamp at which this bundle is valid (inclusive) - revertingTxHashes: [tx1, tx2] // optional list of transaction hashes allowed to revert. Without specifying here, any revert invalidates the entire bundle. + signer: wallet, // ethers signer + transaction: transaction // ethers populated transaction object } - ) -) + ]) +const bundleReceipt = await flashbotsProvider.sendRawBundle( + signedBundle, // bundle we signed above + targetBlockNumber, // block number at which this bundle is valid + { + minTimestamp, // optional minimum timestamp at which this bundle is valid (inclusive) + maxTimestamp, // optional maximum timestamp at which this bundle is valid (inclusive) + revertingTxHashes: [tx1, tx2] // optional list of transaction hashes allowed to revert. Without specifying here, any revert invalidates the entire bundle. + }) ``` In the above example we've constructed a bundle that includes our transaction (transaction) and a transaction from the mempool: SIGNED_ORACLE_UPDATE_FROM_PENDING_POOL. diff --git a/docs/flashbots-auction/searchers/example-searchers/searcher-sponsored-tx.md b/docs/flashbots-auction/searchers/example-searchers/searcher-sponsored-tx.md index b0721ca7..a0c2f37c 100644 --- a/docs/flashbots-auction/searchers/example-searchers/searcher-sponsored-tx.md +++ b/docs/flashbots-auction/searchers/example-searchers/searcher-sponsored-tx.md @@ -1,6 +1,6 @@ --- title: searcher sponsored tx --- -searcher-sponsored-tx is a repository that contains a simple Flashbots "searcher" for submitting a transaction from account X, but paying for the transaction from account Y. This is accomplished by submitting a Flashbots transaction bundle, with the first transaction(s) executing from account X, and the last, single transaction calling a contract which verifies the early transactions ran successfully, then pays the miner. +searcher-sponsored-tx is a repository that contains a simple Flashbots "searcher" for submitting a transaction from account X, but paying for the transaction from account Y. This is accomplished by submitting a Flashbots transaction bundle, with the first transaction(s) executing from account X, and the last, single transaction calling a contract which verifies the early transactions ran successfully, then pays the validator. -We hope you will use this repository as an example of how to integrate Flashbots into your own Flashbot searcher (bot). Access the searcher-sponsored-tx repo [here](https://github.com/flashbots/searcher-sponsored-tx). \ No newline at end of file +We hope you will use this repository as an example of how to integrate Flashbots into your own searcher bot. Access the searcher-sponsored-tx repo [here](https://github.com/flashbots/searcher-sponsored-tx). diff --git a/docs/flashbots-auction/searchers/faq.md b/docs/flashbots-auction/searchers/faq.md index ed71dd52..d2f9f758 100644 --- a/docs/flashbots-auction/searchers/faq.md +++ b/docs/flashbots-auction/searchers/faq.md @@ -1,290 +1,9 @@ --- title: FAQ --- -*Check Flashbots Discord [#release](https://discord.com/invite/7hvTycdNcK) channel for the latest releases.* -Don't see your question answered? Join our dedicated [#🤖searchers](https://discord.com/invite/7hvTycdNcK) channel on Discord and be sure to check out our [Searchers Self Support Group](https://collective.flashbots.net/c/searchers/12)! +The FAQ has been moved to the [Flashbots Collective Forum](https://collective.flashbots.net/). -### What is Flashbots Auction? +If your question hasn't already been answered there, please feel free to post a new question in one of the forum's Self Support Groups. -Flashbots Auction is a permissionless, transparent, and fair ecosystem for efficient MEV extraction and frontrunning protection which preserves the ideals of Ethereum. Flashbots Auction provides a private communication channel between Ethereum users and miners for efficiently communicating preferred transaction order within a block. See the full [Flashbots Auction overview](/flashbots-auction/overview). - -### Who is behind Flashbots Auction? - -Flashbots Auction is built by the Flashbots crew. We are a research and development organization working on solving the problems MEV causes to state-rich blockchains. You can find out more about the organization on our [pm repo](https://github.com/flashbots/pm) and in this introductory [Medium post](https://medium.com/flashbots/frontrunning-the-mev-crisis-40629a613752) that details our values and motives. - -### How is Flashbots funded? - -The Flashbots organization is funded by long term capital partners with a track record of alignment with the ecosystem. Our current capital partner is [Paradigm](https://www.paradigm.xyz). - -### What is the Flashbots Auction roadmap? - -See the latest progress on our [roadmap](/flashbots-auction/overview#roadmap). - -### Where can I submit a feature request? - -In the Flashbots Forums [Discussions section](https://github.com/flashbots/pm/discussions). - -### Can you give a step by step description of how Flashbots works for a searcher today? - -* Searchers send Flashbots "bundles" to MEV-Relay. A bundle contains one or several transactions that can be the trader's and/or other users' pending transactions from the mempool, and fees for a bundle can be paid by the searcher via a smart contract call to `block.coinbase.transfer()` -* Moreover, bundles have these properties: - * Flashbots bundles will always be at the top slot of the block - * Bundles cannot be 'broken up' into multiple transactions. All transactions in a bundle must be included together. (Note: we cannot prevent your bundle from being included in an uncle or a chain reorg) -* MEV-Relay receives bundles and sends them to all whitelisted miners running MEV-Geth -* Miners receive Flashbots bundles from MEV-Relay and process them in MEV-Geth -* MEV-Geth picks the most profitable combination of bundles out of all bundles it is sent. -* MEV-Geth then compares the block that includes these bundles with a vanilla block that does not include any bundles. If it is more profitable to include a bundle, or multiple ones, MEV-Geth will do so, but otherwise it will default back to a vanilla Geth block. -* Only when the searcher's bundle is included in a block then the tip associated with their bundle is paid. - * If a bundle is not included it does not cost the searcher anything (i.e. no gas fees are paid for failed transactions) - -### Why use Flashbots Auction? - -* It allows searchers to bypass the Ethereum mempool and avoid their strategy leaking before it is mined on-chain (e.g. being frontrun by generalized frontrunners). -* It allows searchers to save money from avoiding paying gas fees for failed transactions. -* It allows miners to receive additional revenue in the form of the bundle tip in exchange for including the most profitable bundle in the block they mined. -* It reduces Ethereum network congestion and lowers Ethereum network transaction fees. - -### How much hashrate is currently on Flashbots Auction? - -The mining pools running MEV-geth collectively account for over 85.5% of total Ethereum hashrate. - -### Can I send bundles directly to miners without going through the Relay? - -Using the Flashbots Relay is required during the alpha to aggregate bundle requests from all users, prevent spam and DOS attacks on participating miner(s)/mining pool(s), and collect necessary system health metrics. We are working to remove this requirement in future releases of Flashbots Auction. See the trust assumptions of the [Flashbots Alpha](/flashbots-auction/overview#trust-assumptions). - -### Where are the Relay servers located? - -They are currently in US-East-2 (Ohio) but we are thinking of turning them into a lambda that runs globally. - -### What are examples of Flashbots transactions? - -- Here is an example of a Flashbots bundle with a single transaction: -https://etherscan.io/tx/0x5e1657ef0e9be9bc72efefe59a2528d0d730d478cfc9e6cdd09af9f997bb3ef4 - - -- Here is an example of a Flashbots bundle with 3 transactions: - - tx #1: https://etherscan.io/tx/0xab16c4a7dbb403f45b8cd76945d25138d3c9728ece18959eb0c551d6653018d7 - - tx #2: https://etherscan.io/tx/0x89e47b1d61dbbaaee5669fe1dd783fa0564f380eda47df39e4053bccaa057714 - - tx #3: https://etherscan.io/tx/0x9683e160bdf8628c294bf999c874cddff37254eccc0e486dbe2271531b064178 - -![](https://hackmd.io/_uploads/Sy1Lj2pX_.png) -*Red line indicates where the bundle is* - -### What level of transparency do you provide into how this infrastructure works? -With the exception of MEV-Relay which is now closed source, MEV-Geth and all the code searchers interact with is open-source and documented on our [Github repos](https://github.com/flashbots). In addition, we publish monthly [transparency reports](https://medium.com/flashbots/tagged/transparency-report). - -We've also released a publicly accessible API [blocks.flashbots.net](https://blocks.flashbots.net) for displaying Flashbots blocks and txs, and will be releasing live data visualizations useful in the coming weeks. - -### Can Flashbots Auction be used concurrently with the regular Ethereum tx pool? - -Yes! As a searcher you want to maximize the hashrate you're exposed to and there is no reason you can't submit your trades to Flashbots and another system in parallel. One could also imagine a dual system that submits txs to both the traditional Ethereum mempool and Flashbots, with bot logic conditional on one or the other landing. - -### Is Flashbots Auction a race to maximize miners profits and minimize searcher profits? - -Flashbots Auction uses a first-price sealed-bid auction mechanism for allocating blockspace. This mechanism is designed to perform price discovery for an oportunity with minimal negative externalities. - -We expect searcher who focus on finding "new alpha" to be able to keep the majority of the profits, while searchers who target competitive opportunities will need to give the majority of profits to miners in order to win the auction. - -See the overview for more information on the [auction mechanism](/flashbots-auction/overview#how-does-it-work). - -### What will happen to Flashbots after The Merge? -[to update] - - -### Do I need authentication to access the Flashbots Relay? - -The Flashbots Relay expects payloads to be signed using a standard Ethereum private key. This relay signing address does not need to be given to Flashbots in advance, and it does not need to store any ETH or other assets (and we recommend it does not and it should be a different key from your bot's EOA key). - -The signature needs to be provided via the 'X-Flashbots-Signature' Header. Reference implementation can be found in the [Flashbots Ethers Provider](https://github.com/flashbots/ethers-provider-flashbots-bundle/blob/9e039cc92fcaa3d15e71f11faa7acf4f4f0674fa/src/index.ts#L307-L310) - -### Why am I getting rate limited by the relay? - -Rate limiting is currently in place to protect the relay infrastructure from DOS attacks. Similar to how Infura has a gas limit on eth_call. Rate limiting may be removed in the future for searchers who have accumulated good reputation. - -### How does searcher reputation work? - -By signing payloads with your own relay signing key, this will enable building a reputation for high-priority delivery of your bundles to miners. The Flashbots Relay simulates bundles before sending to miners which can take a small amount of time. The relay cannot determine which bundles are profitable without performing a full simulation. This signing key allows the relay to infer which bundles are likely profitable, based on historical performance. Using a reputation system allows reliable searchers to be rewarded for good performance while still allowing new searchers to participate. - -You can query the relay to obtain an understanding of your [reputation score](https://docs.flashbots.net/flashbots-auction/miners/mev-relay#flashbots_getuserstats). - -### Are you on any testnets? - -Yes, we are on Goerli. See this [guide](/flashbots-auction/searchers/advanced/goerli-testnet) for more information. - -### How do I target a timestamp range instead of a block number when submitting a bundle? - -The best way to do this is to submit one bundle for each block in a range of blocks that is likely to contain the first block with a block.timestamp greater than the target timestamp. - -You **do** need to submit a bundle per target block. You can re-submit the exact same signed transaction bundle; you don't need to re-sign. A more flexible API will be released soon to make this more efficient. - -You can ALSO provide a minimum/maximum timestamp in the bundle, but this only provides a hint to discard the block if it falls outside this time range. It does not expand the target outside the single indicated block number, and it does not change the timestamp selected by the miner. - -- 0,0 timestamp means no restriction - -### Can I submit directly to the sendBundle method without using the library? - -Please see the [reference implementation](https://github.com/flashbots/ethers-provider-flashbots-bundle), in particular how signing is done in order to be processed by the Relay. - -### What is block.coinbase? - -Block.coinbase is a standard Solidity function that gives the current block miner’s address. Read more about it [here](https://docs.soliditylang.org/en/v0.8.4/units-and-global-variables.html#block-and-transaction-properties). - -### Do I need ETH in my account to pay block.coinbase to the Flashbots miner? - -No, you can pay the miner with the profit of your bundle if it lands on-chain. This allows for account abstraction - something explained [here](https://github.com/flashbots/pm/issues/24) in further details. - -### Can I pay my coinbase bribe in something else than ETH? - -Unfortunately not at the current moment. - -### Since this is a first-price sealed-bid auction, how do I know how much to bid for my bundle to win? - -The lower bound on a successfully mined Flashbots bundle is the block tail gas price since the 'tail' of the block, and its transactions, will be pushed out to make room for a Flashbots bundle of transactions. This is what the miner's software will compare against when deciding whether to mine a Flashbots block or the vanilla Geth block. - -If you have no competition for that block, then any tip above the lower bound will get you included (modulo hashrate). If other searchers are going for the same block, you have to pay the highest tip of conflicting bundles for your bundle to be selected. We suggest you look at past data for other bids to get an idea of the average bid sizes and encourage you to check the [bundle pricing section](/flashbots-auction/searchers/advanced/bundle-pricing) in advanced concepts. - -### Will you implement a way for several non-overlapping bundles to be accepted within the same block? - -Yes, bundle merging is introduced in the [alpha-v0.2 release](/flashbots-auction/releases/alpha-v0.2). - -### Where can I get data on past auctions and past blocks? - -[blocks.flashbots.net](https://blocks.flashbots.net) - -### When miners select bundles, are they differentiating between transfers to the coinbase and the gas fees to select which bundle is valid for inclusion? - -Nope! - -### Can I simulate my bundle against historical blocks to backtest them? - -Yes, but only for dates after March 12th since the Relay is running with partial archive nodes. This means you can simulate blocks >= 12030000. This range will be extended shortly. - -### Can bundle simulations take into account state changes from an earlier transaction in the bundle? Eg. say first TX is buying the tokens, second is selling. - -Yep! - -### Can I estimate gas used of the bundle beforehand? - -Yes. You'll want to simulate with a 'fake' tip, like 1 wei, then see how much gas it uses, then change the tip. - -### How does MEV-Geth work when it receives bundles? - -[to update] - -### What are mega bundles? -[to update] - -### Can I use a contract to tip ETH to the miner? - -You can pay miners either via gas or by sending ETH to their coinbase. -It's best to pay via block.coinbase transfer to prevent the inclusion of your bundle when you miss (i.e. you remove the miner incentive of inclusion on a miss) and to protect yourself from re-orgs. - -### Can I deploy contracts using MEV? - -Yes, you can pay the block.coinbase fee in the constructor or you can pay the block.coinbase fee in a separate tx after your contract creation. -Crucially, you don't need to deploy a new contract to include block.coinbase.transfer in the contract function, one already exists [FLashbotsCheckAndSend](https://etherscan.io/address/0xc4595e3966e0ce6e3c46854647611940a09448d3). - -### Why didn't my transaction get included? - -See our [Searcher Troubleshooting Guide](/flashbots-auction/searchers/advanced/troubleshooting) - - -### What do I need to change in my bot aside from using the sendBundle to submit transactions? - -To get the full benefit of using Flashbots, it is worth considering the benefits of transitioning from priority fee payment (e.g. `priorityFee * gasUsed`) to coinbase payments. As of EIP-1559, you can no longer use `0-gas-price` transactions, but you CAN use `0-priority-fee` transactions, combined with custom functionality to your on-chain code to pay `block.coinbase.transfer()` based on the reward intended for the miner. - -Using `0-priority-fee` has several important benefits: - - Allows you to keep less ETH in your bot's `EOA` account (less at risk on a hot address, smaller capital requirements) - - Can pay miner out of proceeds of the opportunity, which could be more ETH than you have on hand! - - Can dynamically adjust to size of opportunity on-chain - - If your bot's transaction is leaked or `uncle`d, there is no incentive to a miner to include your transaction later unless it succeeds. `uncle`d transactions that use a priority fee will still land on chain and cost your `EOA` ETH, even when the opportunity was missed. - -This coinbase transfer amount can be determined in the middle of your contract logic or could come from a calldata argument or some percentage of the overall opportunity calculated on-chain. We recommend using calldata for specifying the reward in order to quickly react to fluctuations in competing Flashbots bundle prices. - -### Can I have a running bundle which I constantly update whenever I find a new trade? Essentially I want to continuously update my bunle until the next block arrives. - -Your previous bundle is dropped if the new bundle is more valuable. - -### Where can I view the health status of Flashbots' infrastructure? - -Status is reported at https://status.flashbots.net/. Please check this link for any network outages or downtime. - -### How will sending bundles change in PoS Ethereum? - -Sending bundles will feel very much the same as it does with Flashbots PoW Ethereum infrastructure. You’ll still be able to send & simulate atomic bundles, and use the same bidding strategies in the blockspace/MEV auction. - -The real difference is in the backend architecture. - -`relay.flashbots.net` (where bundles are sent in PoW Ethereum) will send bundles to the Flashbots builder after the merge. On the searcher side, the method for sending bundles to flashbots doesn’t change at all. All Flashbots relay endpoints from PoW Ethereum will be the same post-merge. - -With PBS, you may want to send bundles to more builders than just Flashbots. Other builders will need to implement their own version of this bundle relay to accept bundles, but as long as other builders adhere to the same API specification as Flashbots, you can use existing Flashbots client libraries to interact with these builders. - -### How do I choose a good block builder? - -There are a few criteria to look for in a block builder: - -* Are they committed to fair and unbiased execution? - * A good builder will not front-run, sandwich or censor bundles, or otherwise engage in activities that abuse privileged data access. -* Do they connect to a trusted relay? - * Keep in mind that the relay can also see raw transactions, which gives them the ability to front-run, censor, etc. -* Does their relay connect to enough validators? - * The more validators a relay connects to, the more slots will generally be available for builders connected to that relay. When you’re targeting a specific block/slot, it’s imperative that you send your transactions to a builder which is connected to the validator responsible for proposing a block in that slot. More validators ⇒ better inclusion rates. - * Note: Any validator can [use mev-boost to connect to the Flashbots relay and other relays](https://github.com/flashbots/mev-boost#usage). - * It’s also worth considering how much collective stake the validators connected to a relay have. Generally speaking, if more than one block is proposed to the network (unusual but possible), the block with the most collective stake attesting to it will be included. This scenario is explained in greater detail in the [Ethereum docs](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#fork-choice). - -Also note that block builders have the freedom to specialize. You may find that one builder is more or less friendly to your strategy than others. Builders are competing with each other, so they are all incentivized to include your bundles in their blocks, but you may find that some builders will prioritize certain strategies over others regardless of potential profits. Builders might also censor certain bundles due to local regulations or corporate strategies and policies. There are a lot of variables in play here, so I recommend trying a few trusted builders and seeing how your mileage varies first-hand. - -Flashbots will run a builder that follows the same principles we’ve adhered to in PoW Ethereum: democratized access to MEV, fair & reliable execution, and privacy. - -### How are “relays” defined in PoS Ethereum? - -Before the merge, mev-relay (commonly referred to as "the relay") was responsible for accepting bundles from searchers and relaying them to miners. - -After the merge, the term "relay" will mean something entirely different. *These* relays are a component of PBS -- they're responsible for escrowing blocks from builders for validators. With mev-boost, validators choose the most profitable block from a number of relays. Each relay keeps the contents of a block private until the validator commits to proposing it to the network for inclusion. - -Specifically, relays do the following: - -* accept new blocks from builders -* send header of most profitable block to a validator upon request - * *the validator locks in their commitment to propose the full block by signing this header* -* send full block to validator after receiving block header signed by the validator -* perform all of this quickly and reliably, so that validators don’t miss proposal deadlines - -For a deeper explanation of mev-boost and relays, Check out @thegostep’s *[ethresear.ch post](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177)*. - -For more information about how bundles are sent post-merge, see [this forum post](https://collective.flashbots.net/t/how-will-sending-bundles-change-in-pos-ethereum/147). - -### Can I be a block builder? How? - -mev-boost provides the foundation for a competitive market of block builders, each trying to provide the most profitable block to validators. Naturally, some searchers should want to become builders themselves. We expect there to be multiple relays in the future with varying requirements on who can submit blocks to them and how those blocks can be submitted. We are currently working on the rules for how the Flashbots Relay for mev-boost will accept blocks from builders. - -If you are interested in becoming a builder or just want to learn more, check out [this issue on mev-boost](https://github.com/flashbots/mev-boost/issues/145). - -### What trust assumptions exist in proposer-builder separation (PBS)? - -In this initial implementation of PBS (mev-boost), to prevent things like front-running, censorship, and unauthorized data sharing, each party has to trust the parties to which they connect. When PBS is [built natively](https://ethresear.ch/t/two-slot-proposer-builder-separation/10980) into the Ethereum protocol, these trust assumptions will be reduced by eliminating the need for relays. - -* Searchers have to trust the builder(s) to which they send bundles. - - Builders may be the most incentivized to ~~use~~ abuse your transactions to extract additional MEV. As a searcher, you must find a builder with reputation at stake, so you can trust that they won’t take short-term profits in favor of your continued bundle submissions. - -* Builders have to trust the relay to which they send blocks. - - For background on relays, see [this post](https://collective.flashbots.net/t/how-are-relays-defined-in-pos-ethereum/148). - - Of course, block builders have to trust that relays won’t leak transaction data or use it to extract additional MEV (secretly building blocks themselves). But the other major consideration is that the relay has to respond to the validator’s requests quickly, so that the validator does not miss the chance to propose a builder’s block. If the validator misses the slot, the builder of the most profitable block which would have been proposed loses out on their profits as well. - -* Validators have to trust the relay(s) from which they receive blocks. - - A strictly rational validator won’t care if a relay abuses their transaction view and extracts unfair MEV, as this is actually more profitable for the validator. That being said, if a relay abuses its power, it won’t last for long. - - For validators, the performance of the relay is paramount. Validators must trust that the relay(s) they connect to will respond to their requests quickly and reliably. If the relay does not respond in time, a validator may miss their window to include a block in the next slot, and will not earn any rewards for their participation. - -Read more about the trust assumptions of mev-boost-enabled PBS in [Stephane’s research post](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177). - -### Will the mempool change in PoS Ethereum? - -The public mempool works the same in PoS as in PoW — anyone running an execution client (e.g. geth) can read transactions from the mempool. - -It should be noted, however, that the post-merge public mempool may not see as much activity as it does today. With PBS, users and wallets may choose to send all of their transactions to a specific builder (or builders) rather than to the public mempool. +*Check the Flashbots Discord [#release](https://discord.com/invite/7hvTycdNcK) channel for the latest releases.* diff --git a/docs/flashbots-auction/searchers/libraries/alchemyprovider.md b/docs/flashbots-auction/searchers/libraries/alchemyprovider.md index 3512937d..4a495484 100644 --- a/docs/flashbots-auction/searchers/libraries/alchemyprovider.md +++ b/docs/flashbots-auction/searchers/libraries/alchemyprovider.md @@ -1,15 +1,15 @@ --- title: alchemy provider --- -The Alchemy SDK makes getting started, shipping builds, and accessing support faster and more streamlined. For instance, it provides high-level access to the `eth_sendPrivateTransaction` and `eth_cancelPrivateTransaction` rpc endpoints on mev-relay. +The Alchemy SDK makes getting started, shipping builds, and accessing support faster and more streamlined. For instance, it provides high-level access to the `eth_sendPrivateTransaction` and `eth_cancelPrivateTransaction` RPC endpoints. Benefits of the Alchemy SDK include providing: **1. Automatic management of your Flashbots reputation** - the SDK takes on the work of actively, and manually, managing your reputation. Learn more about reputation [here](https://docs.flashbots.net/flashbots-auction/searchers/advanced/reputation#querying-reputation) -**2. A superset of the ethers.js Provider library plus the suite of Alchemy APIs** - the Alchemy Provider exposes the relay endpoints and makes the full JSON-RPC specification endpoints available. The Flashbots relay API can be used natively with the core EVM APIs as well as the suite of Alchemy APIs +**2. A superset of the ethers.js Provider library plus the suite of Alchemy APIs** - the Alchemy Provider exposes all Flashbots JSON-RPC endpoints. The Flashbots API can be used natively with the core EVM APIs as well as the suite of Alchemy APIs -**3. Webhook based notifications on [mined and dropped private transactions](https://docs.alchemy.com/docs/alchemy-notify#features)** +**3. Webhook based notifications on [included and dropped private transactions](https://docs.alchemy.com/docs/alchemy-notify#features)** To get started: diff --git a/docs/flashbots-auction/searchers/libraries/ethers-js-provider.md b/docs/flashbots-auction/searchers/libraries/ethers-js-provider.md index 82330dcc..a81f8134 100644 --- a/docs/flashbots-auction/searchers/libraries/ethers-js-provider.md +++ b/docs/flashbots-auction/searchers/libraries/ethers-js-provider.md @@ -2,9 +2,9 @@ title: ethers.js provider --- -ethers-provider-flashbots-bundle is a repository that contains the `FlashbotsBundleProvider` ethers.js provider to provide high-level access to the `eth_sendBundle` rpc endpoint on mev-relay. +ethers-provider-flashbots-bundle is a repository that contains the `FlashbotsBundleProvider` ethers.js provider to provide high-level access to the `eth_sendBundle` rpc endpoint. -Flashbots-enabled relays and miners expose two new jsonrpc endpoint: `eth_sendBundle` and `eth_callBundle`. Since these are brand-new, non-standard endpoints, ethers.js and other libraries do not natively support these requests (like `getTransactionCount`). In order to interact with these endpoints, you will also need access to another full-featured (non-Flashbots) endpoint for nonce-calculation, gas estimation, and transaction status. +Flashbots exposes new json-rpc endpoints such as `eth_sendBundle` and `eth_callBundle`. Since these are non-standard endpoints, ethers.js and other libraries do not natively support these requests (like `getTransactionCount`). In order to interact with these endpoints, you will also need access to another full-featured (non-Flashbots) endpoint for nonce-calculation, gas estimation, and transaction status. This library is not a fully functional ethers.js implementation, just a simple provider class, designed to interact with your existing ethers.js v5 module. diff --git a/docs/flashbots-auction/searchers/libraries/golang.md b/docs/flashbots-auction/searchers/libraries/golang.md index b8e3a977..58607bc5 100644 --- a/docs/flashbots-auction/searchers/libraries/golang.md +++ b/docs/flashbots-auction/searchers/libraries/golang.md @@ -3,9 +3,9 @@ title: golang provider --- _These libraries are provided and maintained by third-parties rather than Flashbots. Please exercise caution._ -The Golang libraries provide high-level access to the `eth_sendBundle` and `eth_callBundle` rpc endpoints on mev-relay. +The Golang libraries provide high-level access to the `eth_sendBundle` and `eth_callBundle` RPC endpoints on the Flashbots builder. -Flashbots-enabled relays and miners expose several new jsonrpc endpoints, such as [`eth_sendBundle`](https://docs.flashbots.net/flashbots-auction/searchers/advanced/rpc-endpoint/#eth_sendbundle) and [`eth_callBundle`](https://docs.flashbots.net/flashbots-auction/searchers/advanced/rpc-endpoint/#eth_callbundle). Since these are non-standard endpoints, ethers.js and other libraries do not natively support these requests (like `getTransactionCount`). +Flashbots exposes several specialized JSON-RPC endpoints, such as [`eth_sendBundle`](https://docs.flashbots.net/flashbots-auction/searchers/advanced/rpc-endpoint/#eth_sendbundle) and [`eth_callBundle`](https://docs.flashbots.net/flashbots-auction/searchers/advanced/rpc-endpoint/#eth_callbundle). Since these are non-standard endpoints, ethers.js and other libraries do not natively support these requests (like `getTransactionCount`). Golang libraries: diff --git a/docs/flashbots-auction/searchers/libraries/web3js-provider.md b/docs/flashbots-auction/searchers/libraries/web3js-provider.md deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/flashbots-auction/searchers/libraries/web3py-provider.md b/docs/flashbots-auction/searchers/libraries/web3py-provider.md index 6002f1ee..0834ad83 100644 --- a/docs/flashbots-auction/searchers/libraries/web3py-provider.md +++ b/docs/flashbots-auction/searchers/libraries/web3py-provider.md @@ -1,10 +1,9 @@ --- title: web3.py provider --- -web3-flashbots is a repository containing a library that works by injecting a new module in the web3.py instance, which allows -submitting "bundles" of transactions directly to miners. This is done by also creating +web3-flashbots is a repository containing a library that works by injecting a new module in the web3.py instance, which can submit "bundles" of transactions to block builders. This is done by creating a middleware which captures calls to `eth_sendBundle` and `eth_callBundle`, and sends -them to an RPC endpoint which you have specified, which corresponds to `mev-geth`. +them to an RPC endpoint which you have specified, which corresponds your preferred block builder. To apply correct headers we use FlashbotProvider which injects the correct header on post diff --git a/docs/flashbots-auction/searchers/quick-start.mdx b/docs/flashbots-auction/searchers/quick-start.mdx index 8fd528af..a555c53c 100644 --- a/docs/flashbots-auction/searchers/quick-start.mdx +++ b/docs/flashbots-auction/searchers/quick-start.mdx @@ -5,7 +5,7 @@ title: quick start import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; -This quickstart guide contains all the information necessary to get up and running as a searcher on Flashbots Auction. If you have any questions, do not hesitate to ask in the ['#🤖 searchers' or '#🐣 newcomers' discord channels](https://discord.com/invite/7hvTycdNcK). +This quickstart guide contains all the information necessary to get up and running as a searcher on Flashbots. If you have any questions, do not hesitate to ask in the ['#🐣 newcomers' or '#🤖 searchers' discord channels](https://discord.com/invite/7hvTycdNcK), or in the [Searcher Self-Support Forum](https://collective.flashbots.net/c/searchers/12). See you on-chain! ⚡🤖 @@ -17,7 +17,7 @@ See you on-chain! ⚡🤖 ### How does Flashbots work for searchers? -Flashbots connects searchers directly to miners and allows them to avoid the public tx pool. Searchers with transactions they would like to send miners first craft what we call "bundles" and send these to Flashbots' MEV-Relay. MEV-Relay is a gateway that Flashbots runs today which simulates searchers' bundles, and if there are no errors then forwards them on to miners. Miners then receive bundles and include them in blocks if it is profitable for them to do so. +Flashbots connects searchers to validators (previously "miners") while allowing them to avoid the public tx pool. Searchers with transactions they would like to send first craft what we call "bundles" and send these to a block builder such as Flashbots. The builder simulates the bundles to ensure there are no reverts, and then builds a full block with the available bundles and transactions. Via mev-boost and the network of relays and builders, these blocks are received by validators while maintaining pre-trade privacy. Getting onboarded to Flashbots is easy for searchers; you simply need to update how you send transactions. @@ -32,7 +32,7 @@ To access the Flashbots network you will need three things: Let's begin with the private key Flashbots uses for identity. When you send bundles to Flashbots you will sign them with a private key so that we can establish identity for searchers and establish reputation for them over time. This private key **does not** store funds and is **not** the primary private key you use for executing transactions. Again, it is only used for identity, and it can be any private key. -Second, you'll need a way to interact with Flashbots. Flashbots runs a relay you will send bundles to at `relay.flashbots.net`, and we have specific RPC endpoints you'll need to use to send us transactions. We've integrated with a few popular developer tools like Ethers.js or web3.py to make interacting with MEV-Relay as easy as possible. Here are a few examples of how to set up a Flashbots provider: +Second, you'll need a way to interact with Flashbots. The Flashbots builder receives bundles at `relay.flashbots.net`, and we have specific RPC endpoints you'll need to use to send us transactions. We've integrated with a few popular developer tools like Ethers.js or web3.py to make interacting with Flashbots as easy as possible. Here are a few examples of how to set up a Flashbots provider: +https://protect.flashbots.net?bundle= ``` Chain ID should be set to `1`. ## Add Transaction to Bundle -To add a transaction to the bundle, sign and send the transaction as you normally would (e.g. via Metamask). The transaction will stay pending until it's mined (after you send the bundle). +To add a transaction to the bundle, sign and send the transaction as you normally would (e.g. via Metamask). The transaction will stay pending until it's included on-chain (after the bundle is sent). ## Get Bundle Transactions You can get the array of transactions included in your bundle using the `GET /bundle?id=` endpoint: ```sh -curl https://rpc.flashbots.net/bundle?id= +curl https://protect.flashbots.net/bundle?id= ``` This will return a JSON object with your signed transactions: @@ -48,13 +48,12 @@ Note: The transaction sent last is the first in the `rawTxs` array. ## Send Bundle -Once all the transactions you want to include in your bundle are added to the queue, send the signed transactions to the flashbots relay. +Once all the transactions you want to include in your bundle are added to the queue, query the bundle with `GET /bundle?id=` and send the returned signed transactions to Flashbots as a bundle. -If you're being helped with a whitehat recovery, we will provide a web interface for you to do this. +If you're being helped with a whitehat recovery, we may provide a web interface for you to do this. If you want to send a bundle directly, check out the [Flashbots Auction Docs](https://docs.flashbots.net/flashbots-auction/searchers/quick-start#how-to-send-your-first-flashbots-bundle) for instructions on how to do this. ## Fake Funds -Querying the balance of an address (using the `?bundle=` argument) will return a fake balance of 100 ETH, to allow crafting transactions even without actual funds. - +Querying the balance of an address when using the `?bundle=` argument will return a fake balance of 100 ETH, to allow crafting transactions without the account having actual funds. diff --git a/docs/flashbots-protect/rpc/cancellations.md b/docs/flashbots-protect/rpc/cancellations.md index c0744daa..9a1353fd 100644 --- a/docs/flashbots-protect/rpc/cancellations.md +++ b/docs/flashbots-protect/rpc/cancellations.md @@ -2,19 +2,15 @@ title: canceling transactions from being submitted further --- -Transactions that are submitted to Flashbots Protect RPC (*not* using fast mode) are submitted to the Flashbots Relay for the next 25 blocks. Once a transaction is submitted from the relay to a miner we cannot "recall" it. However, we can cancel submitting transactions for future blocks. +Transactions that are submitted to Flashbots Protect RPC are sent to the Flashbots block builder, where they may stay pending for up to 6 minutes. Once a transaction is included in a block and submitted to validators we cannot "recall" it. However, we can prevent a transaction from being included in future blocks. -Flashbots Protect RPC allows you to cancel pending transactions by submitting a cancellation transaction to Flashbots Protect RPC. By this we mean a transaction which +Flashbots Protect RPC allows you to cancel pending transactions by submitting a cancellation transaction to Flashbots Protect RPC. By this we mean a transaction which: - Is submitted by the same address as the transaction that is being cancelled - Has the same nonce as the transaction which is being cancelled - Has the same from and to address - Has an empty data field -**Note**: If you want to cancel a transaction that was submitted using fast mode, you must use fast mode to send the cancellation transaction. +## No cost to cancel -## Cancellation costs - -For transactions sent using Flashbots Protect **without fast mode**, this transaction is only used for authentication to ensure that you control the account that sent the transaction you want to cancel. This method allows for easy cancellation of transactions from retail wallets like MetaMask. The cancellation transaction will *not* be sent to the relay nor the miners. - -For transactions that are sent using Flashbots Protect **with fast mode**, you will have to pay the gas fee for the cancellation transaction and the transaction *will* be sent to miners. +This transaction is only used for authentication to ensure that you control the account that sent the transaction you want to cancel. This method allows for easy cancellation of transactions from retail wallets like MetaMask. The cancellation transaction will *not* be included on-chain. diff --git a/docs/flashbots-protect/rpc/fast-mode.md b/docs/flashbots-protect/rpc/fast-mode.md deleted file mode 100644 index 7dd37117..00000000 --- a/docs/flashbots-protect/rpc/fast-mode.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: Flashbots Protect with fast mode ---- - -Flashbots Protect offers a fast mode which may be better for some use cases. Without fast mode Protect uses Flashbots bundles, but by enabling fast mode Protect uses a new transaction type called "private transactions." By sending transactions using Flashbots Protect with fast mode your transactions are more likely to be included as soon as possible. But, transactions sent with fast mode won't have all the benefits of bundles such as protection against reverts and don't get priority at the top of the block. - -## Comparing Flashbots Protect with and without fast mode - -Here is a table that summarizes the differences between Flashbots Protect and Flashbots Protect with fast mode: - -| | Frontrunning protection | Priority at top of the block | No reverts | More blockspace | -|----------------------------------|-------------------------|------------------------------|------------|-----------------| -| Flashbots Protect | ✔ | ✔ | ✔ | | -| Flashbots Protect with fast mode | ✔ | | | ✔ | - -- *Frontrunning protection*: both bundles and private transactions are sent direct to miners and do not propagate in the public mempool -- *Priority at the top of the block*: transactions sent as bundles are included at the top of blocks and prioritized over other transactions. -- *No reverts*: transactions sent as bundles which revert are not included on-chain -- *More blockspace*: private transactions have more blockspace available to them, which means they will be included faster if there are a lot of bundles. - -## Using fast mode - -To use Flashbots Protect with fast mode add `https://rpc.flashbots.net/fast` with a chainID of `1` and currency of `ETH` as a new network in your MetaMask. - -### Cancelling transactions - -Transactions sent using fast mode can only be cancelled using the [standard cancellation method](/flashbots-protect/rpc/cancellations) offered by your wallet. - -Please note that fast mode transactions *cannot* be cancelled using the [`eth_cancelPrivateTransaction`](/flashbots-auction/searchers/advanced/private-transaction) method. This is only applicable to private transactions sent using `eth_sendPrivateTransaction` via the Flashbots relay. - -## When should I use fast mode? - -You should use fast mode if you want to be included in blocks as soon as possible and if your transactions are unlikely to revert. For example, if you are trading on a DEX that doesn't see much volume. - -If you think your transaction might revert, or if being at the top of the block matters a lot to you, you should use Flashbots Protect without fast mode. - -## Note -Fast mode transaction does not have 25 blocks limit, It will be sent to miner's private transaction mempool. Transaction remains there until either included or evicted, Default eviction period is 3 days but miners might have their own eviction period. diff --git a/docs/flashbots-protect/rpc/quick-start.md b/docs/flashbots-protect/rpc/quick-start.md index 24ac54d5..dea2f75f 100644 --- a/docs/flashbots-protect/rpc/quick-start.md +++ b/docs/flashbots-protect/rpc/quick-start.md @@ -1,26 +1,30 @@ --- title: quick start --- -**Please note that Flashbots Protect RPC is currently in public beta. Your transactions may occasionally time out and not be mined!** +**Please note that Flashbots Protect RPC is currently in public beta. Your transactions may occasionally time out and not be included!** -Flashbots Protect RPC allows regular users to easily submit their transactions to the Flashbots Auction by using a custom RPC endpoint in their wallet. Everything should be the same for users, except transactions are sent to Flashbots, and then directly to miners, instead of the public mempool. +Flashbots Protect RPC allows regular users to easily submit their transactions to the Flashbots Auction by using a custom RPC endpoint in their wallet. Everything should be the same for users, except transactions are sent to the Flashbots builder instead of the public mempool. + +Key benefits to using the Flashbots RPC endpoint: -There are a few key benefits to using the Flashbots RPC endpoint: - **Frontrunning protection:** your transaction will not be seen by hungry sandwich bots in the public mempool. -- **No failed transactions:** your transaction will only be mined if it doesn't include any reverts, so you don't pay for failed transactions. Note: your transaction could be uncled, emitted to the mempool, and then included on-chain. -- **Priority in blocks:** transactions sent via Flashbots are mined at the top of blocks, giving them priority. +- **No failed transactions:** your transaction will only be included if it doesn't include any reverts, so you don't pay for failed transactions. + > Note: your transaction could be uncled, emitted to the mempool, and then included on-chain. ## Key considerations -Before you get started here are a few things to be mindful of + +Before you get started here are a few things to be mindful of: + - **You can find the status of your transaction on Etherscan.** Etherscan has a nice interface for viewing the status of your transaction from our [status API](/flashbots-protect/rpc/status-api). -- We will try to resubmit your transaction for 25 blocks after which point it is considered “expired” and will be dropped. -- Transactions under 42,000 gas, such as simple ether transfers, are rejected by the Flashbots relay. As a result, we will forward these to the public mempool instead. -- Transactions that perform simple actions - such as token approvals or transfers - will be sent to the public mempool as these do not need frontrunning protection. +- We will try to include your transaction for 6 minutes, after which point it is considered “expired” and will be dropped. +- Transactions under 42,000 gas, such as simple ETH transfers, do not need front-running protection, so they are sent to the public mempool to provide the fastest execution possible. +- Transactions that perform simple actions - such as token approvals or transfers - will also be sent to the public mempool as these do not need frontrunning protection. - **There is a risk that your transactions are included in uncled blocks** and then emitted to the public mempool. Please read [the uncle bandits article](/flashbots-protect/rpc/uncle-bandits) to learn more about uncle bandits and how to mitigate this risk. - Your transactions can be emitted to the public mempool if you switch RPC endpoints from Flashbots Protect RPC to another RPC while your transactions are pending. ## Choosing the right gas price -In most cases sending a transaction through Flashbots Protect RPC should not require a higher gas price than normal. However, in periods of high load, you may want to increase gas prices to ensure your transaction is mined quickly. If the network is congested and you need your transaction quickly you could up your max fee to adjust for fluctations in base fee and set your priority fee to be 3 - 5 gwei. + +In most cases sending a transaction through Flashbots Protect RPC should not require a higher gas price than normal. However, in periods of high load, you may want to increase gas prices to ensure your transaction is included in a block quickly. If the network is congested and you need your transaction quickly you could up your max fee to adjust for fluctations in base fee and set your priority fee to be 3 - 5 gwei. Note also that the money saved from keeping reverts from landing on-chain means you will save money *even if you occasionally need to pay higher fees during periods of congestion*. @@ -30,7 +34,7 @@ To add Flashbots Protect RPC endpoint follow these steps: 1. Enter your MetaMask and click on your RPC endpoint at the top of your MetaMask. By default it says “Ethereum mainnet.” 2. Click “Custom RPC” -3. Add `https://rpc.flashbots.net` with a chainID of `1` and currency of `ETH`. +3. Add `https://protect.flashbots.net` with a chainID of `1` and currency of `ETH`. 4. Scroll to the bottom and click “Save” ![first metamask onboarding image](/img/flashbotsRPC-metamask1.png) @@ -46,9 +50,11 @@ Follow these steps to add Flashbots Protect RPC endpoint for Goerli: 4. Scroll to the bottom and click “Save” ## Fixing stuck transactions or fixing nonce errors + In the case that your transaction is stuck in a "pending" state or you have an extremely high nonce, you will need to 'reset' your MetaMask account. This will cause it to update the nonce and transaction history from the network. Don't worry, your funds and keys are safe during this process. Follow these steps: + 1. Click the account icon on the top-right corner of MetaMask. 2. Click "Settings". 3. Click "Advanced". @@ -57,4 +63,5 @@ Follow these steps: In the future we will offer more tooling to cancel transactions. ## Acknowledgements + Thank you to the [mistX](https://mistx.io/), [Nethermind](https://nethermind.io/), and [MiningDAO](https://miningdao.io/) teams for their contributions to Flashbots Protect RPC. diff --git a/docs/flashbots-protect/rpc/ratelimiting.md b/docs/flashbots-protect/rpc/ratelimiting.md index 6ff5ab23..c7741f19 100644 --- a/docs/flashbots-protect/rpc/ratelimiting.md +++ b/docs/flashbots-protect/rpc/ratelimiting.md @@ -4,8 +4,7 @@ title: rate limiting We have rate limits on the number of requests that can be made to Flashbots Protect RPC in order to protect our service from abuse. Currently you can only make 80 requests per second with a burst limit of up to 100 requests. -Note that this is *requests* per second and not *transactions* submitted per second. The number of transactions in a request is not limited. - +Note that this is *requests* per second and not *transactions* submitted per second. The number of transactions in a request is not limited. Note that you are not required to read JSON RPC requests to send transactions to Flashbots Protect RPC. @@ -14,4 +13,5 @@ Note that you are not required to read JSON RPC requests to send transactions to If you are a wallet or application integrating with protect and you require a higher rate limit please reach out to [bertcmiller](https://twitter.com/bertcmiller). ## Batch request support + Flashbots Protect RPC is not supporting batch JSON-RPC requests. diff --git a/docs/flashbots-protect/rpc/status-api.md b/docs/flashbots-protect/rpc/status-api.md index dfecf3b9..d85563d1 100644 --- a/docs/flashbots-protect/rpc/status-api.md +++ b/docs/flashbots-protect/rpc/status-api.md @@ -20,18 +20,20 @@ In turn you will receive a JSON response that looks like the following: "nonce": "41", "value": "10000000000" }, - "fastMode": false, + "fastMode": true, // for backwards compatibility; may be removed in a future version "seenInMempool": false, "simError": "MaxFeePerGasTooLow" } ``` ## Potential statuses -* `PENDING` - The transaction was received and is currently being submitted to miners + +* `PENDING` - The transaction was received and is currently being processed by the block builder * `INCLUDED` - The transaction was included on-chain * `FAILED` - The transaction was submitted for 25 blocks and failed to be included on-chain * `CANCELLED` - The transaction was cancelled by the user and not included on-chain * `UNKNOWN` - The transaction was not received ## Privacy + In order to receive a response from the status API you must know and provide a transaction hash to look up. As a result, you are only able to look up transactions which you know about. diff --git a/docs/flashbots-protect/rpc/uncle-bandits.md b/docs/flashbots-protect/rpc/uncle-bandits.md index 09bebaab..6b271b46 100644 --- a/docs/flashbots-protect/rpc/uncle-bandits.md +++ b/docs/flashbots-protect/rpc/uncle-bandits.md @@ -2,11 +2,11 @@ title: uncle bandit risk --- -Transactions using Flashbots for frontrunning protection in theory never reach the public mempool and therefore should not be visible to bot operators until successfully mined in the chain. However, if the block in which the transaction is included is uncled (honestly or maliciously), the transactions are revealed and can be targeted. This type of exploit is dubbed an “[uncle bandit](https://twitter.com/bertcmiller/status/1382673587715342339?s=20)”. On average, [1 in 20 blocks](https://ycharts.com/indicators/ethereum_uncle_rate) are uncled. +Transactions using Flashbots for frontrunning protection in theory never reach the public mempool and therefore should not be visible to bot operators until successfully included on-chain. However, if the block in which the transaction is included is uncled (honestly or maliciously), the transactions are revealed and can be targeted. This type of exploit is dubbed an “[uncle bandit](https://twitter.com/bertcmiller/status/1382673587715342339?s=20)”. On average, [1 in 20 blocks](https://ycharts.com/indicators/ethereum_uncle_rate) are uncled. In order to protect against uncle bandits, users looking for frontrunning protection should include a check on the parent hash in their transaction: -``` +```solidity require(blockhash(block.number - 1) == expectedParentHash, "block was uncled"); ``` diff --git a/docs/sidebars.js b/docs/sidebars.js index 6bb956c8..ec5838e0 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -6,7 +6,7 @@ module.exports = { ], }, { - 'flashbots auction': [ + 'Flashbots auction': [ 'flashbots-auction/overview', { "for searchers": [ @@ -41,37 +41,7 @@ module.exports = { }, 'flashbots-auction/other-resources' ], - 'for miners & mining pools': [ - 'flashbots-auction/miners/quick-start', - 'flashbots-auction/miners/how-it-works', - 'flashbots-auction/miners/demo', - 'flashbots-auction/miners/faq', - { - "advanced concepts": [ - 'flashbots-auction/miners/advanced/source-code', - 'flashbots-auction/miners/advanced/interacting-with-relay', - 'flashbots-auction/miners/advanced/discord-setup', - - { - 'mev-geth spec': [ - 'flashbots-auction/miners/mev-geth-spec/v06', - 'flashbots-auction/miners/mev-geth-spec/v06-rpc', - 'flashbots-auction/miners/mev-geth-spec/v05', - 'flashbots-auction/miners/mev-geth-spec/v05-rpc', - 'flashbots-auction/miners/mev-geth-spec/v04', - 'flashbots-auction/miners/mev-geth-spec/v04-rpc', - 'flashbots-auction/miners/mev-geth-spec/v03', - 'flashbots-auction/miners/mev-geth-spec/v03-rpc', - 'flashbots-auction/miners/mev-geth-spec/v02', - 'flashbots-auction/miners/mev-geth-spec/v02-rpc', - 'flashbots-auction/miners/mev-geth-spec/v01', - 'flashbots-auction/miners/mev-geth-spec/v01-rpc', - ] - }, - ], - }, - ], - 'releases': [ + 'mev-geth releases': [ 'flashbots-auction/releases/alpha-v0.6', 'flashbots-auction/releases/alpha-v0.5', 'flashbots-auction/releases/alpha-v0.4', @@ -84,7 +54,7 @@ module.exports = { ] }, { - "flashbots data": [ + "Flashbots data": [ { 'mev-inspect': [ 'flashbots-data/mev-inspect-py/overview', @@ -109,12 +79,11 @@ module.exports = { ], }, { - "flashbots protect": [ + "Flashbots Protect": [ 'flashbots-protect/overview', { 'rpc': [ 'flashbots-protect/rpc/quick-start', - 'flashbots-protect/rpc/fast-mode', 'flashbots-protect/rpc/uncle-bandits', 'flashbots-protect/rpc/status-api', 'flashbots-protect/rpc/bundle-cache', diff --git a/docs/welcome.mdx b/docs/welcome.mdx index fac35d36..f3723e5a 100644 --- a/docs/welcome.mdx +++ b/docs/welcome.mdx @@ -12,10 +12,10 @@ Flashbots is a research and development organization working on mitigating the n Our primary focus is to enable a permissionless, transparent, and fair ecosystem for MEV extraction. It falls under three goals: Democratizing Access to MEV Revenue, Bringing Transparency to MEV Activity, and Redistributing MEV Revenue. Our efforts are focused on three verticals: -1. **Flashbots Auction**: a private communication channel between miners and searchers for transparent and efficient MEV extraction. +1. **Flashbots Auction**: a private communication channel between validators and searchers for transparent and efficient MEV extraction. 2. **Flashbots Data**: a suite of tools for increasing MEV transparency and reducing information asymmetry. 3. **Flashbots Research**: an open, transparent, and collaborative research effort to tackle short and long term research questions relevant to MEV. -You can interact with Flashbots on Discord and Github. We have dedicated channels on Discord for each of our efforts and welcome your contributions. Our work is open source and you can follow our progress in each Github repository of the Flashbots organization. +You can interact with Flashbots on Discord, Github, and our Discourse forum. We have dedicated channels on Discord for each of our efforts and welcome your contributions. Our work is open source and you can follow our progress in each Github repository of the Flashbots organization. -[Mission](https://writings.flashbots.net/writings/frontrunning-mev-crisis) | [Discord](https://discord.gg/7hvTycdNcK) | [Blog](https://writings.flashbots.net) | [Github](https://github.com/flashbots/pm) | [Transparency Reports](https://writings.flashbots.net/writings/tags/transparency-report) | [Status](https://status.flashbots.net) +[Mission](https://writings.flashbots.net/writings/frontrunning-mev-crisis) | [Discord](https://discord.gg/7hvTycdNcK) | [Discourse Forum](https://collective.flashbots.net/) | [Blog](https://writings.flashbots.net) | [Github](https://github.com/flashbots/pm) | [Transparency Reports](https://writings.flashbots.net/writings/tags/transparency-report) | [Status](https://status.flashbots.net) diff --git a/src/css/custom.css b/src/css/custom.css index 74ba0f27..2e6d27e7 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -23,3 +23,19 @@ margin: 0 calc(-1 * var(--ifm-pre-padding)); padding: 0 var(--ifm-pre-padding); } + +.med { + width: 720px; +} + +.caption-img { + text-align: center; + font-style: italic; + font-size: small; + padding-bottom: 16px; +} + +.caption-img>p { + padding-top: 0; + margin-bottom: 4px; +} diff --git a/static/img/block-builder-flow.png b/static/img/block-builder-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8a2b37e0d8b58ae1a67b1ea72df39278120116 GIT binary patch literal 117580 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

4{XA-7BnPQSNG|D>D1h6^pz}`{N`NuecqS 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 literal 0 HcmV?d00001 diff --git a/static/img/mevboost-searcher-bundle-flow.png b/static/img/mevboost-searcher-bundle-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..7877535179a9bb63d4227fb1a4999a3d818a122c GIT binary patch literal 282260 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