diff --git a/.cspell.json b/.cspell.json new file mode 100644 index 00000000..09e84999 --- /dev/null +++ b/.cspell.json @@ -0,0 +1,32 @@ +{ + "version": "0.2", + "gitignoreRoot": ".", + "useGitignore": true, + "dictionaries": [ + "css", + "html", + "fonts", + "typescript", + "softwareTerms", + "companies", + "project-words" + ], + "dictionaryDefinitions": [ + { + "name": "project-words", + "path": "./project-words.txt", + "noSuggest": false + } + ], + "ignorePaths": [ + "package.json", + "yarn.lock", + "project-words.txt", + "*.gitignore" + ], + "ignoreRegExpList": [ + "Email", + "Urls", + "#[\\w-]*" + ] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..8c5cb46f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +max_line_length = 80 +trim_trailing_whitespace = true + +[*.md] +insert_final_newline = false +# 2 trailing whitespace indicate a new line in markdown +trim_trailing_whitespace = false diff --git a/.env.template b/.env.template index 402068d5..7e0cf003 100644 --- a/.env.template +++ b/.env.template @@ -1,2 +1,5 @@ BASE_URL=/docs/ -TARGET_URL=https://flashbots.github.io \ No newline at end of file +TARGET_URL=https://flashbots.github.io +ALGOLIA_APP_ID="example" +ALGOLIA_SEARCH_API_KEY="example" +ALGOLIA_INDEX_NAME="example" diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..4bce9ac0 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,8 @@ +node_modules +.yarn +.history +build +coverage +jest.config.js +jest.transform.js +jest/vendor diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..f9adefb6 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,92 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +const OFF = 0; +const WARNING = 1; +const ERROR = 2; + +module.exports = { + parser: '@typescript-eslint/parser', + parserOptions: { + project: true, + tsconfigRootDir: __dirname, + }, + plugins: ['header'], + extends: [ + 'eslint:recommended', + 'airbnb', + 'airbnb/hooks', + 'airbnb-typescript', + 'plugin:@docusaurus/recommended', + 'plugin:react/jsx-runtime', + 'plugin:mdx/recommended', + 'plugin:import/recommended', + 'prettier', + ], + rules: { + camelcase: WARNING, + 'max-len': [ + WARNING, + { + code: Infinity, // Code width is already enforced by Prettier + tabWidth: 2, + comments: 80, + ignoreUrls: true, + ignorePattern: '(eslint-disable|@)', + }, + ], + 'header/header': [ + ERROR, + 'block', + [ + '*', + ' * Copyright (c) Flashbots Ltd. and its affiliates.', + ' *', + ' * This source code is licensed under the MIT license found in the', + ' * LICENSE file in the root directory of this source tree.', + ' ', + ], + ], + 'import/no-unresolved': [ERROR, {ignore: ['^@docusaurus', '@theme']}], + 'import/no-extraneous-dependencies': [ERROR, {includeTypes: true}], + 'react/require-default-props': [ + WARNING, + { + functions: 'defaultArguments', + }, + ], + 'react/jsx-filename-extension': [ + WARNING, + {extensions: ['.js', '.jsx', '.ts', '.tsx']}, + ], + "react/jsx-props-no-spreading": OFF, + }, + settings: { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + 'import/resolver': { + typescript: {}, + }, + // optional, if you want to lint code blocks at the same time + 'mdx/code-blocks': true, + // optional, if you want to disable language mapper, set it to `false` + // if you want to override the default language mapper inside, you can + // provide your own + 'mdx/language-mapper': { + typescript: '@typescript-eslint/parser', + ts: '@typescript-eslint/parser', + javascript: 'espree', + js: 'espree', + }, + }, + overrides: [ + { + files: ['*.mdx'], + extends: ['plugin:mdx/overrides'], + }, + ], +}; diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..78cc8f64 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# they will be requested for review when someone opens a pull request. +* @odysseus0 @sketsdever @zeroXbrock @sukoneck diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..b206ac8b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "yarn" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + groups: + dev-dependencies: + patterns: + - "*" diff --git a/.github/workflows/algolia.yml.txt b/.github/workflows/algolia.yml.txt new file mode 100644 index 00000000..af940cb8 --- /dev/null +++ b/.github/workflows/algolia.yml.txt @@ -0,0 +1,25 @@ +name: Vercel -> Algolia Crawler (push on main) +on: + push: + branches: [ main ] + +jobs: + algolia_recrawl: + name: Algolia Recrawl + runs-on: ubuntu-latest + steps: + # checkout this repo + - name: Checkout Repo + uses: actions/checkout@v2 + + - name: Vercel-MAIN => Algolia crawler creation and recrawl on preview (Push on Main branch) + uses: algolia/algoliasearch-crawler-github-actions@v1 + id: crawler_push + with: + crawler-user-id: ${{ secrets.ALGOLIA_CRAWLER_USER_ID }} + crawler-api-key: ${{ secrets.ALGOLIA_CRAWLER_API_KEY }} + algolia-app-id: ${{ secrets.ALGOLIA_APP_ID }} + algolia-api-key: ${{ secrets.ALGOLIA_SEARCH_API_KEY }} + crawler-name: 'flashbots' + site-url: 'https://docs.flashbots.net/' + override-config: true \ No newline at end of file diff --git a/.github/workflows/broken-link-check-cron.yml.txt b/.github/workflows/broken-link-check-cron.yml.txt new file mode 100644 index 00000000..e1b833e5 --- /dev/null +++ b/.github/workflows/broken-link-check-cron.yml.txt @@ -0,0 +1,16 @@ +name: Check for broken links (cron) + +on: + workflow_dispatch: + schedule: + - cron: '0 10 * * *' + +jobs: + check-for-broken-links: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-node@v1 + with: + node-version: '16.x' + - run: npm install -g linkinator + - run: linkinator https://docs.flashbots.net --recurse --timeout 3000 --concurrency 10 --retry -s https://dune.com/ChainsightAnalytics,'https://.*etherscan.io/tx.*','https://twitter.com.*/','https://.*imgur.com.*/' diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index 98ecb5fc..1e88d3a6 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -1,28 +1,31 @@ name: PR Tests -on: +on: + push: + branches: + - main pull_request: - branches: "staging" jobs: - build: - if: github.event_name != 'push' + build-and-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 with: - node-version: '12.x' - - name: Test Build + node-version: '18.x' + - name: Test build env: - TARGET_URL: "http://not-docs.flashbots.net/" - BASE_URL: "/docs/" + TARGET_URL: "https://docs.flashbots.net/" + BASE_URL: "/" + ALGOLIA_APP_ID: "example" + ALGOLIA_SEARCH_API_KEY: "example" + ALGOLIA_INDEX_NAME: "example" run: | - if [ -e yarn.lock ]; then yarn install --frozen-lockfile - elif [ -e package-lock.json ]; then - npm ci - else - npm i - fi - npm run build + yarn build + # - name: Check for broken links + # run: | + # cd build + # npm install -g linkinator + # linkinator "**/*.html" --recurse --timeout 3000 --concurrency 10 --retry -s https://dune.com/ChainsightAnalytics,'https://.*etherscan.io/.*','https://twitter.com.*/','https://.*imgur.com.*/' diff --git a/.github/workflows/production-deploy.yml b/.github/workflows/production-deploy.yml deleted file mode 100644 index c6674ba4..00000000 --- a/.github/workflows/production-deploy.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Production Deploy - -on: - push: - branches: [main] - -jobs: - checks: - if: github.event_name != 'push' - runs-on: ubuntu-latest - environment: production - steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Test Build - run: | - if [ -e yarn.lock ]; then - yarn install --frozen-lockfile - elif [ -e package-lock.json ]; then - npm ci - else - npm i - fi - npm run build - gh-release: - if: github.event_name != 'pull_request' - runs-on: ubuntu-latest - environment: - name: production - url: docs.flashbots.net - steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - uses: webfactory/ssh-agent@v0.5.0 - with: - ssh-private-key: ${{ secrets.GH_PAGES_DEPLOY }} - - name: Release to GitHub Pages - env: - USE_SSH: true - GIT_USER: git - CURRENT_BRANCH: ${{ secrets.CURRENT_BRANCH }} - DEPLOYMENT_BRANCH: ${{ secrets.DEPLOYMENT_BRANCH }} - TARGET_URL: ${{ secrets.TARGET_URL }} - BASE_URL: ${{ secrets.BASE_URL }} - run: | - git config --global user.email "actions@github.com" - git config --global user.name "gh-actions" - if [ -e yarn.lock ]; then - yarn install --frozen-lockfile - elif [ -e package-lock.json ]; then - npm ci - else - npm i - fi - npm run deploy diff --git a/.gitignore b/.gitignore index 3fd24114..7863ca11 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,9 @@ yarn-debug.log* yarn-error.log* node_modules -.env \ No newline at end of file +.env +.vercel +.env*.local + +.idea/ +.eslintcache diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 00000000..b25a96cf --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,8 @@ +{ + "*.{js,jsx,ts,tsx,mjs}": ["eslint --fix"], + "*.css": ["stylelint --allow-empty-input --fix"], + "*": [ + "prettier --ignore-unknown --write", + "cspell --no-must-find-files --no-progress" + ] +} diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..3f430af8 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v18 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..d3ba7ed7 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,24 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +node_modules + +.env +.vercel \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..b2ff9852 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,10 @@ +{ + "arrowParens": "always", + "bracketSpacing": false, + "bracketSameLine": true, + "printWidth": 80, + "proseWrap": "never", + "singleQuote": true, + "trailingComma": "all", + "plugins": ["prettier-plugin-tailwindcss"] +} diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 00000000..d36c946b --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,4 @@ +# Stylelint runs on everything by default; we only lint CSS files. +* +!*/ +!*.css diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 00000000..dba9dd23 --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,19 @@ +module.exports = { + extends: ['stylelint-config-standard', 'stylelint-config-prettier'], + rules: { + 'at-rule-no-unknown': [ + true, + { + ignoreAtRules: [ + 'tailwind', + 'apply', + 'variants', + 'responsive', + 'screen', + ], + }, + ], + 'declaration-block-trailing-semicolon': null, + 'no-descending-specificity': null, + }, +}; diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..2afab388 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,20 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + "recommendations": [ + "streetsidesoftware.code-spell-checker", + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "stylelint.vscode-stylelint", + "EditorConfig.EditorConfig", + "Gruntfuggly.todo-tree", + "github.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "GitHub.remotehub", + "eamodio.gitlens", + "unifiedjs.vscode-mdx", + "christian-kohler.npm-intellisense", + "christian-kohler.path-intellisense", + "bradlc.vscode-tailwindcss", + ], + "unwantedRecommendations": [] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..9926ef31 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.fixAll.stylelint": "explicit" + }, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "css.validate": false, + "scss.validate": false, + "javascript.validate.enable": false, + "typescript.validate.enable": true, + "javascript.suggest.paths": false, + "typescript.suggest.paths": false +} diff --git a/LICENSE b/LICENSE index 10fabd90..e5bd22a7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,395 +1,21 @@ -Attribution 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution 4.0 International Public License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution 4.0 International Public License ("Public License"). To the -extent this Public License may be interpreted as a contract, You are -granted the Licensed Rights in consideration of Your acceptance of -these terms and conditions, and the Licensor grants You such rights in -consideration of benefits the Licensor receives from making the -Licensed Material available under these terms and conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - d. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - e. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - f. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - g. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - h. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - i. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - j. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - k. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - 4. If You Share Adapted Material You produce, the Adapter's - License You apply must not prevent recipients of the Adapted - Material from complying with this Public License. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material; and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public licenses. -Notwithstanding, Creative Commons may elect to apply one of its public -licenses to material it publishes and in those instances will be -considered the “Licensor.” The text of the Creative Commons public -licenses is dedicated to the public domain under the CC0 Public Domain -Dedication. Except for the limited purpose of indicating that material -is shared under a Creative Commons public license or as otherwise -permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the public -licenses. - -Creative Commons may be contacted at creativecommons.org. +MIT License + +Copyright (c) Flashbots Ltd. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LICENSE-docs b/LICENSE-docs new file mode 100644 index 00000000..c40295db --- /dev/null +++ b/LICENSE-docs @@ -0,0 +1,386 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public +licenses to material it publishes and in those instances will be +considered the “Licensor.” The text of the Creative Commons public +licenses is dedicated to the public domain under the CC0 Public Domain +Dedication. Except for the limited purpose of indicating that material +is shared under a Creative Commons public license or as otherwise +permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the public +licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/README.md b/README.md index a5264822..eb2d24b3 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,17 @@ # Website -This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator. +This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator. ## Installation +Use Node.js v18+ + +Note: if you want to install the node packages from within a Docker container (recommended for security), then you can start it like this: + +```bash +docker run -p 3000:3000 --rm -it -w /mnt -v $(pwd):/mnt node:18 /bin/bash +``` + First create a copy of the environment file `.env.template` in the root of the codebase and rename it to `.env` Then run the following: @@ -14,11 +22,18 @@ yarn install ## Local Development +First create a local `.env` file to fill in env variable placeholders necessary for setting up the development. Note that these are merely placeholders. + +```sh +cp .env.template .env +``` +Then run the below command to start a local development server (and may open up a browser window). Some changes are reflected live without having to restart the server. + ```console yarn start ``` -This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. +You can open the local docs at [http://localhost:3000/](http://localhost:3000/) ## Build @@ -30,8 +45,6 @@ This command generates static content into the `build` directory and can be serv ## Deployment -```console -GIT_USER= USE_SSH=true yarn deploy -``` +Create a PR and once merged, Github actions automatically deploy it. -If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. +The docs use Vercel for hosting, and deployment is done by Vercel on any merge into the master branch. diff --git a/docs/brand-assets.mdx b/docs/brand-assets.mdx new file mode 100644 index 00000000..17d21412 --- /dev/null +++ b/docs/brand-assets.mdx @@ -0,0 +1,7 @@ +--- +title: Brand Assets +--- + +import BrandAssets from "@site/src/components/BrandAssets/index.tsx"; + + \ No newline at end of file diff --git a/docs/cheatsheet.mdx b/docs/cheatsheet.mdx index cedc91c7..ed138534 100644 --- a/docs/cheatsheet.mdx +++ b/docs/cheatsheet.mdx @@ -1,5 +1,5 @@ --- -title: docs cheatsheet +title: Docs Cheatsheet --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/docs/code-of-conduct.mdx b/docs/code-of-conduct.mdx index bdba787c..ba9f761e 100644 --- a/docs/code-of-conduct.mdx +++ b/docs/code-of-conduct.mdx @@ -1,10 +1,10 @@ --- -title: code of conduct +title: Code of Conduct --- At Flashbots we contribute with the larger free software community to illuminate the dark forest. -You are welcome here <3. +You are welcome here \<3. We just ask you to be nice. Please start by reading our code of conduct. @@ -69,9 +69,9 @@ representative at an online or offline event. #### Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement writing an -email to leo@flashbots.net or contacting elopio#8526 in -[Discord](https://discord.com/invite/7hvTycdNcK). +reported to the community leaders responsible for enforcement through +emailing fredrik@flashbots.net or contacting Fred in +[Discord](https://discord.gg/flashbots). All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the diff --git a/docs/community-tools.mdx b/docs/community-tools.mdx index cfc7cf81..219a037b 100644 --- a/docs/community-tools.mdx +++ b/docs/community-tools.mdx @@ -1,25 +1,27 @@ --- -title: community tools +title: Community Tools --- -### [Flashbots Bundle Explorer](http://flashbots-explorer.marto.lol/) +### [DotPics Info](https://dotpics.info/) -- Inspect bundles (bundle merging supported!) -- Search by block number -- Shareable permalinks (e.g. https://flashbots-explorer.marto.lol/?block=12506647) +- A collection of interactive dashboards of the MEV-Boost ecosystem. -[![Flashbots Bundle Explorer](/img/bundle-explorer.png)](http://flashbots-explorer.marto.lol/) +### [MEV Data by EigenPhi](https://eigenphi.io/) -### [flashbots.tools](https://flashbots.tools/) +- Analytical explorers detailing MEV and liquidity on-chain data. -Simple frontend to interface with https://github.com/flashbots +### [libMEV](https://libmev.com/) -![Flashbots Tools](/img/flashbots-tools.png) +- A living dashboard with MEV searcher data. -### [zeneth](https://github.com/ScopeLift/zeneth) +### [Ethereum Block Value Analytics](https://payload.de/data/) -[![Zeneth](/img/zeneth.png)](https://youtu.be/lTivZBhqltY) +- Transaction pool, value over time, and builder bids of Ethereum block. -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. +### [MEV-Boost Dashboard](https://dune.com/ChainsightAnalytics/mev-after-ethereum-merge) -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. +- Overview of MEV-Boost adoption and profitability of proposers and block builders. + +### [MEV-Boost Relay & Builder Stats](https://www.relayscan.io/) + +- Ethereum MEV-Boost Relay Monitoring. diff --git a/docs/contribution-guide.mdx b/docs/contribution-guide.mdx index 8f72a6af..109e048e 100644 --- a/docs/contribution-guide.mdx +++ b/docs/contribution-guide.mdx @@ -1,5 +1,5 @@ --- -title: docs contribution guide +title: Docs Contribution Guide --- Thank you for your interest in adding to our knowledge base! @@ -27,10 +27,10 @@ We've created a simple cheatsheet file with examples of every heading, code bloc - the render bot will comment a link on your PR others can use to look at the version of the staging-docs website with your PR implemented [eg.](https://github.com/flashbots/docs/pull/23) **Step 4:** Changes to staging branch (PRs) are reviewed and merged by *docs* admins -- after review, PRs are merged to the staging branch and your changes are now deployed live to the [staging docs website](https://docs-staging.flashbots.net/) +- after review, PRs are merged to the staging branch and your changes are now deployed live to the staging docs website **Step 5:** Once enough changes have been collected/time is right, staging branch is merged into main branch by *docs* admins -- changes are now deployed live to the [docs website](https://docs.flashbots.net/) +- changes are now deployed live to the [docs website](/) ## Docusaurus-specific considerations There's a couple things to be aware of when adding your own `*.md` files to our codebase: diff --git a/docs/flashbots-auction/advanced/bundle-cancellations.mdx b/docs/flashbots-auction/advanced/bundle-cancellations.mdx new file mode 100644 index 00000000..2345706b --- /dev/null +++ b/docs/flashbots-auction/advanced/bundle-cancellations.mdx @@ -0,0 +1,51 @@ +--- +title: bundle cancellations +--- + +Bundle cancellations are currently deployed to our mainnet staging environment: `https://relay-staging.flashbots.net`. You must send both bundles and cancellations to this endpoint for it to be successful. + +This staging environment is limited to sending and cancelling bundles, and +will only simulate bundles targeting currently built and the next blocks. The bundles make it to our staging builder (`0x81babe`) and you should see the bundles landing on mainnet as you would be using the production endpoint. + +### Understanding bundle cancellations + +Bundles can be replaced and canceled using a unique identifier (`replacementUuid`) assigned to a bundle at the time of submission. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendBundle", + "params": [ + { + txs, + blockNumber, + minTimestamp, + maxTimestamp, + revertingTxHashes, + replacementUuid, // UUIDv4 to uniquely identify submission + } + ] +} +``` + +### Replacing bundles + +To replace a bundle, send the new bundle via `eth_sendBundle` with the same `replacementUuid` as the bundle you want to replace. + +### Canceling bundles + +Canceling a bundle will prevent Flashbots builders from including it on-chain. To cancel a bundle, call the [`eth_cancelBundle`](/flashbots-auction/advanced/rpc-endpoint#eth_cancelbundle) endpoint, or use the `cancelBundle` function in your preferred [Flashbots library](/flashbots-auction/libraries/bundle-relay). + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_cancelBundle", + "params": [ + { + replacementUuid, // UUIDv4 to uniquely identify submission + } + ] +} +``` diff --git a/docs/flashbots-auction/advanced/bundle-pricing.md b/docs/flashbots-auction/advanced/bundle-pricing.md new file mode 100644 index 00000000..e6d2ba8c --- /dev/null +++ b/docs/flashbots-auction/advanced/bundle-pricing.md @@ -0,0 +1,36 @@ +--- +title: Bundle Pricing +--- + +## Understanding 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 _the Flashbots block builder is designed to include the most profitable transactions possible in the blocks it builds_. + +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. + +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. + +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. + +## Bundle ordering formula + +The Flashbots builder employs a new algorithm aimed at maximizing block profitability. This new approach brings about several significant changes that searchers need to understand: + +* 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? + +There could be two potential reasons why your bundles are not being included. The first reason to consider is that the gas price of your bundles might not be higher than that at the tail end of a block. It's recommended to analyze the gas price your bundles are offering by initially simulating the bundles and observing the difference in the coinbase and the gas consumed. If this value is found to be lower than the tail end of recent blocks, it would be necessary to increase your gas price accordingly. + +Alternatively, your bundles may not be included due to competition with other searchers targeting the same opportunities. These competitors might be offering a higher gas price than you. To address this, first simulate your bundles to check the gas price they are offering. Log the amount you are paying for a specific opportunity in a specific block. diff --git a/docs/flashbots-auction/advanced/co-locate.mdx b/docs/flashbots-auction/advanced/co-locate.mdx new file mode 100644 index 00000000..917ddf85 --- /dev/null +++ b/docs/flashbots-auction/advanced/co-locate.mdx @@ -0,0 +1,7 @@ +--- +title: Co-locate with Flashbots Builder +--- + +For searchers who want to optimize the latency of their bundle submission, they can choose to co-locate with Flashbots Builders. + +The Flashbots Builder is located in Ohio, USA. Specifically, it is located in the AWS `us-east-2` region. diff --git a/docs/flashbots-auction/searchers/advanced/coinbase-payment.mdx b/docs/flashbots-auction/advanced/coinbase-payment.mdx similarity index 68% rename from docs/flashbots-auction/searchers/advanced/coinbase-payment.mdx rename to docs/flashbots-auction/advanced/coinbase-payment.mdx index 3216a9f4..db518d18 100644 --- a/docs/flashbots-auction/searchers/advanced/coinbase-payment.mdx +++ b/docs/flashbots-auction/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). +For more information on how coinbase transfers are priced see the [bundle pricing page](/flashbots-auction/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 accommodate 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/advanced/eip1559.mdx b/docs/flashbots-auction/advanced/eip1559.mdx new file mode 100644 index 00000000..3f29f569 --- /dev/null +++ b/docs/flashbots-auction/advanced/eip1559.mdx @@ -0,0 +1,79 @@ +--- +title: EIP-1559 Support +--- + +EIP-1559 is an upgrade to the Ethereum network that changes how you pay for transactions. It introduces a base fee that varies depending on the network demand, and a priority fee that you can set to get faster confirmation. The base fee is burned, while the priority fee goes to the miner who includes your transaction in a block. Flashbots, starting from [mev-geth v1.10.5-mev-0.3.0](https://github.com/flashbots/mev-geth/releases/tag/v1.10.5-mev0.3.0), has integrated support for EIP-1559 transactions. + +While users of the legacy transaction type don't need to make any configuration changes, they should be aware that it's now mandatory to include a `gasPrice` that is at least equal to the base fee. Coinbase transfer can still be used to incentivize faster inclusion, but it cannot be used to bypass the base fee requirement. + +## Legacy Transaction example + +Below is an example of signing bundles with a legacy transaction: + +```js +const signedTransactions = await flashbotsProvider.signBundle([ + { + signer: authSigner, + transaction: { + to: "0xf1a54b075fb71768ac31b33fd7c61ad8f9f7dd18", + gasPrice: 10, + gasLimit: 33000, + chainId: 5, + value: 0, + }, + }, +]); +``` + +The full amount of `gasPrice` will be consumed first to clear the base fee, and the remaining will be used as priority fee. + +## EIP-1559 Transaction example + +Below is an example of signing bundles with EIP-1559 transactions (note: `chainId` is a required attribute for 1559 or type2 transaction): + +```js +const block = await provider.getBlock("latest"); +const maxBaseFeeInFutureBlock = + FlashbotsBundleProvider.getMaxBaseFeeInFutureBlock(block.baseFeePerGas, 1); +const priorityFee = BigNumber.from(2).pow(9); +const signedTransactions = await flashbotsProvider.signBundle([ + { + signer: authSigner, + transaction: { + to: "0xf1a54b075fb71768ac31b33fd7c61ad8f9f7dd18", + type: 2, + maxFeePerGas: priorityFee.add(maxBaseFeeInFutureBlock), + maxPriorityFeePerGas: priorityFee, + gasLimit: 33000, + chainId: 5, + value: 0, + }, + }, +]); +``` + +Here the priorityFee is set to 2 Gwei, and the maxFeePerGas is set to be exactly equal to the max base fee in the next block plus the priority fee. + +## FAQ + +### Can a transaction specify `maxFeePerGas=0`? + +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 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 and will not appear on chain. + +However, with the new requirement for searchers to provide a gas price that meets the `base fee` for each transaction, successfully included bundle transactions may end up in the mempool following block re-organizations. If `gasPrice=0` is used, re-organized transactions are swiftly dropped from the gossip network, making it unlikely for them to appear in a future block unless reintroduced by another searcher. Transactions that pay at least the base fee will remain in the mempool and have a higher chance of appearing in future blocks, potentially conflicting with expectations regarding reverting transactions. + +### How can I send a transaction from an account with 0 ETH, like one with a malicious `sweeper` running against it? + +We have a working example of how to accomplish this in our [Sponsored Transaction Github Repository](https://github.com/flashbots/searcher-sponsored-tx/), which has been updated to work with EIP-1559. + +### Where can I learn more about EIP-1559? + +[EIP-1559 Hackmd Cheat Sheet](https://hackmd.io/@q8X_WM2nTfu6nuvAzqXiTQ/1559-wallets) diff --git a/docs/flashbots-auction/advanced/gas-fee-refunds.md b/docs/flashbots-auction/advanced/gas-fee-refunds.md new file mode 100644 index 00000000..12a0af4e --- /dev/null +++ b/docs/flashbots-auction/advanced/gas-fee-refunds.md @@ -0,0 +1,78 @@ +--- +title: Gas Fee Refunds +--- + +## Introduction + +Searchers and private transaction API users are automatically eligible to receive gas fee refunds. If a bundle can be included on chain for a lower price, you are eligible to receive a refund. + +Gas fee refunds do not change how bundles are executed and searchers do not need to make any changes to be eligible for them. + +## Where do refunds come from + +Gas fee refunds include both priority fees and coinbase transfers. + +In an optimal case, searchers are refunded the difference between their bid and the bid of the next-best bundle or transaction targeting the same state. Ie. the refund effectively results in the searcher paying the second price. In practice, searchers will receive some fraction of this amount depending on how much profit BuilderNet makes. + +## Which bundles receive refunds + +Flashbots provides refunds for bundles in blocks landed by [BuilderNet](https://buildernet.org/). Whether a bundle receives a refund depends on a few factors that vary from block to block: +* How much network congestion and competition there was +* Whether BuilderNet made a profit and how much +* How much the specific bundle contributed to the value of the block +* If the bundle was sent directly to Flashbots or BuilderNet, or shared with other block builders by the searcher + +Note that transactions seen in the public mempool are excluded and bundles containing only public mempool transactions do not receive refunds. + +## How to maximize both refunds and speed + +Transactions which are sent directly to the Flashbots Bundle Relay or BuilderNet, and not multiplexed _by the searcher_ to other block builders, are likely to receive higher refunds. This is because they increase the profit of BuilderNet which is used to provide refunds. + +BuilderNet does not land 100% of blocks. In order to land bundles in all blocks, searchers can ask Flashbots to share their bundles with other block builders in cases where BuilderNet does not win a block. Flashbots will automatically share with all specified builders on the searcher's behalf. + +### Smart multiplexing + +To share bundles with other builders, add the `builders` field to your `eth_sendBundle` request. The `builders` field accepts a list of strings which correspond to the "name" tags of [registered builders](https://github.com/flashbots/dowg/blob/main/builder-registrations.json). + +All `eth_sendBundle` requests are shared with BuilderNet. They are multiplexed to other block builders at the end of the slot if BuilderNet determines it will not win that block. + +For example: + +``` +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendBundle", + "params": [ + { + "txs": ["0x123abc...", "0x456def..."], + "blockNumber": "0xb63dcd", + "minTimestamp": 0, + "maxTimestamp": 1615920932 + "builders": ["builder0x69", "beaverbuild.org"] + } + ] +} +``` + +Searchers can also use `mev_sendBundle` to multiplex bundles if they prefer. This method is more complex and not necessary for gas fee refunds. + +_Note: Smart multiplexing has a 1% rate of false positives, meaning that in 1% of MEV-Boost blocks there is a risk that searcher bundles will not be landed._ + +## How are refunds calculated + +BuilderNet uses a refund rule to retroactively calculate refunds for all bundles landed in its blocks. For more information, see the [BuilderNet docs](https://buildernet.org/docs/refunds). + +## Who receives refunds + +By default, the refund recipient is the signer used on the `eth_sendBundle`, `mev_sendBundle`, or `eth_sendPrivateTransaction` request. You can delegate your recipient to a different address using the `flashbots_setFeeRefundRecipient` API. + +## How to track refunds + +Refunds are tracked from a start date of July 8, 2024. Refunds are sent to recipients in batches, the first batch originated from the Flashbots builder address `0xdf99A0839818B3f120EBAC9B73f82B617Dc6A555` while newer batches originate from [`refunds.buildernet.eth`](https://etherscan.io/address/0x62a29205f7ff00f4233d9779c210150787638e7f). + +Track your refunds using the [`flashbots_getFeeRefundTotalsByRecipient`](/flashbots-auction/advanced/rpc-endpoint#flashbots_getfeerefundtotalsbyrecipient) RPC method or the [refund dashboard](https://app.hex.tech/9eb1e790-53f7-4c16-be76-4a22c1aa7d17/app/0c2d34ef-1304-481a-b3d6-b773ce9e0e19/latest) on Dune. + +## Distributed refunds + +The on-chain transactions corresponding to distributed refunds can be viewed with this Dune query: [https://dune.com/queries/4398421](https://dune.com/queries/4398421) diff --git a/docs/flashbots-auction/advanced/multiplexing.mdx b/docs/flashbots-auction/advanced/multiplexing.mdx new file mode 100644 index 00000000..0d168556 --- /dev/null +++ b/docs/flashbots-auction/advanced/multiplexing.mdx @@ -0,0 +1,15 @@ +--- +title: Send transaction/bundle to multiple builders +--- + +import Builders from '../../specs/mev-share/_builders.mdx'; + +Some users might want to send their transactions or bundles to multiple builders for various reasons. The ability to multiplex is supported by our APIs. + +If you are using [`mev_sendBundle`](https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#mev_sendbundle) to send bundles, or [`eth_sendPrivateTransaction`](https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendprivatetransaction) to send transactions, specify the builders you want to multiplex to in the `privacy.builders` parameter. + +If you are using [`eth_sendBundle`](https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle) to send bundles, specify the builders you want to multiplex to in the `builders` parameter. + +Below is the list of builders that you can multiplex to: + + diff --git a/docs/flashbots-auction/advanced/reputation.md b/docs/flashbots-auction/advanced/reputation.md new file mode 100644 index 00000000..da35c009 --- /dev/null +++ b/docs/flashbots-auction/advanced/reputation.md @@ -0,0 +1,34 @@ +--- +title: Searcher Reputation +--- + +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. Otherwise, both queues are identical. + +## Reputation scoring + +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 `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 builder to adapt in periods of high demand and maintain high reliability for top searchers. + +## Building reputation + +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 bundles/transactions which have a high likelihood of landing on chain. diff --git a/docs/flashbots-auction/advanced/rpc-endpoint.mdx b/docs/flashbots-auction/advanced/rpc-endpoint.mdx new file mode 100644 index 00000000..957d9f3d --- /dev/null +++ b/docs/flashbots-auction/advanced/rpc-endpoint.mdx @@ -0,0 +1,885 @@ +--- +title: JSON-RPC Endpoints +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import Hints from '../../specs/mev-share/HintsTable'; +import Builders from '../../specs/mev-share/_builders.mdx'; +import SendBundleSpec from '../../specs/mev-share/_mev_sendBundle.mdx'; +import SimBundleSpec from '../../specs/mev-share/_mev_simBundle.mdx'; + +## Interact directly with the Flashbots RPC endpoint + +Advanced users can interact with the RPC endpoint at `relay.flashbots.net`, or one of the testnet URLs below. + +### Bundle Relay URLS + +| Network | URL | +| -------- | ---------------------------------------- | +| Mainnet | `https://relay.flashbots.net` | +| Sepolia | `https://relay-sepolia.flashbots.net` | + +The API provides JSON-RPC methods for interfacing with Flashbots. Below are some of the restrictions: + +- There is a rate limit of 10,000 requests per second per IP +- Each bundle (`txs` parameter) can contain at most 100 transactions and have a size limit of 300,000 bytes + +Each method is documented below. + +### eth_sendBundle + +`eth_sendBundle` can be used to send your bundles to the Flashbots builder. The `eth_sendBundle` RPC has the following payload format: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendBundle", + "params": [ + { + 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 maximum timestamp for which this bundle is valid, in seconds since the unix epoch + revertingTxHashes, // (Optional) Array[String], A list of tx hashes that are allowed to revert + replacementUuid, // (Optional) String, UUID that can be used to cancel/replace this bundle + builders, // (Optional) Array[String], A list of [registered](https://github.com/flashbots/dowg/blob/main/builder-registrations.json) block builder names to share the bundle with + } + ] +} +``` + +example: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendBundle", + "params": [ + { + "txs": ["0x123abc...", "0x456def..."], + "blockNumber": "0xb63dcd", + "minTimestamp": 0, + "maxTimestamp": 1615920932 + } + ] +} +``` + +example response: + +```json +{ + "jsonrpc": "2.0", + "id": "123", + "result": { + "bundleHash": "0x2228f5d8954ce31dc1601a8ba264dbd401bf1428388ce88238932815c5d6f23f" + } +} +``` + +If `builders` are specified, the response will include an additional `smart` field. + +example with `builders`: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendBundle", + "params": [ + { + "txs": ["0x123abc...", "0x456def..."], + "blockNumber": "0xb63dcd", + "minTimestamp": 0, + "maxTimestamp": 1615920932, + "builders": ["builder0x69"] + } + ] +} +``` + +example response: + +```json +{ + "jsonrpc": "2.0", + "id": "123", + "result": { + "bundleHash": "0x2228f5d8954ce31dc1601a8ba264dbd401bf1428388ce88238932815c5d6f23f", + "smart": "true" + } +} +``` + +### mev_sendBundle + +`mev_sendBundle` uses a new bundle format to send bundles to MEV-Share. See the [Understanding Bundles](/flashbots-mev-share/searchers/understanding-bundles) page for more information, or check out the [Sending Bundles](/flashbots-mev-share/searchers/sending-bundles) page for a short guide. Note that as of October 20, 2025, a bundle can now only contain one backrun transaction. + + +example request: + +```json +{ + "params": [ + { + "version": "v0.1", + "inclusion": { + "block": "0x8b8da8", + "maxBlock": "0x8b8dab" + }, + "body": [ + { + "hash": "0x24e6e999b8abf2c4df46e8a02516c0983043039a5a54f89fa87274427ce64798" + }, + { + "tx": "0x02f880058201d685e9103fda0085e9103fda368255f0940000c335bc9d5d1af0402cad63fa7f258363d71a8092696d206261636b72756e6e69696969696e67c080a0c5058ccf5759e29d4ad28e038f632a9b6269bbb0644c61447e0f14d56c453d73a048e877ee621c4b6be1234a8ad84379e80d45b288a7271e2b1aede7a04f06fd98", + "canRevert": false + } + ], + "validity": { + "refund": [], + "refundConfig": [] + } + } + ], + "method": "mev_sendBundle", + "id": 1, + "jsonrpc": "2.0" +} +``` + +example response: + +```json +{ + "bundleHash": "0x7d6e491ab67aee5f4b75321c936bf05664d2d9b234fd67083e46bd43bb42f383" +} +``` + +### eth_callBundle + +`eth_callBundle` can be used to simulate a bundle against a specific block number, including simulating a bundle at the top of the next block. The `eth_callBundle` RPC has the following payload format: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_callBundle", + "params": [ + { + 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 + 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": [ + { + "txs": ["0x123abc...", "0x456def..."], + "blockNumber": "0xb63dcd", + "stateBlockNumber": "latest", + "timestamp": 1615920932 + } + ] +} +``` + +example response: + +```json +{ + "jsonrpc": "2.0", + "id": "123", + "result": { + "bundleGasPrice": "476190476193", + "bundleHash": "0x73b1e258c7a42fd0230b2fd05529c5d4b6fcb66c227783f8bece8aeacdd1db2e", + "coinbaseDiff": "20000000000126000", + "ethSentToCoinbase": "20000000000000000", + "gasFees": "126000", + "results": [ + { + "coinbaseDiff": "10000000000063000", + "ethSentToCoinbase": "10000000000000000", + "fromAddress": "0x02A727155aeF8609c9f7F2179b2a1f560B39F5A0", + "gasFees": "63000", + "gasPrice": "476190476193", + "gasUsed": 21000, + "toAddress": "0x73625f59CAdc5009Cb458B751b3E7b6b48C06f2C", + "txHash": "0x669b4704a7d993a946cdd6e2f95233f308ce0c4649d2e04944e8299efcaa098a", + "value": "0x" + }, + { + "coinbaseDiff": "10000000000063000", + "ethSentToCoinbase": "10000000000000000", + "fromAddress": "0x02A727155aeF8609c9f7F2179b2a1f560B39F5A0", + "gasFees": "63000", + "gasPrice": "476190476193", + "gasUsed": 21000, + "toAddress": "0x73625f59CAdc5009Cb458B751b3E7b6b48C06f2C", + "txHash": "0xa839ee83465657cac01adc1d50d96c1b586ed498120a84a64749c0034b4f19fa", + "value": "0x" + } + ], + "stateBlockNumber": 5221585, + "totalGasUsed": 42000 + } +} +``` + +### mev_simBundle + +`mev_simBundle` uses a new bundle format to simulate matched bundles on MEV-Share. See [mev-share spec](https://github.com/flashbots/mev-share/blob/main/specs) for more information. + + + +example request (sent after landing a bundle via `mev_sendBundle`): + +```json +{ + "params": [ + { + "inclusion": { + "block": "0x8b8da8", + "maxBlock": "0x8b8dab" + }, + "body": [ + { + "tx": "0x02f87b058201d5843b9aca00843b9aca368255f0940000c335bc9d5d1af0402cad63fa7f258363d71a808f696d20736861726969696969696e67c001a00d8d998fb0dc1e4da9b1de477acea54f185153d66d0af45a4ecfd20e453772baa07bd0ad1e1afb3f19749aaa5660f22859a6e485942346cd7186c024a5da747ada", + "canRevert": false + }, + { + "tx": "0x02f880058201d685e9103fda0085e9103fda368255f0940000c335bc9d5d1af0402cad63fa7f258363d71a8092696d206261636b72756e6e69696969696e67c080a0c5058ccf5759e29d4ad28e038f632a9b6269bbb0644c61447e0f14d56c453d73a048e877ee621c4b6be1234a8ad84379e80d45b288a7271e2b1aede7a04f06fd98", + "canRevert": false + } + ], + "version": "v0.1", + "validity": { + "refund": [], + "refundConfig": [] + } + }, + { + "parentBlock": "0x8b8da8" + } + ], + "method": "mev_simBundle", + "id": 1, + "jsonrpc": "2.0" +} +``` + +example response: + +```json +{ + "success": true, + "stateBlock": "0x8b8da8", + "mevGasPrice": "0x74c7906005", + "profit": "0x4bc800904fc000", + "refundableValue": "0x4bc800904fc000", + "gasUsed": "0xa620", + "logs": [{}, {}] +} +``` + +### eth_cancelBundle + +`eth_cancelBundle` is used to prevent a submitted bundle from being included on-chain. See [bundle cancellations](/flashbots-auction/advanced/bundle-cancellations) for more information. + +[`eth_cancelPrivateTransaction`](https://docs.alchemy.com/alchemy/apis/ethereum/eth_cancelPrivateTransaction/?a=fb) is also supported on [Alchemy](https://alchemy.com/?a=fb). + +:::caution +`replacementUuid` must have been set when bundle was submitted. +::: + +:::caution +When you cancel a bundle in Flashbots, the cancelled bundle is excluded from all future bids by the builder. However, there's no active adjustment to decrease the bid value on the relay for already placed bids. If the block value increases without your bundle, the bid might be replaced to reflect the new value. +::: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_cancelBundle", + "params": [ + { + replacementUuid, // UUIDv4 to uniquely identify submission + } + ] +} +``` + +### eth_sendPrivateTransaction + +`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-protect/additional-documentation/eth-sendPrivateTransaction) for more info. + +[`eth_sendPrivateTransaction`](https://docs.alchemy.com/reference/eth-sendprivatetransaction?a=fb) is also supported on [Alchemy](https://alchemy.com?a=fb). + +This method has the following JSON-RPC format: + +```typescript +{ + jsonrpc: "2.0", + id: string | number, + method: "eth_sendPrivateTransaction", + 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, // Sends transactions to all registered block builders, sets MEV-Share revenue share to 50% + privacy?: { // MEV-Share options; optional + hints?: Array< // data about tx to share w/ searchers on mev-share + "contract_address" | + "function_selector" | + "calldata" | + "logs" | + "hash" + >, + builders?: Array< // MEV-Share builders to exclusively receive bundles; optional + "default" | + "flashbots" + >, + }, + validity?: { + refund?: Array<{address, percent}> + } + } + }] +} +``` + +example request: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendPrivateTransaction", + "params": [ + { + "tx": "0x123abc...", + "maxBlockNumber": "0xcd23a0", + "preferences": { + "fast": true, + "privacy": { + "hints": ["calldata", "transaction_hash"], + "builders": ["default"] + }, + "validity": { + "refund": [{"address": "0xadd123", "percent": 50}] + } + } + } + ] +} +``` + +example response: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": "0x45df1bc3de765927b053ec029fc9d15d6321945b23cac0614eb0b5e61f3a2f2a" // tx hash +} +``` + +#### `privacy` + +By default, transactions are sent to the Flashbots MEV-Share Node with the default [Stable](/flashbots-protect/mev-refunds#stable-configuration) configuration. The `privacy` parameter allows you to specify your own privacy parameters. + +| Param | Type Info | Description | +| --- | --- | --- | +| `hint` | Array of strings | Each hint specifies which data about the transaction will be shared with searchers on mev-share. | +| `builders` | Array of strings | Builders to grant permission to include the transaction in a block. | + +**`hint`** + + + +**`builders`** + +Flashbots currently supports sending orderflow to the following block builders. This is subject to change over time. + + + +#### `validity` + +Validity is used to specify the address and percentage to pay refund from the backrun of this transaction. + +By default, the refund is paid to the signer of the transaction and 90% of the backrun value is sent to the user by default. + +If multiple refund addresses are specified, then the backrun value is split between them according to the percentage specified. For example, if refund is `[{address: addr1, percent: 10}, {address: addr1, percent: 20}]` then 10% of the backrun value is sent to `addr1` and 20% is sent to `addr2` and 70% of the backrun value is left to the builder. + +| Param | Type Info | Description | +| --- | --- | --- | +| `refund` | Array of objects | Each entry in the array specifies address that should receive refund from backrun and percent of the backrun value. | +| `refund[].address` | Address | Address that should receive refund. | +| `refund[].percent` | Number | Percentage of the total backrun value that this address should receive. | + +### eth_sendPrivateRawTransaction + +`eth_sendPrivateRawTransaction` behaves like [eth_sendPrivateTransaction](#eth_sendprivatetransaction) but its format is similar to that of [`eth_sendRawTransaction`](https://docs.alchemy.com/reference/eth-sendrawtransaction) + +This method has the following JSON-RPC format: + +```typescript +{ + jsonrpc: "2.0", + id: string | number, + method: "eth_sendPrivateRawTransaction", + params: [ + tx, // String, raw signed transaction + preferences?: { + fast: boolean, // Sends transactions to all registered block builders, sets MEV-Share revenue share to 50% + privacy?: { // MEV-Share options; optional + hints?: Array< // data about tx to share w/ searchers on mev-share + "contract_address" | + "function_selector" | + "calldata" | + "logs" | + "hash" + >, + builders?: Array< // MEV-Share builders to exclusively receive bundles; optional + "default" | + "flashbots" + >, + }, + validity?: { + refund?: Array<{address, percent}> + } + } + ] +} +``` + +example request: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendPrivateRawTransaction", + "params": ["0x123abc..."] +} +``` + +example response: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": "0x45df1bc3de765927b053ec029fc9d15d6321945b23cac0614eb0b5e61f3a2f2a" // tx hash +} +``` + +| Param | Type Info | Description | +| --- | --- | --- | +| `params[0]` | String | Raw signed transaction | +| `params[1]` | Object | Optional private tx preferences, see `preferences` in eth_sendPrivateTransaction. | + +### eth_cancelPrivateTransaction + +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 +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_cancelPrivateTransaction", + "params": [{ + txHash, // String, transaction hash of private tx to be cancelled + }] +} +``` + +example request: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_cancelPrivateTransaction", + "params": [ + { + "txHash": "0x45df1bc3de765927b053ec029fc9d15d6321945b23cac0614eb0b5e61f3a2f2a" + } + ] +} +``` + +example response: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": true // true if tx successfully cancelled, false if not +} +``` + +### flashbots_getFeeRefundTotalsByRecipient + +The `flashbots_getFeeRefundTotalsByRecipient` JSON-RPC method returns the total amount of fee refunds that have been earned by a specific address. Our refund process calculates these values weekly. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "flashbots_getFeeRefundTotalsByRecipient", + "params": [ + recipient, // String, the address to query for fee refunds + ] +} +``` + +The response contains three fields: + +```json +{ + "pending":"0x17812ea4fbbe314", + "received":"0x108d1b27b63a213", + "maxBlockNumber":"0x13ddb08" +} +``` + +- `pending`: the total amount of fee refunds that have been earned but not yet received by the recipient +- `received`: the total amount of fee refunds that have been received by the recipient +- `maxBlockNumber`: the highest block number for which fee refunds have been processed + +### flashbots_getFeeRefundsByRecipient + +The `flashbots_getFeeRefundsByRecipient` JSON-RPC method returns detailed information about [fee refunds](/flashbots-protect/gas-fee-refunds) that have been earned by a specific address. Our refund process usually calculates these values with a 4 hour delay. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "flashbots_getFeeRefundsByRecipient", + "params": [ + { + recipient, // String, the address to query for fee refunds + cursor, // [optional] String, the cursor to continue from + } + ] +} +``` + +Responses are paginated and contain the following fields: + +```json +{ + "refunds": [ + { + "hash": "0x...", + "amount": "0x...", + "blockNumber": "0x13ddaa4", + "status": "pending", + "recipient": "0x..." + }, + ... + ], + "cursor": "0x..." +} +``` + +The `"refunds"` field contains an array of per-order fee refunds, each with the following fields: + +- `hash`: the bundle hash or transaction hash associated with the fee refund +- `amount`: the amount of the fee refund, in wei +- `blockNumber`: the block number the order was contained in +- `status`: the status of the fee refund, either "pending" or "received" +- `recipient`: the address the fee refund is credited to, either the bundle signer or transaction sender + +The `"cursor"` field is only included if there are more fee refunds to fetch. To continue fetching fee refunds, include the cursor as the second argument in the next request. + +NOTE: This API currently only returns details for bundles included in block 20802497 and later. To see total fee refunds processed for a specific address since inception, use the `flashbots_getFeeRefundTotalsByRecipient` method. + +### flashbots_getFeeRefundsByBundle + +The `flashbots_getFeeRefundsByBundle` is similar to `flashbots_getFeeRefundsByRecipient` but returns result for the given bundle. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "flashbots_getFeeRefundsByBundle", + "params": [ + { + bundle_hash, // String, the hash of the bundle + } + ] +} +``` + +### flashbots_getFeeRefundsByBlock + +The `flashbots_getFeeRefundsByBlock` is similar to `flashbots_getFeeRefundsByRecipient` but returns result for the given block. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "flashbots_getFeeRefundsByBlock", + "params": [ + { + block_number, // String, hex-encoded block number (e.g. 0x15d0280) + } + ] +} +``` + + + +### flashbots_setFeeRefundRecipient + +The `flashbots_setFeeRefundRecipient` JSON-RPC method allows a user to "delegate" their [fee refunds](/flashbots-auction/advanced/gas-fee-refunds) to a specific wallet address. Two addresses must be provided, the first is the address associated with the signing key used to authenticate your request, while the second is the address to send refunds to. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "flashbots_setFeeRefundRecipient", + "params": [ + "0xD2824D2D7D6399a4b9A47F258B870D2AFb213948", + "0xa273A268CE96E54cF6a7D879B7d016F57E396F48" + ] +} +``` + +If the first address matches the authentication signature, then a response with `from` and `to` fields in the result will be returned: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "from":"0xd2824d2d7d6399a4b9a47f258b870d2afb213948", + "to":"0xa273a268ce96e54cf6a7d879b7d016f57e396f48" + } +} +``` + +If the signature is invalid or does not match the first address, an appropriate error will be returned instead. + +### buildernet_getDelayedRefunds + +The `buildernet_getDelayedRefunds` JSON-RPC method returns detailed information about delayed refunds. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "buildernet_getDelayedRefunds", + "params": [ + { + recipient, // String, the address that receives delayed refunds + blockRangeFrom, // [optional] String, hex-encoded block number for the start of the range (inclusive) + blockRangeTo, // [optional] String, hex-encoded block number for the end of the range (inclusive) + cursor, // [optional] String, the cursor to continue from + hash, // [optional] String, bundle hash; if provided, you must also set both blockRangeFrom and blockRangeTo + } + ] +} +``` + +Responses are paginated and contain the following fields: + +```json +{ + "refunds": [ + { + "hash": "0x...", + "amount": "0x...", + "blockNumber": "0x13ddaa4", + "status": "pending", + "recipient": "0x..." + }, + ... + ], + "nextCursor": "0x..." + "indexedUpTo": "0x..." +} +``` + +The `"refunds"` field contains an array of per-order fee refunds, each with the following fields: + +- `hash`: the bundle hash that generated delayed refund +- `amount`: the amount of the delayed refund, in wei +- `blockNumber`: the block number the order was contained in +- `status`: the status of the delayed refund, either "pending" or "received" +- `recipient`: the address the delayed refund is credited to + +The `"cursor"` field is only included if there are more delayed refunds to fetch, some data might be avaiable in the future. To continue fetching, include the cursor as the second argument in the next request. If response is empty but contains cursor retry later. + +`"indexedUpTo"` contains maximum block number for which delayed refunds are indexed + +### buildernet_getDelayedRefundTotalsByRecipient + +The `buildernet_getDelayedRefundTotalsByRecipient` JSON-RPC method returns the total amount of delayed refunds that have been earned by a specific address. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "buildernet_getDelayedRefundTotalsByRecipient", + "params": [{ + recipient, // String, the address to query for delayed refunds + blockRangeFrom, // [optional] String, hex-encoded block number for the start of the range (inclusive) + blockRangeTo, // [optional] String, hex-encoded block number for the end of the range (inclusive) + }] +} +``` + +The response contains three fields: + +```json +{ + "pending":"0x17812ea4fbbe314", + "received":"0x108d1b27b63a213", + "indexedUpTo":"0x13ddb08" +} +``` + +- `pending`: the total amount of fee refunds that have been earned but not yet received by the recipient +- `received`: the total amount of fee refunds that have been received by the recipient +- `indexedUpTo`: the highest block number for which delayed refunds have been processed + + +### flashbots_getMevRefundTotalByRecipient + +Returns the total amount of [MEV refunds](/flashbots-protect/mev-refunds) that have been paid to a specific recipient address. This API not require authentication. + +#### Request + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "flashbots_getMevRefundTotalByRecipient", + "params": ["0xDCDDAE87EDF1D9F62AE2F3A66EB2018ACD0B2508"] +} +``` + +#### Response + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "total": "0xeff5f44e097dcfac" + } +} +``` + +Note: The total is returned as a hexadecimal string representing the amount in wei. + +### flashbots_getMevRefundTotalBySender + +Returns the total amount of [MEV refunds](/flashbots-protect/mev-refunds) that have been generated on transactions or bundles from a specific sender address. The sender is the `tx.origin` for individual transactions or bundles of size 1, or the Flashbots signer for bundles of size > 1. It may be different from the recipient if the recipient has been delegated to another address. + +This API does not require authentication. + +#### Request + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "flashbots_getMevRefundTotalBySender", + "params": ["0xDCDDAE87EDF1D9F62AE2F3A66EB2018ACD0B2508"] +} +``` + +#### Response + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "total": "0x4a817c800" + } +} +``` + +### API Response + +- All method supports JSON-RPC standards for success response and not supported for error response(V2 methods are exceptions). +- V2 methods supports JSON-RPC standards for both success and error response. + +### Authentication + +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: :" --data '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}' https://relay.flashbots.net +``` + +Any valid ECDSA-secp256k1 key, like an arbitrary Ethereum key, can be used to sign the payload. The address associated with this key will be used by Flashbots to keep track of your [reputation](/flashbots-auction/advanced/reputation) 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: + + + + +```ts +import {Wallet, id} from 'ethers'; + +const privateKey = '0x1234'; +const wallet = new Wallet(privateKey); +const body = + '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}'; +const signature = wallet.address + ':' + wallet.signMessage(id(body)); +``` + + + + +```py +from web3 import Web3 +from eth_account import Account, messages + +body = '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}' +message = messages.encode_defunct(text=Web3.keccak(text=body).hex()) +signature = Account.from_key(private_key).address + ':' + Account.sign_message(message, private_key).signature.hex() +``` + + + + +```go +body := `{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}` +hashedBody := crypto.Keccak256Hash([]byte(body)).Hex() +sig, err := crypto.Sign(accounts.TextHash([]byte(hashedBody)), privKey) +signature := crypto.PubkeyToAddress(privKey.PublicKey).Hex() + ":" + hexutil.Encode(sig) +``` + + + diff --git a/docs/flashbots-auction/searchers/advanced/goerli-testnet.mdx b/docs/flashbots-auction/advanced/testnets.mdx similarity index 79% rename from docs/flashbots-auction/searchers/advanced/goerli-testnet.mdx rename to docs/flashbots-auction/advanced/testnets.mdx index b6b3b665..1a361664 100644 --- a/docs/flashbots-auction/searchers/advanced/goerli-testnet.mdx +++ b/docs/flashbots-auction/advanced/testnets.mdx @@ -1,20 +1,34 @@ --- -title: goerli testnet +title: Testnets --- -Flashbots operates a Goerli validator and searchers can test Flashbots by using it. Here's how to setup the Flashbots Bundle Provider in Ethers to use Goerli: +Flashbots operates on Sepolia so that searchers can test Flashbots without risking real funds. + +## Bundle Relay URLS + +| Network | URL | +| --- | --- | +| Mainnet | `https://relay.flashbots.net` | +| Sepolia | `https://relay-sepolia.flashbots.net` | + +## Examples + +Here's how to setup the Flashbots Bundle Provider in Ethers to use Goerli or Sepolia: ```js const provider = new ethers.getDefaultProvider("goerli"); +// uncomment the line below to use Sepolia +// const provider = new ethers.getDefaultProvider("sepolia"); const authSigner = new ethers.Wallet( '0x2000000000000000000000000000000000000000000000000000000000000000', provider ); - + const flashbotsProvider = await flashbots.FlashbotsBundleProvider.create( provider, authSigner, + // use "https://relay-sepolia.flashbots.net/" for Sepolia "https://relay-goerli.flashbots.net/", "goerli" ); @@ -35,7 +49,6 @@ const signedTransactions = await flashbotsProvider.signBundle([ value: 0, }, }, - // we need this second tx because flashbots only accept bundles that use at least 42000 gas. { signer: wallet, transaction: { diff --git a/docs/flashbots-auction/advanced/troubleshooting.mdx b/docs/flashbots-auction/advanced/troubleshooting.mdx new file mode 100644 index 00000000..dbebe0eb --- /dev/null +++ b/docs/flashbots-auction/advanced/troubleshooting.mdx @@ -0,0 +1,273 @@ +--- +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: + +``` +1. Any transaction failure within the bundle that isn't specified in the optional argument `revertingTxHashes` +2. Insufficient incentives (the sum of gas price and coinbase transfers) to compensate for the value of block space +3. Higher bids from competitors for the same opportunity +4. Late receipt of the bundle, preventing its inclusion in the target block +5. The validator for the target slot is not running mev-boost +``` + +Instead of relying on [Etherscan](https://etherscan.io) to examine the execution of your transaction, its on-chain status, and its comparison with competitors, you'll need a different approach with Flashbots. This is because Flashbots prevents failed transactions from appearing on the chain. For effective debugging, we highly recommend simulating your transactions, logging the results, and maintaining a record of all submitted data, including the complete bundle and its signed transactions. If you are a TEE searcher, you will receive logs with full transaction information at a 5 minute delay to help with troubleshooting and debugging. + +The issues listed above are arranged in the order of their priority for consideration. In the following sections, we will explore each issue in detail, providing guidance on how to identify and address them. While the examples provided assume the use of the [Flashbots Ethers Provider](https://github.com/flashbots/ethers-provider-flashbots-bundle), the [RPC calls are standard](/flashbots-auction/advanced/rpc-endpoint) and the suggested strategies can be easily adapted for use with [other providers](/flashbots-auction/libraries/golang). + +## Does your transaction work and pay enough? + +Covers: + +``` +1. Transaction failure (ANY within the bundle) +2. Incentives (gas price/coinbase transfers) not high enough to offset value of block space +``` + +The first two issues are grouped together as their causes, investigations, and solutions are closely related. Flashbots will not include a bundle if: + +1. A transaction within the bundle reverts, unless it's specified via the [optional argument `revertingTxHashes`](/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle) or it's uncled. +2. The [gas price is below the base fee](/flashbots-auction/advanced/eip1559#faq), as this would result in an invalid block if included. +3. The effective priority fee is not sufficient to offset the opportunity cost of using the block space for other unrelated transactions. For instance, if your bundle is paying a 1 Gwei priority fee, but the cheapest transaction in the block is paying 2 Gwei, the builder would benefit more from discarding 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: + +1. It operates on an array of _signed_ transactions, as opposed to a single unsigned transaction description. These transactions are executed sequentially, starting from the top of the specified block. Simulating with signed transactions minimizes discrepancies between how your system creates transactions and how they will be processed on-chain. For instance, it eliminates the possibility of using an incorrect `from` field when simulating a signed transaction. +2. It provides the gas used and the coinbase transfer for each transaction. The coinbase transfer is a factor in the effective gas price calculation. +3. It allows for the precise specification of the following arguments, enabling a more accurate simulation: + - State block number: This determines the values read from SLOADs. + - EVM block number: This determines the value returned from `block.number`. + - EVM timestamp: This determines the value returned from `block.timestamp`. + +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. + +```js +const signedTransactions = + await flashbotsProvider.signBundle(transactionBundle); +const simulation = await flashbotsProvider.simulate( + signedTransactions, + targetBlockNumber, + targetBlockNumber + 1, +); +console.log(JSON.stringify(simulation, null, 2)); +``` + +Output: + +```js +{ + "totalGasUsed": 98564, + "bundleHash": "0x9a6a9fa038343fe3c57260fb7bdb2c79ebadb3088656300d8a494123ebda6d85", + "coinbaseDiff": BigNumber(0x034dc9949767a4), + }, + "results": [ + { + "coinbaseDiff": "929953106847652", + "ethSentToCoinbase": "0", + "fromAddress": "0x9874Ef8519a0Fc7a6B553aad92fDF0E469488931", + "gasFees": "929953106847652", + "gasPrice": "35008022393", + "gasUsed": 29964, + "toAddress": "0x48B2dD9CEFbA73c60882478a16BC3428Aceed2B9", + "txHash": "0xee3f6f22bf3b4740b36833d41d4872f48f98c6328fa04b3679558e482ba0e328", + "value": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + ... + ], +} +``` + +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 your bundle paying enough to be competitive? + +Covers: + +``` +3. Competitors paying more +``` + +[Flashbots bundles adhere to a "blind" auction](/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. + +While you cannot see a competitor's bid in real time, it is possible to look onchain AFTER the fact to: + +1. Identify the exact bundle (if any) that conflicted with yours +2. Compare the conflicting bundle's `effective priority fee` with your own (to see if you should be bidding more to remain competitive) + +### Types of conflicts + +There are numerous reasons why two bundles might conflict. Consider that the basic algorithm for merging bundles is: + +1. Simulate each bundle at the top of the block +2. Sort bundles by `effective priority fee`, highest first +3. In descending order, try each bundle **that does not error or lower its effective priority fee from top-of-block simulation** until you reach a maximum bundle inclusion count or you run out of profitable bundles + +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 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: + +1. Simulate your bundle at the head of the target block, note its revert states and `effective priority fee` +2. Fetch all bundles found in the target block +3. Simulate [bundle1 + your bundle] as a single bundle, check the behavior of your bundle +4. Simulate [bundle1 + bundle2 + your bundle] as a single bundle, see the behavior of your bundle +5. Simulate [bundle1 + bundle2 + ...bundleN + your bundle] as a single bundle, see the behavior of your bundle +6. And so on... + +Using this method, we can identify the conflicting bundle that caused your target bundle to change behavior. The `Flashbots ethers.js provider` has a built-in helper function for running this strategy called `getConflictingBundle()`: + +```js +const signedTransactions = + await flashbotsProvider.signBundle(transactionBundle); +console.log( + await flashbotsProvider.getConflictingBundle( + signedTransactions, + 13140328, // blockNumber + ), +); +``` + +Output: + +```js +{ + "conflictType": FlashbotsBundleConflictType.NonceCollision, + "initialSimulation": { + "totalGasUsed": 205860, + "bundleHash": "0x1720ea33d96dca026dddd5689f8cad21966988348ced04e9054a0dca5d60f1d4", + "coinbaseDiff": BigNumber(0x0176750858d000), + }, + "results": [...] + }, + "targetBundleGasPricing": { + "gasUsed": 205860, + "txCount": 1, + "gasFeesPaidBySearcher": BigNumber(0x0176750858d000), + "priorityFeesReceivedByMiner": BigNumber(0x52efd8d80dbc24), + "ethSentToCoinbase": BigNumber.from(0x00), + "effectiveGasPriceToSearcher": BigNumber(0x77359400), + "effectivePriorityFeeToMiner": BigNumber(0x1a6734f601) + }, + "conflictingBundleGasPricing": { + "gasUsed": 396462, + "txCount": 3, + "gasFeesPaidBySearcher": BigNumber(0xc4c3c97ce1bff8b4), + "priorityFeesReceivedByMiner": BigNumber(0xc4213e4d7ad82006), + "ethSentToCoinbase": BigNumber(0xc4c2663d3b804731), + "effectiveGasPriceToSearcher": BigNumber(0x410ce509aa1e), + "effectivePriorityFeeToMiner": BigNumber(0x40f2069f201d) + }, + "conflictingBundle": [ + { + "transaction_hash": "0x23a33038289dda1b6e722835d2b9388cb41d96d085c19ca6b71bb3e9697e6692", + "tx_index": 0, + "bundle_type": "flashbots", + "bundle_index": 0, + "block_number": 13140328, + "eoa_address": "0x38563699560e4512c7574C8cC5Cf89fd43923BcA", + "to_address": "0x000000000035B5e5ad9019092C665357240f594e", + "gas_used": 100893, + "gas_price": "0", + "coinbase_transfer": "0", + "total_miner_reward": "0" + }, + ... + ] +} +``` + +:::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? + +Covers: + +``` +4. Bundle received too late to appear in target block +``` + +Each bundle submission is designed to target a specific block number. Therefore, it's crucial to ensure that your bundle is received as promptly as possible. This allows the bundle sufficient time to: + +1. Arrive at the builder +2. Undergo simulation +3. Be included in a block +4. Reach the validator through an mev-boost relay + +All these steps need to be completed before the targeted block is proposed. If you're targeting `blockNumber +1`, which is common for most bundles, it's vital to deliver your bundle to your builder(s) as quickly as you can. + +It's important to remember that there's a time frame for every block when your local perspective of block height is `X`, while `X+1` has already been discovered and propagated to a portion of the network, but hasn't reached your local node yet. During this period of partial propagation, submitting a bundle targeting `X+1` may seem valid from your network perspective, but could be pointless if builders have already started working on solving X+2. In rare cases, targeting the `X+1` block just before its discovery can also cause bundle failure due to insufficient time for the bundle to complete the above listed 4 steps, each of which takes around 1-2 seconds. + +To monitor the time taken from the submission of your bundle to the Flashbots and the proposal of the next block, Flashbots provides an RPC endpoint `eth_getBundleStats`. This endpoint returns timing information based on a previously-submitted bundle. Each submitted bundle is uniquely identified by a bundleHash and target block number for future reference. The bundleHash is straightforward to calculate, as shown [here](https://github.com/flashbots/ethers-provider-flashbots-bundle/blob/0d404bb041b82c12789bd62b18e218304a095b6f/src/index.ts#L266-L269). + +```js +console.log( + await flashbotsProvider.getBundleStats( + "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234", + 13509887, + ), +); +``` + +Output: + +```json +{ + "isSimulated": true, + "isSentToMiners": true, + "isHighPriority": true, + "simulatedAt": "2021-10-29T04:00:50.526Z", + "submittedAt": "2021-10-29T04:00:50.472Z", + "sentToMinersAt": "2021-10-29T04:00:50.546Z" +} +``` + +:::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. + +::: + +Analyze the timestamps above in relation to when you observe the targeted block being propagated to your node. + +- If the time difference is minimal, focus on reducing your processing time and network latency. +- If there is a significant delay between `sentToMinersAt` and when you observe the target block, proceed to the next section for further troubleshooting. + +## Is the validator for a particular block/slot running mev-boost? + +``` +5. A validator for target slot not running mev-boost +``` + +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 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. + +## 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: + +[Fill out our Searcher Issue Reporting Form](https://flashbots.notion.site/Searcher-Issue-Reporting-Form-700a5ff3843a443c993912099b4c1b56) + +Be sure to include the output from the above RPC calls: + +- eth_callBundle / simulate +- eth_getBundleStats +- getConflictingBundle + +in the form submission. diff --git a/docs/flashbots-auction/advanced/understanding-bundles.mdx b/docs/flashbots-auction/advanced/understanding-bundles.mdx new file mode 100644 index 00000000..404a2849 --- /dev/null +++ b/docs/flashbots-auction/advanced/understanding-bundles.mdx @@ -0,0 +1,31 @@ +--- +title: Understanding Bundles +--- + +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 + { + 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-minter.md b/docs/flashbots-auction/example-searchers/searcher-minter.md similarity index 95% rename from docs/flashbots-auction/searchers/example-searchers/searcher-minter.md rename to docs/flashbots-auction/example-searchers/searcher-minter.md index 724c0f64..b9303e0f 100644 --- a/docs/flashbots-auction/searchers/example-searchers/searcher-minter.md +++ b/docs/flashbots-auction/example-searchers/searcher-minter.md @@ -1,5 +1,5 @@ --- -title: searcher minter +title: Searcher Minter --- searcher-minter is a repository that contains a very simple demo application which allows arbitrary submission of a single transaction to Flashbots. This could be used for many simple purposes, but in the demonstration, the goal was to mint an NFT. diff --git a/docs/flashbots-auction/example-searchers/searcher-sponsored-tx.md b/docs/flashbots-auction/example-searchers/searcher-sponsored-tx.md new file mode 100644 index 00000000..a04e71f6 --- /dev/null +++ b/docs/flashbots-auction/example-searchers/searcher-sponsored-tx.md @@ -0,0 +1,6 @@ +--- +title: Searcher Sponsored TX +--- +searcher-sponsored-tx contains a simple Flashbots "searcher" for submitting a transaction from an executor account, but paying for the transaction from a sponsor account. This is accomplished by submitting a Flashbots transaction bundle, with the first "sponsor" transaction paying the "executor" wallet in ETH, followed by a series of executor transactions that spend this newly received ETH on gas fees. + +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/example-searchers/simple-arbitrage-bot.md b/docs/flashbots-auction/example-searchers/simple-arbitrage-bot.md similarity index 95% rename from docs/flashbots-auction/searchers/example-searchers/simple-arbitrage-bot.md rename to docs/flashbots-auction/example-searchers/simple-arbitrage-bot.md index b6cfe2cf..fe7a0290 100644 --- a/docs/flashbots-auction/searchers/example-searchers/simple-arbitrage-bot.md +++ b/docs/flashbots-auction/example-searchers/simple-arbitrage-bot.md @@ -1,5 +1,5 @@ --- -title: simple arbitrage bot +title: Simple Arbitrage Bot --- simple-arbitrage is a repository that contains a simple, mechanical system for discovering, evaluating, rating, and submitting arbitrage opportunities to the Flashbots bundle endpoint. Please note that this is **very unlikely to be profitable, as many users have access to it, and it is targeting well-known Ethereum opportunities.** diff --git a/docs/flashbots-auction/searchers/example-searchers/synthetix-searcher.md b/docs/flashbots-auction/example-searchers/synthetix-searcher.md similarity index 97% rename from docs/flashbots-auction/searchers/example-searchers/synthetix-searcher.md rename to docs/flashbots-auction/example-searchers/synthetix-searcher.md index a02a2797..0ebdd210 100644 --- a/docs/flashbots-auction/searchers/example-searchers/synthetix-searcher.md +++ b/docs/flashbots-auction/example-searchers/synthetix-searcher.md @@ -1,5 +1,5 @@ --- -title: synthetix searcher +title: Synthetix Searcher --- This repo by [Bert Miller](https://twitter.com/bertcmiller) contains a searcher developed to take advantage of a 1 off MEV opportunity created by the Synthetix team deprecating their ETH collateral trial program. As a result of this there were many loans that would be liquidatable after the governance proposal was executed. Taking advantage of this required a bot that could backrun the governance proposal execution transaction from the mempool as well as monitoring and execution infrastructure - all of which is contained here. diff --git a/docs/flashbots-auction/faq.md b/docs/flashbots-auction/faq.md new file mode 100644 index 00000000..ad66f27e --- /dev/null +++ b/docs/flashbots-auction/faq.md @@ -0,0 +1,7 @@ +--- +title: FAQ +--- + +The FAQ has been moved to the [Flashbots Collective Forum](https://collective.flashbots.net/). + +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. diff --git a/docs/flashbots-auction/libraries/alchemyprovider.md b/docs/flashbots-auction/libraries/alchemyprovider.md new file mode 100644 index 00000000..aec5c408 --- /dev/null +++ b/docs/flashbots-auction/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. + +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](/flashbots-auction/advanced/reputation#querying-reputation) + +**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 [included 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/sendprivatetransaction-sdk-v3](https://docs.alchemy.com/reference/sendprivatetransaction-sdk-v3) + +* [https://github.com/alchemyplatform/alchemy-sdk-js](https://github.com/alchemyplatform/alchemy-sdk-js) diff --git a/docs/flashbots-auction/libraries/bundle-relay.md b/docs/flashbots-auction/libraries/bundle-relay.md new file mode 100644 index 00000000..73e8c3bd --- /dev/null +++ b/docs/flashbots-auction/libraries/bundle-relay.md @@ -0,0 +1,12 @@ +--- +title: Bundle Relay Clients +--- + +The following clients connect to the Bundle Relay API, which exposes [these JSON-RPC methods](/docs/flashbots-auction/advanced/rpc-endpoint.mdx). + +- [ethers-js](/docs/flashbots-auction/libraries/ethers-js-provider.md) +- [golang](/docs/flashbots-auction/libraries/golang.md) +- [web3.py](/docs/flashbots-auction/libraries/web3py-provider.md) +- [Alchemy API](/docs/flashbots-auction/libraries/alchemyprovider.md) + +MEV-Share endpoints (e.g. `mev_sendBundle`) are implemented in [their own libraries](/docs/flashbots-auction/libraries/mev-share-clients.md). diff --git a/docs/flashbots-auction/libraries/ethers-js-provider.md b/docs/flashbots-auction/libraries/ethers-js-provider.md new file mode 100644 index 00000000..1e3d2c47 --- /dev/null +++ b/docs/flashbots-auction/libraries/ethers-js-provider.md @@ -0,0 +1,11 @@ +--- +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. + +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. + +Access the ethers-provider-flashbots-bundle repository [here](https://github.com/flashbots/ethers-provider-flashbots-bundle). diff --git a/docs/flashbots-auction/libraries/golang.md b/docs/flashbots-auction/libraries/golang.md new file mode 100644 index 00000000..8f8b91f5 --- /dev/null +++ b/docs/flashbots-auction/libraries/golang.md @@ -0,0 +1,13 @@ +--- +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 the Flashbots builder. + +Flashbots exposes several specialized JSON-RPC endpoints, such as [`eth_sendBundle`](/flashbots-auction/advanced/rpc-endpoint/#eth_sendbundle) and [`eth_callBundle`](/flashbots-auction/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: + +* [github.com/metachris/flashbotsrpc](https://github.com/metachris/flashbotsrpc) +* [github.com/cryptoriums/flashbot](https://github.com/cryptoriums/flashbot) diff --git a/docs/flashbots-auction/libraries/mev-share-clients.md b/docs/flashbots-auction/libraries/mev-share-clients.md new file mode 100644 index 00000000..71269953 --- /dev/null +++ b/docs/flashbots-auction/libraries/mev-share-clients.md @@ -0,0 +1,11 @@ +--- +title: MEV-Share Clients +--- + +* [mev-share-client-ts](https://github.com/flashbots/mev-share-client-ts) +* [mev-share-rs](https://github.com/paradigmxyz/mev-share-rs) +* [mev-share-go](https://github.com/duoxehyon/mev-share-go) +* [mev-share-java](https://github.com/optimism-java/mev-share-java) +* [mev-share-py](https://github.com/ZigaMr/mev-share-py) + +> :eyes: If you want to write a MEV-Share client for another language, please [reach out](/flashbots-mev-share/searchers/tutorials/limit-order/more-resources). We love client diversity! diff --git a/docs/flashbots-auction/libraries/rust-provider.md b/docs/flashbots-auction/libraries/rust-provider.md new file mode 100644 index 00000000..f4f98373 --- /dev/null +++ b/docs/flashbots-auction/libraries/rust-provider.md @@ -0,0 +1,11 @@ +--- +title: Rust Provider +--- + +Ethers-flashbots is a robust and user-friendly Rust library for interacting with flashbots. + +By using this library, you can easily access the flashbots endpoints and send bundles of transactions with little effort from you favorite language. + +This library is built on [ethers-rs,](https://github.com/gakonst/ethers-rs) which is a port of the popular ethers.js library, and it provides a convenient middleware layer for integrating with ethers-rs. + +With ethers-flashbots, you can quickly and easily automate your trading activities on DEXs, allowing you to take advantage of market opportunities and maximize your profits. To learn more about ethers-flashbots and its features, visit the library's repository [here.](https://github.com/onbjerg/ethers-flashbots) \ No newline at end of file diff --git a/docs/flashbots-auction/searchers/libraries/web3py-provider.md b/docs/flashbots-auction/libraries/web3py-provider.md similarity index 52% rename from docs/flashbots-auction/searchers/libraries/web3py-provider.md rename to docs/flashbots-auction/libraries/web3py-provider.md index 6002f1ee..25041032 100644 --- a/docs/flashbots-auction/searchers/libraries/web3py-provider.md +++ b/docs/flashbots-auction/libraries/web3py-provider.md @@ -1,11 +1,10 @@ --- -title: web3.py provider +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 +To apply correct headers, we use FlashbotProvider which injects the correct header on post. Access the web3-flashbots repository [here](https://github.com/flashbots/web3-flashbots). 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..149c535d 100644 --- a/docs/flashbots-auction/other-resources.md +++ b/docs/flashbots-auction/other-resources.md @@ -1,11 +1,12 @@ --- -title: other resources +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 +* [Walking through simple-arbitrage](https://www.youtube.com/watch?v=wn8r674U1B4) by Robert Miller * [Finding & Capturing MEV 101](https://www.youtube.com/watch?v=70WtsHtFd8Y) by thegostep & Robert Miller * [Using Flashbots to Mint NFTs on Ethereum - Part 1](https://youtu.be/1ve1YIpDs_I) by Scott Bigelow * [Anatomy of an MEV Strategy: Synthetix](https://www.bertcmiller.com/2021/09/05/mev-synthetix.html) by Robert Miller diff --git a/docs/flashbots-auction/overview.mdx b/docs/flashbots-auction/overview.mdx index 9a9b5bc0..4553022b 100644 --- a/docs/flashbots-auction/overview.mdx +++ b/docs/flashbots-auction/overview.mdx @@ -1,57 +1,62 @@ --- -title: overview +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. -Flashbots Auction is currently in version alpha-v0.4 of the [roadmap](#roadmap). +In PoS Ethereum, the Flashbots Auction is built on [mev-boost](https://boost.flashbots.net/), an implementation of proposer-builder separation for Ethereum. ## 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. -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. +Throughout the second half of 2020 and beginning 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. -We have observed and are concerned about the active development of permissioned and exclusive transaction routing infrastructure as it holds the potential to erode the neutrality, transparency, decentralization, and fairness of Ethereum today. Flashbots Auction is an open-sourced, democratic, and credibly neutral alternative which aims to mitigate the aforementioned negative externalities and existential risks. +The extraction of MEV introduces an existential threat to Ethereum's consensus security. This is primarily due to the potential for chain history re-org to extract past MEV, known as [time-bandit attacks](https://arxiv.org/pdf/1904.05234.pdf), and the centralization of transaction routing for the benefits of privacy, low latency, and control over transaction order. These factors critically undermine Ethereum's foundational principles of finality and permissionlessness, posing a serious risk to its very existence. + +We've noted with deep concern about the rise of exclusive transaction routing infrastructures that could undermine Ethereum's neutrality, transparency, decentralization, and fairness. As a response, Flashbots Auction is built as an open-sourced, democratic, and credibly neutral alternative, designed to counter these existential threats and risks. ## Timeline + - July 2020: Formation of MEV-Ship Research Collective. - November 2020: Formation of Flashbots Research Organization and proposal of [Flashbots Auction architecture](https://ethresear.ch/t/flashbots-frontrunning-the-mev-crisis/8251). - January 2021: Flashbots Auction Alpha (v0.1) made available for miners and searchers to adopt. -- May 2021: [Flashbots Auction Alpha (v0.2)](/flashbots-auction/releases/alpha-v0.2) made available for miners and searchers to adopt. -- 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. - +- May 2021: Flashbots Auction Alpha (v0.2) made available for miners and searchers to adopt. +- August 2021: Flashbots Auction Alpha (v0.3) made available for miners and searchers to adopt. +- September 2021: Flashbots Auction Alpha (v0.4) made available for miners and searchers to adopt. +- February 2022: Flashbots Auction Alpha (v0.5) made available for miners and searchers to adopt. +- February, 2022: Flashbots Auction 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. -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. +Flashbots Auction provides a private transaction pool and a sealed bid blockspace auction mechanism. This enables block proposers (validators; previously "miners" in PoW) to trustlessly outsource the task of finding the optimal block construction. + +In the standard Ethereum transaction pool, users broadcast transactions to the public peer-to-peer network, specifying a gas price that represents their willingness to pay for each unit of computation on the Ethereum chain. Block builders receive these transactions, sort them by gas price, and employ a greedy algorithm to construct a block that aims to maximize the value derived from transaction fees. This mechanism is a hybrid of an [English auction](https://en.wikipedia.org/wiki/English_auction) and an [all-pay auction](https://en.wikipedia.org/wiki/All-pay_auction), where bids for blockspace are made openly, the highest bidder secures the opportunity, and all participants bear 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 -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. +1. The open nature of the regular transaction pool leads to bidding wars for blockspace. This results in unnecessary network load and gas price volatility. It also puts less sophisticated network participants at a disadvantage, as they may lack access to advanced bidding strategies. +2. The all-pay nature of the auction results in failed bids reverting on-chain, unnecessarily consuming blockspace. This leads bidders to underprice their bids due to the risk of execution failure, creating artificial blockspace scarcity and reducing validator (previously "miner") revenues. +3. The dependency on gasPrice restricts bidders from expressing detailed ordering preferences, as they are limited to bidding for the top position in the block. This limitation encourages alternative strategies such as spamming to increase the chances of winning, thereby exacerbating the 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 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: +The ultimate design goals include: -- **Pre-trade privacy**: implies transactions only become publicly known after they have been included in a block. This excludes intermediaries such as relayers / miners. -- **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. -- **Permissionless**: implies there are no trusted intermediaries which can censor transactions. +- **Pre-trade privacy**: Transactions are only made public after their inclusion in a block, excluding intermediaries such as relays and block builders. This means that the details of a transaction are not visible to the network until the transaction has been successfully included in a block. +- **Failed trade privacy**: Losing bids are never included in a block, thus they remain unknown to the public. +- **Efficiency**: MEV extraction is conducted without causing unnecessary network or chain congestion. +- **Bundle merging**: Multiple incoming bundles can be merged without conflict. +- **Finality protection**: Once propagated to the network, it becomes impractical to modify Flashbots blocks containing Flashbots bundles. This protects against time-bandit chain re-org attacks. +- **Complete Privacy**: This extends the concept of pre-trade privacy to all intermediaries involved in the transaction process. Not only are transactions hidden from the network until their inclusion in a block, but also intermediaries such as relays and validators are unable to view the content of transactions until they are included in the blockchain. This ensures that no party has an unfair advantage by being able to view transaction details before they are publicly available. +- **Permissionless**: This system does not rely on trusted intermediaries, thus eliminating the possibility of transaction censorship. | Stage | PGA | DarkPool | ⚡🤖 v0.1 | ⚡🤖 v0.2 | ⚡🤖 v0.3 | ⚡🤖 v0.4 | ⚡🤖 v1.0 | -| -------------------- |:---:|:--------:|:---------:|:---------:|:---------:|:---------:|:---------:| +| -------------------- | :-: | :------: | :-------: | :-------: | :-------: | :-------: | :-------: | | Pre-trade privacy | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Failed trade privacy | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | | Efficiency | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | @@ -59,19 +64,20 @@ 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.
-![Auction Architecture](/img/core-architecture.png) +![Auction Architecture](/img/mevboost-searcher-bundle-flow.png)
Flashbots Auction introduces a new `eth_sendBundle` RPC which standardizes the message format in the communication channel. This message is called a "Flashbots Bundle". -The bundle includes an array of arbitrary signed Ethereum transactions along with some metadata describing under what conditions these transactions should be included. +The bundle comprises an array of arbitrary signed Ethereum transactions, accompanied by metadata that specifies the conditions under which these transactions should be included. ```json { @@ -91,66 +97,102 @@ The bundle includes an array of arbitrary signed Ethereum transactions along wit ``` ### Searchers -Searchers are Ethereum users who, for whatever reason, prefer to use the Flashbots private transaction pool over the regular p2p transaction pool. These users monitor the state of the chain and send bundles to relayers. -Typically, searchers will be one of the following types: -1. Ethereum bot operators looking for fast, and risk free access to blockspace (for example, arbitrage and liquidation bots) -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) +Searchers are Ethereum users who opt for the Flashbots private transaction pool over the standard p2p transaction pool. These users keep track of the chain's state and submit bundles to block builders. -
+Searchers typically fall into one of the following categories: + +1. Ethereum bot operators seeking swift and risk-free access to blockspace, such as arbitrage and liquidation bots. +2. Ethereum users seeking protection from frontrunning for their transactions, such as Uniswap traders. +3. Ethereum Dapps that require advanced features like account abstraction or gasless transactions. + +
![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. +Searchers submit bundles directly to block builders, bypassing the p2p network. This approach ensures `Pre-trade privacy` as the transactions remain unseen by the rest of the network until they are included in a block. Searchers express their inclusion bids through Ethereum transactions, either as a gas price or as a direct ETH transfer to the coinbase address. Opting for direct payments over gas price allows users to condition their payments on the success of their transaction, thereby eliminating the need to pay for unsuccessful bids. -See the [searcher quick-start guide](/flashbots-auction/searchers/quick-start) to learn how to get started. +See the [searcher quick-start guide](/flashbots-auction/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, often referred to as "builders", are specialized entities that receive transactions from users and searchers. Their primary role is to construct the most profitable block from these transactions. Once a block is built, it is transmitted to validators via an mev-boost relay. For a more detailed understanding of relays, refer to the [Relays](#relays) section. It's important to note that searchers can send bundles to multiple builders. + +
-![Relay Architecture](/img/relay-architecture.png) +![Block Builder Flow](/img/block-builder-flow.png) + +Block builders construct blocks by integrating bundles from searchers and transactions from the mempool, which are submitted by regular users.
-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. +⚠️ Not all builders can be trusted ⚠️ -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. +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: -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). +- Do they uphold fair and unbiased execution principles? + - A reputable builder will refrain from front-running, sandwiching, or censoring bundles, and will avoid exploiting privileged data access. +- Are they connected to a reliable relay (or relays)? + - Remember that relays also have visibility of raw transactions, which could potentially enable front-running, censorship, and other manipulative practices. +- Are their relays linked to a sufficient number of validators? + - The more validators a relay is connected to, the more slots are typically available for builders linked to that relay. If you're aiming for a specific block/slot, it's crucial to send your transactions to a builder that is connected to the validator tasked with proposing a block in that slot. More validators equate to improved inclusion rates. + - Note: Any validator can [utilize mev-boost to establish connections with the Flashbots relay and other relays](https://github.com/flashbots/mev-boost#usage). + - It's also beneficial to consider the collective stake of the validators connected to a relay. Generally, if more than one block is proposed to the network (which is unusual but possible), the block with the highest collective stake attesting to it will be included. This scenario is further elaborated in the [Ethereum docs](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#fork-choice). -⚠️ Not all relayers can be trusted ⚠️ +Keep in mind that block builders can specialize in certain areas. Some may be more compatible with your strategy than others. While all builders are incentivized to include your bundles in their blocks due to competition, some may prioritize specific strategies over others, regardless of potential profits. Additionally, certain bundles may be censored by builders due to local regulations or corporate strategies. Given these variables, it's advisable to experiment with several reputable builders to determine which ones best suit your needs. -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. +Learn more about the [trust assumptions of the Flashbots Auction](#trust-assumptions). -Learn more about the [trust assumptions of the Flashbots Alpha](#trust-assumptions). +### Relays -### 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 play a pivotal role as illustrated in the preceding architecture diagram. Their main responsibility is to securely store blocks received from builders and subsequently make them accessible to validators. -
+
-![Miner Architecture](/img/miner-architecture.png) +![Relay Flow](/img/relay-flow.png) + +The relay selects the most profitable block from the builders it is connected to and holds it in escrow 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. +In the mev-boost system, validators select the most profitable block from a variety of relays. Each relay maintains the privacy of a block's contents until the validator commits to proposing it for inclusion in the network. + +Specifically, relays do the following: + +- Receive new blocks from builders +- Send the header of the most profitable block to a validator upon request + - The validator secures their commitment to propose the full block by signing this header +- Send the full block to the validator after receiving the block header signed by the validator +- Execute all of these tasks swiftly and reliably to ensure validators meet 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). -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. +Learn more about the [trust assumptions of the Flashbots Auction](#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 ⚠️ +In Proof of Stake (PoS) Ethereum, validators, also known as "proposers", have the crucial role of proposing new blocks to the network and appending these blocks to the blockchain. For a comprehensive understanding of validators, refer to the [Ethereum documentation](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#validators). -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. +
-Learn more about the [trust assumptions of the Flashbots Alpha](#trust-assumptions). +![Validator Flow](/img/validator-flow.png) + +Validator uses mev-boost to choose the most profitable block to propose from multiple relays. + +
+ +By incorporating MEV-generating transactions into their blocks, builders can increase the profitability of these blocks. Validators, in turn, can enhance their earnings by selecting these more profitable blocks via mev-boost. For a deeper understanding of mev-boost, visit [boost.flashbots.net](https://boost.flashbots.net). + +Learn more about the [trust assumptions of the Flashbots Auction](#trust-assumptions). ## Trust Assumptions -The current version of Flashbots Auction contains technical limitations which prevent the network from operating in a fully trustless manner. Specifically, the properties of complete privacy and permissionlessness are required for Flashbots to be fully decentralized. -In the future, the [Flashbots Auction roadmap](#roadmap) aims to replace these trust guarantees with cryptographic and cryptoeconomic guarantees of full privacy. We invite privacy researchers and interested community members to review our proposed architecture and contribute to building a more robust and decentralized system. +The current iteration of Flashbots Auction has certain technical constraints that prevent it from operating in a completely trustless manner. Specifically, the network has yet to achieve complete privacy and permissionlessness, both of which are crucial for full decentralization. + +Looking ahead, the [Flashbots Auction roadmap](#roadmap) is designed to replace these trust-based elements with cryptographic and cryptoeconomic guarantees that ensure total privacy. We encourage privacy researchers and other interested parties to review our proposed architecture and contribute to the development of a more robust and decentralized system. diff --git a/docs/flashbots-auction/quick-start.mdx b/docs/flashbots-auction/quick-start.mdx new file mode 100644 index 00000000..90ec3c10 --- /dev/null +++ b/docs/flashbots-auction/quick-start.mdx @@ -0,0 +1,283 @@ +--- +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. 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! ⚡🤖 + +### Bundle Relay URLS + +| Network | URL | +| ------- | ------------------------------------- | +| Mainnet | `https://relay.flashbots.net` | +| Sepolia | `https://relay-sepolia.flashbots.net` | + +### Who should use Flashbots Auction? + +1. Ethereum bot operators (we call them "searchers") looking for fast, and risk free access to blockspace (for example, arbitrage and liquidation bots) +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 + +### How does Flashbots work for searchers? + +Flashbots provides a platform that connects searchers with validators, bypassing the public transaction pool. Searchers create 'bundles' of transactions they wish to send and forward these to block builders, such as Flashbots. The builder then simulates these bundles to ensure they won't revert and constructs a full block using the available bundles and transactions. Through the use of mev-boost and a network of relays and builders, these blocks are delivered to validators while preserving pre-trade privacy. + +Getting onboarded to Flashbots is easy for searchers; you simply need to update how you send transactions. + +### How to send your first Flashbots bundle + +To access the Flashbots network you will need three things: + +1. A unique ECDSA-secp256k1 key pair for Flashbots to identify you +2. A method to communicate with the Flashbots network + - [Alchemy](https://docs.alchemy.com/docs/how-to-send-a-private-transaction-on-ethereum?a=fb) provides a convenient way to dispatch individual transactions to Flashbots. +3. A "bundle" comprising your transactions + +When you send bundles to Flashbots, they are signed with your key, which allows us to confirm your identity and accumulate your [reputation](/flashbots-auction/advanced/reputation) over time. Reputation system is set up to protect the infrastructure from attacks like DDoS. Searchers with higher reputation will have better access to the network especially during times of high congestion. + +It's crucial to understand that this key **does not** manage any funds and does **not** have to be the main Ethereum key used for authenticating transactions. Its only function is to establish your identity with Flashbots. You can use any ECDSA-secp256k1 key for this purpose. + +Next, you need a means to communicate with the Flashbots network. The Flashbots builder accepts bundles at `relay.flashbots.net`, and there are specific RPC endpoints that you must use to transmit transactions to us. To simplify this process, we've integrated with several widely-used developer tools such as Ethers.js and web3.py. Below are some examples of how to configure a Flashbots provider: + + + + +```ts +const { ethers } = require("ethers"); +const { + FlashbotsBundleProvider, +} = require("@flashbots/ethers-provider-bundle"); + +// Standard json rpc provider directly from ethers.js. You can use Infura, Alchemy, or your own node. +const provider = new ethers.providers.JsonRpcProvider({ + url: ETHEREUM_RPC_URL, +}); + +// `authSigner` is an Ethereum private key that does NOT store funds and is NOT your bot's primary key. +// This is an identifying key for signing payloads to establish reputation and whitelisting +const authSigner = new ethers.Wallet( + "0x0000000000000000000000000000000000000000000000000000000000000000" +); + +// Flashbots provider requires passing in a standard provider and an auth signer +const flashbotsProvider = await FlashbotsBundleProvider.create( + provider, + authSigner +); +``` + + + + +```python +import os + +from eth_account.account import Account +from eth_account.signers.local import LocalAccount +from flashbots import flashbot + from web3 import Web3, HTTPProvider + + +# Create a web3 object with a standard json rpc provider, such as Infura, Alchemy, or your own node. +w3 = Web3(HTTPProvider("http://localhost:8545/")) + +# ETH_ACCOUNT_SIGNATURE is an Ethereum private key that does NOT store funds and is NOT your bot's primary key. +# This is an identifying key for signing payloads to establish reputation and whitelisting +ETH_ACCOUNT_SIGNATURE: LocalAccount = Account.from_key(os.environ.get("ETH_SIGNATURE_KEY")) + +# Flashbots providers require both a standard provider and ETH_ACCOUNT_SIGNATURE (to establish reputation) +flashbot(w3, ETH_ACCOUNT_SIGNATURE) +``` + + + + +```go +package main + +import ( + "bytes" + "crypto/ecdsa" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" +) + +const ( + flashbotURL = "https://relay.flashbots.net/" + flashbotXHeader = "X-Flashbots-Signature" +) + +var ( + // authSigner is an Ethereum private key that does NOT store funds and is NOT your bot's primary key. + // This is an identifying key for signing payloads to establish reputation and whitelisting + privateKey, _ = crypto.HexToECDSA( + "2e19800fcbbf0abb7cf6d72ee7171f08943bc8e5c3568d1d7420e52136898154", + ) +) + +func flashbotHeader(signature []byte, privateKey *ecdsa.PrivateKey) string { + return crypto.PubkeyToAddress(privateKey.PublicKey).Hex() + + ":" + hexutil.Encode(signature) +} + +func main() { + // Example: create a Flashbots authenticated request + mevHTTPClient := &http.Client{ + Timeout: time.Second * 3, + } + + // Prepare your RPC request (e.g., eth_sendBundle, eth_callBundle, etc.) + params := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendBundle", // or other Flashbots RPC methods + "params": []interface{}{ /* your bundle params */ }, + } + + payload, _ := json.Marshal(params) + req, _ := http.NewRequest("POST", flashbotURL, bytes.NewBuffer(payload)) + + // Sign the payload for Flashbots authentication + headerReady, _ := crypto.Sign( + accounts.TextHash([]byte(hexutil.Encode(crypto.Keccak256(payload)))), + privateKey, + ) + + req.Header.Add("content-type", "application/json") + req.Header.Add("Accept", "application/json") + req.Header.Add(flashbotXHeader, flashbotHeader(headerReady, privateKey)) + + resp, _ := mevHTTPClient.Do(req) + res, _ := ioutil.ReadAll(resp.Body) + fmt.Println(string(res)) +} +``` + + + + +```rust +use ethers::core::rand::thread_rng; +use ethers::prelude::*; +use ethers_flashbots::*; +use std::convert::TryFrom; +use url::Url; + +#[tokio::main] +async fn main() { + // Connect to the network + let provider = Provider::::try_from("https://www.ankr.com/rpc/eth/").unwrap(); + + // This is your searcher identity + let bundle_signer = LocalWallet::new(&mut thread_rng()); + + // This signs transactions and is randomly generated in this example + let wallet = LocalWallet::new(&mut thread_rng()); + + // Add signer and Flashbots middleware + let flashbots_client = SignerMiddleware::new( + FlashbotsMiddleware::new( + provider, + Url::parse("https://relay.flashbots.net/").unwrap(), + bundle_signer, + ), + wallet, + ); +} +``` + + + + +Now that we have a private key to identify ourselves with and a Flashbots provider we can create and send a bundle. Here's how: + + + + +```js +const { ethers } = require("ethers"); +const { + FlashbotsBundleProvider, +} = require("@flashbots/ethers-provider-bundle"); +const provider = new ethers.providers.JsonRpcProvider({ + url: ETHEREUM_RPC_URL, +}); + +const authSigner = new ethers.Wallet( + "0x2000000000000000000000000000000000000000000000000000000000000000" +); +const flashbotsProvider = await FlashbotsBundleProvider.create( + provider, + authSigner +); + +const signedBundle = await flashbotsProvider.signBundle([ + { + signer: SOME_SIGNER_TO_SEND_FROM, + transaction: SOME_TRANSACTION_TO_SEND, + }, +]); + +const bundleReceipt = await flashbotsProvider.sendRawBundle( + signedBundle, + TARGET_BLOCK_NUMBER +); +``` + + + + +See https://github.com/onbjerg/ethers-flashbots + +```rust +let tx = TransactionRequest::pay("vitalik.eth", 100); +let pending_tx = client.send_transaction(tx, None).await?; + +// Get the receipt +let receipt = pending_tx + .await? + .ok_or_else(|| eyre::format_err!("tx not included"))?; +let tx = client.get_transaction(receipt.transaction_hash).await?; + +println!("Sent transaction: {}\n", serde_json::to_string(&tx)?); +println!("Receipt: {}\n", serde_json::to_string(&receipt)?); +``` + + + + +That's it! + +### Next steps + +Congrats! You should now have everything you need to start sending transactions to the Flashbots network. + +- If you are looking to interact with Flashbots without using one of the libraries, check out the [RPC endpoint documentation](/flashbots-auction/advanced/rpc-endpoint) and other advanced concepts. +- For examples of advanced usage of Flashbots, check out the [example searchers](/flashbots-auction/example-searchers/simple-arbitrage-bot). +- For additional tools, check out the [searcher libraries](/flashbots-auction/libraries/ethers-js-provider). +- For potential MEV opportunities, check out the [MEV job board](https://github.com/flashbots/mev-job-board) 🤠 diff --git a/docs/flashbots-auction/releases/alpha-v0.2.mdx b/docs/flashbots-auction/releases/alpha-v0.2.mdx deleted file mode 100644 index 569ef9de..00000000 --- a/docs/flashbots-auction/releases/alpha-v0.2.mdx +++ /dev/null @@ -1,151 +0,0 @@ ---- -title: alpha-v0.2 ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -## Changelog - -#### `eth_sendBundle` RPC parameters change -The specification of the `eth_sendBundle` RPC is changing to support new features of v0.2. This change must be adopted by all searchers in order to be compatible with the v0.2 relay. - -Here is the change in the specification: - - - - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_sendBundle", - "params": [ - 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 maximum timestamp for which this bundle is valid, in seconds since the unix epoch - ] -} -``` - - - - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_sendBundle", - "params": [ - { - 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 maximum timestamp for which this bundle is valid, in seconds since the unix epoch - revertingTxHashes // (Optional) Array[String], A list of tx hashes that are allowed to revert - } - ] -} -``` - - - - -A new parameter `revertingTxHashes` is added to the bundles which allows the searcher to list the transactions in their bundle which are allowed to revert. By default, all transactions included in a bundle should never revert on chain. - -#### Bundle scoring -Bundles received by mev-geth will use a new scoring function to [mitigate some of the issues](https://hackmd.io/@flashbots/core-v2-proposal#Revamped-auction-pricing) with the scoring function used in v0.1. - -While the v0.2 pre-release removed the ability to pay the miner using gas price of a transaction, the scoring function selected for v0.2 allows the use of gas price based payments but excludes payments from transactions which are present in the regular transaction pool. - -Here is the formal definition of these scoring functions: - - - - -$$ -s_{v0.1} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tp_T}{\sum_{T\in U}g_T} -$$ - - - -$$ -s_{v0.2-pre} = \frac{\Delta_{coinbase}}{\sum_{T\in U}g_T} -$$ - - - -$$ -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 validation -The relay removes the temporary limitation of two 'from' addresses per bundle. The bundle can once again contain transactions from an arbitrary number of EOAs. - -#### Bundle delivery -The `eth_sendBundle` RPC method on mev-geth is put into maintenance mode in the v0.2 release. Instead, mev-geth establishes an outgoing websockets connection with the relay, which streams bundles as they become available. This improves the security of the miner infrastructure as it no longer requires exposing an incoming RPC port. - -To connect to the relay over websockets, each miner will receive an access key which they must add to their mev-geth node to perform the authentication. - -#### Block construction -A [simple bundle merging algorithm](https://hackmd.io/@flashbots/core-v2-proposal#Bundle-merging) is introduced to mev-geth which allows multiple bundles to be merged together in a block so long as they do not cause an unexpected revert, or pass a certain amount of gas. The number of bundles mev-geth will attempt to merge together is controlled by the CLI flag`miner.maxmergedbundles`. This can be configured by the miner according to the performance of their hardware and their risk tolerance. - -## Timeline - -**May 10th**: launch v0.2 relay -- v0.2 relay starts accepting new bundle format -- searchers are asked to update their bots to send bundles to v0.2 relay endpoint -- v0.2 bundles are converted to v0.1 bundles in the relay and submitted to v0.1 miners along with v0.1 bundles -- miners receive access key and are asked to deploy a parallel v0.2 mev-geth node and provide relevant IPs - -Rollback plan: -- Since v0.2 bundles can be made backwards compatible with v0.1 bundles by dropping the `revertingTxHashes` field, if v0.2 to v0.1 bundle conversion on the relay is having issues, searchers can fallback to using v0.1 bundle format - -**May 24th**: v0.1 relay deprecation -- relay only accepts v0.2 bundles, v0.1 bundle submission is deprecated -- v0.2 bundles are converted to v0.1 bundles by the relay and sent to the v0.1 miners over RPC -- relay starts sending v0.2 bundles to the v0.2 mev-geth miners over RPC - -Rollback plan: -- If the v0.2 mev-geth nodes are having issues, notify miners to continue pointing hashpower to v0.1 nodes - -**May 31st**: v0.1 mev-geth deprecation -- relay stops converting v0.1 bundles and stops sending bundles to miners v0.1 mev-geth miners - -## Upgrade Steps - -### Searchers -- **May 10th**: Searchers able to send v0.2 bundles using new bundle format. -- **May 10th to May 24th**: Searchers upgrade their bots to send v0.2 bundles. -- **May 24th**: Deadline for searchers to upgrade to v0.2 bundles. - -### Miners -- **Before May 17th**: Miner complete new [authentication process](https://hackmd.io/@flashbots/miner-authentication). -- **May 17th**: Miners receive mev-geth v0.2 spec, mev-geth v0.2 reference implementation, and bundle delivery access key over discord. -- **May 17th to May 24th**: Miners review, integrate, and deploy their mev-geth v0.2 nodes in parallel to their v0.1 deployment and provide a new IP address to receive v0.2 bundles. -- **May 24th**: Miners who have provided the new IP addresses will begin receiving bundles and can begin migrating their hashrate to these nodes. -- **May 24th to May 31st**: Miners monitor the performance of the v0.2 nodes and communicate back any issues. -- **May 31st**: v0.1 nodes can safely be shut down. diff --git a/docs/flashbots-auction/releases/alpha-v0.3.mdx b/docs/flashbots-auction/releases/alpha-v0.3.mdx deleted file mode 100644 index 781c7a12..00000000 --- a/docs/flashbots-auction/releases/alpha-v0.3.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: alpha-v0.3 ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -## Changelog - -#### EIP-1559 support added -Bundle scoring takes into account BASEFEE mechanisms to calculate miner's revenue from bundles. - -Here is the formal definition of scoring functions: - - - - -$$ -s_{v0.1} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tp_T}{\sum_{T\in U}g_T} -$$ - - - -$$ -s_{v0.2-pre} = \frac{\Delta_{coinbase}}{\sum_{T\in U}g_T} -$$ - - - -$$ -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_{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$. -$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. diff --git a/docs/flashbots-auction/releases/alpha-v0.4.mdx b/docs/flashbots-auction/releases/alpha-v0.4.mdx deleted file mode 100644 index bbbee138..00000000 --- a/docs/flashbots-auction/releases/alpha-v0.4.mdx +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: alpha-v0.4 ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -## Changelog - -#### Megabundles support added -Relays can merge bundles and suggest them for profit switching. -Miners can define a list of trusted relay addresses from which megabundles are accepted. - -Scoring function does not change between v0.3 and v0.4: - - - - -$$ -s_{v0.1} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tp_T}{\sum_{T\in U}g_T} -$$ - - - -$$ -s_{v0.2-pre} = \frac{\Delta_{coinbase}}{\sum_{T\in U}g_T} -$$ - - - -$$ -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_{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} -$$ - - - - -$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. - -## Timeline - -### September, 10th 2021 -Final spec of version alpha-v0.4 ready - -Flashbots reference implementation ready - -Flashbots Goerli running on version alpha-v0.4 - -Start of miners custom implementations and testing - -### September, 22nd 2021 -End of miners custom implementation and testing - -### September, 27th 2021 -All miners running on v0.4 - -Flashbots mainnet relay switching to alpha-v0.4 - -## Upgrade Steps - -- Miners asked to upgrade to v1.10.8-mev0.4.0 -- Miners can update 100% of capacity to this new version -- Miners will need to upgrade to the [newest version of mev-proxy](https://github.com/flashbots/mev-proxy) or whitelist the RPC call `eth_sendMegabundle` for your specific environment. -- Miners must add a new command line parameter for Megabundle Relays (see below) - -## Node configuration - -Miners must configure a new command line parameter to specify which relays megabundles will be accepted. The parameter is set as follows for a list of 3 relayers. - -```bash --miner.trustedrelays=0xADDR1,0xADDR2,0xADDR3 -``` - -The default Mega Bundle Relayer is set to the Flashbots Relayer `0x870e2734DdBe2Fba9864f33f3420d59Bc641f2be`. If you only want to receive bundles from this default relayer no configuration is necessary. For configurations which allow more relayers, be sure to also include the Flashbots relayer in your configuration. - -```bash --miner.trustedrelays=0x870e2734DdBe2Fba9864f33f3420d59Bc641f2be,0xADDR2,0xADDR3 -``` diff --git a/docs/flashbots-auction/releases/alpha-v0.5.mdx b/docs/flashbots-auction/releases/alpha-v0.5.mdx deleted file mode 100644 index 920b9d54..00000000 --- a/docs/flashbots-auction/releases/alpha-v0.5.mdx +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: alpha-v0.5 ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -## Changelog - -#### v0.5 Immediate megabundle processing -Miners pick up megabundles immediately if they are better than the best known block so far. -It leads to significantly increased profitability (+50% MEV backtested). - -#### v0.4 Megabundles support added -Relays can merge bundles and suggest them for profit switching. -Miners can define a list of trusted relay addresses from which megabundles are accepted. - -#### v0.3 EIP-1559 support added -Bundle scoring takes into account BASEFEE mechanisms to calculate miner's revenue from bundles. - -#### v0.2 `eth_sendBundle` RPC parameters change -The specification of the `eth_sendBundle` RPC is changing to support new features of v0.2. This change must be adopted by all searchers in order to be compatible with the v0.2 relay. - -Scoring function does not change between v0.4 and v0.5: - - - - -$$ -s_{v0.1} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tp_T}{\sum_{T\in U}g_T} -$$ - - - -$$ -s_{v0.2-pre} = \frac{\Delta_{coinbase}}{\sum_{T\in U}g_T} -$$ - - - -$$ -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_{v0.3-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$. -$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. - -## Timeline - -### February, 15th 2022 - v0.5 spec and MEV-Geth-v0.5 release ready - -## Upgrade Steps - -- Miners asked to upgrade to v[geth_version]-mev0.5.0 -- Miners can update 100% of capacity to this new version - -## Node configuration - -No additional configuration is required. \ No newline at end of file diff --git a/docs/flashbots-auction/releases/alpha-v0.6.mdx b/docs/flashbots-auction/releases/alpha-v0.6.mdx deleted file mode 100644 index 2ed2de9f..00000000 --- a/docs/flashbots-auction/releases/alpha-v0.6.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: alpha-v0.6 (current) ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -## Changelog - -#### v0.6 Private transactions support -Added eth_sendPrivateRawTransaction support. Private transactions can be now accepted and included in the blocks. Such transactions are not distributed to any other nodes in the network and only taken into account when a block is constructed locally. - -#### v0.5 Immediate megabundle processing -Miners pick up megabundles immediately if they are better than the best known block so far. -It leads to significantly increased profitability (+50% MEV backtested). - -#### v0.4 Megabundles support added -Relays can merge bundles and suggest them for profit switching. -Miners can define a list of trusted relay addresses from which megabundles are accepted. - -#### v0.3 EIP-1559 support added -Bundle scoring takes into account BASEFEE mechanisms to calculate miner's revenue from bundles. - -#### v0.2 `eth_sendBundle` RPC parameters change -The specification of the `eth_sendBundle` RPC is changing to support new features of v0.2. This change must be adopted by all searchers in order to be compatible with the v0.2 relay. - -Scoring function does not change between v0.4 and v0.5: - - - - -$$ -s_{v0.1} = \frac{\Delta_{coinbase} + \sum_{T\in U}g_Tp_T}{\sum_{T\in U}g_T} -$$ - - - -$$ -s_{v0.2-pre} = \frac{\Delta_{coinbase}}{\sum_{T\in U}g_T} -$$ - - - -$$ -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_{v0.3-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$. -$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. - -## Timeline - -### February, 28th 2022 - v0.6 spec and MEV-Geth-v0.6 release ready - -## Upgrade Steps - -- Miners asked to upgrade to v[geth_version]-mev0.6.0 -- Miners can update 100% of capacity to this new version - -## Node configuration - -No additional configuration is required. diff --git a/docs/flashbots-auction/releases/upgrade-process.md b/docs/flashbots-auction/releases/upgrade-process.md deleted file mode 100644 index 493fb838..00000000 --- a/docs/flashbots-auction/releases/upgrade-process.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: upgrade process ---- - -Flashbots Auction project encompasses the suite of user facing products used for democratizing MEV extraction outlined in the overview section. - -Breaking changes to these products requires coordination with searchers and miners to update their bot / node implementations. As such, we've devised the following high level upgrade process to set expectations, standardize communications, and provide sufficient time for 3rd parties to update their software. - -1. Feature selection process -2. Formal specification and reference implementation -3. Versioned deployment and testing -4. Monitoring continuing performance - -We do not make any commitments around how frequently / quickly these upgrades will happen as we wish to maintain flexibility during the Flashbots Alpha (v0.x.x). That being said, we will do our best to provide adequate information and time to adapt to critical changes. - -![Flashbots Auction Upgrades](/img/gant-chart-upgrade.png) - -## Feature selection process -The goal of the feature selection process is to surface feature requests from the community and collaborate on implementation. - -Product Manager (PM): @thegostep -1. Feature requests are submitted by anyone to the [flashbots forum](https://github.com/flashbots/pm/discussions) and titled 'Feature request:' -2. The PM is responsible for engaging and moderating the forums -3. The PM updates the ['core releases' project board](https://github.com/orgs/flashbots/projects/6) to keep track of feature requests and assigns them to target releases -4. The PM produces a proposal that outlines the details of modifications to the flashbots auction infrastructure -5. The proposal is posted to ['General' forum](https://github.com/flashbots/pm/discussions/categories/general) and shared with the community for feedback -6. Feedback is incorporated into the formal specification - -## Formal specification and reference implementation -We've learned that despite maintaining a reference implementation of mev-geth, miners tend to re-implement our feature set on their own custom nodes. This has lead to some confusion around what are "required" vs "nice to have" features as well as bugs which have lead to unexpected behaviors like mining unprofitable / reverting bundles. - -By producing a formal specification and updating it on each release, we aim to provide a document that clearly outlines the expected behavior of the node implementation and use it to grant / withhold access to the relay. - -## Versioned deployment and testing -To provide the best possible availability and correctness guarantees to the Flashbots Network, we aim to perform upgrades in a way that minimizes disruptions. This involves a 'rolling' upgrade process where searchers can define which version of Flashbots Auction they are targeting. - -At a selected block height, the relay will route all searcher bundles exclusively to the nodes that have implemented the new specification. A searcher desiring to remain on a previous version may do so by [specifying the target version](https://github.com/flashbots/mev-relay-js/issues/37) until a predetermined deprecation block height where the old version will no longer be supported by the relay. - -Miners will want to begin implementing the changes required as soon as the updated specification is released in order to be ready for the upgrade block height. Once the miner's implementation is ready, they can request to undergo our suite of correctness tests which once successfully passed, will allow them to begin receiving bundles on the new system version. - -These tests involve receiving and mining a series of bundles on a test environment which can be analyzed by the flashbots team. The tests will cover a range of known edge cases including but not limited to: - -- logic testing - - block formation / ordering - - bundle prioritization - - bundle atomicity -- probabilistic testing - - custom profit switcher - - latency and delays - - mempool volume - -## Monitoring continuing performance - -While passing the test suite helps identify and correct some logical errors, it will not be able to catch everything which can go wrong on the mining side. As such, the Flashbots Auction team has built a series of monitoring tools which analyses mined flashbots blocks for correctness and profitability in order to help miners insure their infrastructure is behaving as expected. If unexpected behavior is identified, like mining bundles which did not go through the relay or producing incorrect blocks, Flashbots will temporarily disable sending the bundles to the miner and provide the technical support required to resolve the issues at hand. diff --git a/docs/flashbots-auction/searchers/advanced/bundle-pricing.md b/docs/flashbots-auction/searchers/advanced/bundle-pricing.md deleted file mode 100644 index bd95f1d9..00000000 --- a/docs/flashbots-auction/searchers/advanced/bundle-pricing.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: bundle pricing ---- - -### Understanding 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. - -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. - -### Bundle pricing formula - -Here is the formula for how bundle gas pricing is calculated: - -$$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}$$ - -$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. - -### 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. - -### Why aren't my bundles being included? - -There are three reasons to examine. First, your bundles may not be paying a higher gas price than the tail end of a block. You should examine the gas price that your bundles are paying by first simulating the bundles and looking at the coinbase difference and gas consumed. If it is lower than the tail end of recent blocks you will need to up your gas price accordingly. - -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. diff --git a/docs/flashbots-auction/searchers/advanced/eip1559.mdx b/docs/flashbots-auction/searchers/advanced/eip1559.mdx deleted file mode 100644 index a50913c2..00000000 --- a/docs/flashbots-auction/searchers/advanced/eip1559.mdx +++ /dev/null @@ -1,62 +0,0 @@ ---- -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 - -**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** - -Signing bundles with a legacy transaction: -```js -const signedTransactions = await flashbotsProvider.signBundle([ - { - signer: authSigner, - transaction: { - to: "0xf1a54b075fb71768ac31b33fd7c61ad8f9f7dd18", - gasPrice: 10, - gasLimit: 33000, - chainId: 5, - value: 0, - }, - }, - ]); -``` - -Signing bundles with EIP-1559 transactions (note: `chainId` is a required attribute for 1559 transaction `type: 2`): -```js -const block = await provider.getBlock("latest"); -const maxBaseFeeInFutureBlock = FlashbotsBundleProvider.getMaxBaseFeeInFutureBlock(block.baseFeePerGas, 1); -const priorityFee = BigNumber.from(10).pow(9); -const signedTransactions = await flashbotsProvider.signBundle([ - { - signer: authSigner, - transaction: { - to: "0xf1a54b075fb71768ac31b33fd7c61ad8f9f7dd18", - type: 2, - maxFeePerGas: priorityFee.add(maxBaseFeeInFutureBlock), - maxPriorityFeePerGas: priorityFee, - gasLimit: 33000, - chainId: 5, - value: 0, - }, - }, - ]); -``` - -## FAQ -### Can a transaction specify `maxFeePerGas=0` -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. - -### 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. - -### How can I send a transaction from an account with 0 ETH, like one with a malicious `sweeper` running against it? -We have a working example of how to accomplish this in our [Sponsored Transaction Github Repository](https://github.com/flashbots/searcher-sponsored-tx/), which has been updated to work with EIP-1559. - -### Where can I learn more about EIP-1559? -[EIP-1559 Hackmd Cheat Sheet](https://hackmd.io/@q8X_WM2nTfu6nuvAzqXiTQ/1559-wallets) diff --git a/docs/flashbots-auction/searchers/advanced/private-transaction.mdx b/docs/flashbots-auction/searchers/advanced/private-transaction.mdx deleted file mode 100644 index ba7dcdb2..00000000 --- a/docs/flashbots-auction/searchers/advanced/private-transaction.mdx +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: private transactions ---- - -import Tabs from '@theme/Tabs'; -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. - -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. - -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. - -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. - - - - -```ts -const signer = Wallet.createRandom() -const provider = new providers.JsonRpcProvider("http://localhost:8545/") -const flashbotsProvider = await FlashbotsBundleProvider.create(provider, signer) - -const transaction = { - from: signer.address, - to: signer.address, - value: "0x42", - gasPrice: BigNumber.from(99).mul(1e9), - gasLimit: BigNumber.from(21000), -} - -const res = await flashbotsProvider.sendPrivateTransaction({ - transaction, - signer, -}, { - maxBlockNumber: (await provider.getBlockNumber()) + 5, // only allow tx to be mined for the next 5 blocks -}); - -const waitRes = await res.wait(); -if (waitRes === FlashbotsTransactionResolution.TransactionIncluded) { - console.log("Private transaction successfully mined.") -} else if (waitRes === FlashbotsTransactionResolution.TransactionDropped) { - console.log("Private transaction was not mined and has been removed from the system.") -} -``` - - - diff --git a/docs/flashbots-auction/searchers/advanced/reputation.md b/docs/flashbots-auction/searchers/advanced/reputation.md deleted file mode 100644 index 99b44d81..00000000 --- a/docs/flashbots-auction/searchers/advanced/reputation.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -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). - -## 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. - -## 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: - -$$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. -$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. - -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). - -## 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. - -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. diff --git a/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx b/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx deleted file mode 100644 index 043575ce..00000000 --- a/docs/flashbots-auction/searchers/advanced/rpc-endpoint.mdx +++ /dev/null @@ -1,354 +0,0 @@ ---- -title: RPC endpoint ---- - -import Tabs from "@theme/Tabs"; -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: - -### eth_sendBundle - -`eth_sendBundle` can be used to send your bundles to the relay. The `eth_sendBundle` RPC has the following payload format: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_sendBundle", - "params": [ - { - 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 maximum timestamp for which this bundle is valid, in seconds since the unix epoch - revertingTxHashes, // (Optional) Array[String], A list of tx hashes that are allowed to revert - } - ] -} -``` - -example: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_sendBundle", - "params": [ - { - "txs": ["0x123abc...", "0x456def..."], - "blockNumber": "0xb63dcd", - "minTimestamp": 0, - "maxTimestamp": 1615920932 - } - ] -} -``` - -example response: - -```json -{ - "jsonrpc": "2.0", - "id": "123", - "result": { - "bundleHash": "0x2228f5d8954ce31dc1601a8ba264dbd401bf1428388ce88238932815c5d6f23f" - } -} -``` - -### eth_callBundle - -`eth_callBundle` can be used to simulate a bundle against a specific block number, including simulating a bundle at the top of the next block. The `eth_callBundle` RPC has the following payload format: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_callBundle", - "params": [ - { - 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 - 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": [ - { - "txs": ["0x123abc...", "0x456def..."], - "blockNumber": "0xb63dcd", - "stateBlockNumber": "latest", - "timestamp": 1615920932 - } - ] -} -``` - -example response: - -```json -{ - "jsonrpc": "2.0", - "id": "123", - "result": { - "bundleGasPrice": "476190476193", - "bundleHash": "0x73b1e258c7a42fd0230b2fd05529c5d4b6fcb66c227783f8bece8aeacdd1db2e", - "coinbaseDiff": "20000000000126000", - "ethSentToCoinbase": "20000000000000000", - "gasFees": "126000", - "results": [ - { - "coinbaseDiff": "10000000000063000", - "ethSentToCoinbase": "10000000000000000", - "fromAddress": "0x02A727155aeF8609c9f7F2179b2a1f560B39F5A0", - "gasFees": "63000", - "gasPrice": "476190476193", - "gasUsed": 21000, - "toAddress": "0x73625f59CAdc5009Cb458B751b3E7b6b48C06f2C", - "txHash": "0x669b4704a7d993a946cdd6e2f95233f308ce0c4649d2e04944e8299efcaa098a", - "value": "0x" - }, - { - "coinbaseDiff": "10000000000063000", - "ethSentToCoinbase": "10000000000000000", - "fromAddress": "0x02A727155aeF8609c9f7F2179b2a1f560B39F5A0", - "gasFees": "63000", - "gasPrice": "476190476193", - "gasUsed": 21000, - "toAddress": "0x73625f59CAdc5009Cb458B751b3E7b6b48C06f2C", - "txHash": "0xa839ee83465657cac01adc1d50d96c1b586ed498120a84a64749c0034b4f19fa", - "value": "0x" - } - ], - "stateBlockNumber": 5221585, - "totalGasUsed": 42000 - } -} -``` - -### 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`](https://docs.alchemy.com/alchemy/apis/ethereum/eth-sendPrivateTransaction/?a=fb) is also supported for free on [Alchemy](https://alchemy.com/?a=fb). - -This method has the following JSON-RPC format: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_sendPrivateTransaction", - "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 - }] -} -``` - -example request: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_sendPrivateTransaction", - "params": [ - { - "tx": "0x123abc...", - "maxBlockNumber": "0xcd23a0", - "preferences": { "fast": true } // optional, see https://docs.flashbots.net/flashbots-protect/rpc/fast-mode - } - ] -} -``` - -example response: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": "0x45df1bc3de765927b053ec029fc9d15d6321945b23cac0614eb0b5e61f3a2f2a" // tx hash -} -``` - -### eth_cancelPrivateTransaction - -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. - -This method has the following JSON-RPC format: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_cancelPrivateTransaction", - "params": [{ - txHash, // String, transaction hash of private tx to be cancelled - }] -} -``` - -example request: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "eth_cancelPrivateTransaction", - "params": [ - { - "txHash": "0x45df1bc3de765927b053ec029fc9d15d6321945b23cac0614eb0b5e61f3a2f2a" - } - ] -} -``` - -example response: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": true // true if tx successfully cancelled, false if not -} -``` - -### 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: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "flashbots_getUserStats", - "params": [ - blockNumber, // String, a hex encoded recent block number, in order to prevent replay attacks. Must be within 20 blocks of the current chain tip. - ] -} -``` - -example response: - -```json -{ - "is_high_priority": true, - "all_time_miner_payments": "1280749594841588639", - "all_time_gas_simulated": "30049470846", - "last_7d_miner_payments": "1280749594841588639", - "last_7d_gas_simulated": "30049470846", - "last_1d_miner_payments": "142305510537954293", - "last_1d_gas_simulated": "2731770076" -} -``` - -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 - -### flashbots_getBundleStats - -The `flashbots_getBundleStats` JSON-RPC method returns stats for a single bundle. You must provide a blockNumber and the bundleHash, and the signing address must be the same as the one who submitted the bundle. - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "method": "flashbots_getBundleStats", - "params": [ - { - bundleHash, // String, returned by the flashbots api when calling eth_sendBundle - blockNumber, // String, the block number the bundle was targeting (hex encoded) - } - ] -} -``` - -example response: - -```json -{ - "isSimulated": true, - "isSentToMiners": true, - "isHighPriority": true, - "simulatedAt": "2021-08-06T21:36:06.317Z", - "submittedAt": "2021-08-06T21:36:06.250Z", - "sentToMinersAt": "2021-08-06T21:36:06.343Z" -} -``` - -### 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. - -```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. - -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: - - - - -```ts -import { Wallet, utils } from "ethers"; - -const privateKey = "0x1234"; -const wallet = new Wallet(privateKey); -const body = - '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}'; -const signature = wallet.address + ":" + wallet.signMessage(utils.id(body)); -``` - - - - -```py -from web3 import Web3 -from eth_account import Account, messages - -body = '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}' -message = messages.encode_defunct(text=Web3.keccak(text=body).hex()) -signature = Account.from_key(private_key).address + ':' + Account.sign_message(message, private_key).signature.hex() -``` - - - - -```go -body := `{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}` -hashedBody := crypto.Keccak256Hash([]byte(body)).Hex() -sig, err := crypto.Sign(accounts.TextHash([]byte(hashedBody)), privKey) -signature := crypto.PubkeyToAddress(privKey.PublicKey).Hex() + ":" + hexutil.Encode(sig) -``` - - - diff --git a/docs/flashbots-auction/searchers/advanced/troubleshooting.mdx b/docs/flashbots-auction/searchers/advanced/troubleshooting.mdx deleted file mode 100644 index 1d23fbb3..00000000 --- a/docs/flashbots-auction/searchers/advanced/troubleshooting.mdx +++ /dev/null @@ -1,227 +0,0 @@ ---- -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: -``` -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 -``` - -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. - -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). - -## Does your transaction work and pay enough? -Covers: -``` -1. Transaction failure (ANY within the bundle) -2. Incentives (gas price/coinbase transfers) not high enough to offset value of block space -``` - -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) -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)_ - -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: - - 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. -``` - const signedTransactions = await flashbotsProvider.signBundle(transactionBundle) - const simulation = await flashbotsProvider.simulate(signedTransactions, targetBlockNumber, targetBlockNumber + 1) - console.log(JSON.stringify(simulation, null, 2)) -``` - -Output: -``` -{ - "totalGasUsed": 98564, - "bundleHash": "0x9a6a9fa038343fe3c57260fb7bdb2c79ebadb3088656300d8a494123ebda6d85", - "coinbaseDiff": BigNumber(0x034dc9949767a4), - }, - "results": [ - { - "coinbaseDiff": "929953106847652", - "ethSentToCoinbase": "0", - "fromAddress": "0x9874Ef8519a0Fc7a6B553aad92fDF0E469488931", - "gasFees": "929953106847652", - "gasPrice": "35008022393", - "gasUsed": 29964, - "toAddress": "0x48B2dD9CEFbA73c60882478a16BC3428Aceed2B9", - "txHash": "0xee3f6f22bf3b4740b36833d41d4872f48f98c6328fa04b3679558e482ba0e328", - "value": "0x0000000000000000000000000000000000000000000000000000000000000001" - }, - ... - ], -} -``` - -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? -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). - -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 -2. Compare the conflicting bundle's `effective priority fee` with your own (to see if you should be bidding more to remain competitive) - -### Types of conflicts -There are numerous reasons why two bundles might conflict. Consider that the basic algorithm for merging bundles is: -1. Simulate each bundle at the top of the block -2. Sort bundles by `effective priority fee`, highest first -3. In descending order, try each bundle **that does not error or lower its effective priority fee from top-of-block simulation** until you reach a maximum bundle inclusion count or you run out of profitable bundles - -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. - -### 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: - -1. Simulate your bundle at the head of the target block, note its revert states and `effective priority fee` -2. Fetch all bundles found in the target block -3. Simulate [bundle1 + your bundle] as a single bundle, check the behavior of your bundle -4. Simulate [bundle1 + bundle2 + your bundle] as a single bundle, see the behavior of your bundle -5. Simulate [bundle1 + bundle2 + ...bundleN + your bundle] as a single bundle, see the behavior of your bundle -6. And so on... - -Using this method, we can identify the conflicting bundle that caused your target bundle to change behavior. The `Flashbots ethers.js provider` has a built-in helper function for running this strategy called `getConflictingBundle()`: - -``` -const signedTransactions = await flashbotsProvider.signBundle(transactionBundle) -console.log(await flashbotsProvider.getConflictingBundle( - signedTransactions, - 13140328 // blockNumber - )) -``` - -Output: -``` -{ - "conflictType": FlashbotsBundleConflictType.NonceCollision, - "initialSimulation": { - "totalGasUsed": 205860, - "bundleHash": "0x1720ea33d96dca026dddd5689f8cad21966988348ced04e9054a0dca5d60f1d4", - "coinbaseDiff": BigNumber(0x0176750858d000), - }, - "results": [...] - }, - "targetBundleGasPricing": { - "gasUsed": 205860, - "txCount": 1, - "gasFeesPaidBySearcher": BigNumber(0x0176750858d000), - "priorityFeesReceivedByMiner": BigNumber(0x52efd8d80dbc24), - "ethSentToCoinbase": BigNumber.from(0x00), - "effectiveGasPriceToSearcher": BigNumber(0x77359400), - "effectivePriorityFeeToMiner": BigNumber(0x1a6734f601) - }, - "conflictingBundleGasPricing": { - "gasUsed": 396462, - "txCount": 3, - "gasFeesPaidBySearcher": BigNumber(0xc4c3c97ce1bff8b4), - "priorityFeesReceivedByMiner": BigNumber(0xc4213e4d7ad82006), - "ethSentToCoinbase": BigNumber(0xc4c2663d3b804731), - "effectiveGasPriceToSearcher": BigNumber(0x410ce509aa1e), - "effectivePriorityFeeToMiner": BigNumber(0x40f2069f201d) - }, - "conflictingBundle": [ - { - "transaction_hash": "0x23a33038289dda1b6e722835d2b9388cb41d96d085c19ca6b71bb3e9697e6692", - "tx_index": 0, - "bundle_type": "flashbots", - "bundle_index": 0, - "block_number": 13140328, - "eoa_address": "0x38563699560e4512c7574C8cC5Cf89fd43923BcA", - "to_address": "0x000000000035B5e5ad9019092C665357240f594e", - "gas_used": 100893, - "gas_price": "0", - "coinbase_transfer": "0", - "total_miner_reward": "0" - }, - ... - ] -} -``` - -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. -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? -Covers: -``` -4. Bundle received too late to appear in target block -``` - -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 - -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. - -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). - -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. - -``` -console.log( - await flashbotsProvider.getBundleStats("0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234", 13509887) - ) - -``` - -Output: -``` -{ - "isSimulated": true, - "isSentToMiners": true, - "isHighPriority": true, - "simulatedAt": "2021-10-29T04:00:50.526Z", - "submittedAt": "2021-10-29T04:00:50.472Z", - "sentToMinersAt": "2021-10-29T04:00:50.546Z" -} -``` - -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? -``` -5. A miner for target block not running Flashbots -``` - -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. - -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. - -## 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: - -[Fill out our Searcher Issue Reporting Form](https://www.notion.so/flashbots/Searcher-Issue-Reporting-Form-700a5ff3843a443c993912099b4c1b56) - -Be sure to include the output from the above RPC calls: -- eth_callBundle / simulate -- eth_getBundleStats -- getConflictingBundle - -in the form submission. diff --git a/docs/flashbots-auction/searchers/advanced/understanding-bundles.mdx b/docs/flashbots-auction/searchers/advanced/understanding-bundles.mdx deleted file mode 100644 index 7ecf6b3d..00000000 --- a/docs/flashbots-auction/searchers/advanced/understanding-bundles.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -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: - -```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 - { - 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 deleted file mode 100644 index b0721ca7..00000000 --- a/docs/flashbots-auction/searchers/example-searchers/searcher-sponsored-tx.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -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. - -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 diff --git a/docs/flashbots-auction/searchers/faq.md b/docs/flashbots-auction/searchers/faq.md deleted file mode 100644 index 4d5a950e..00000000 --- a/docs/flashbots-auction/searchers/faq.md +++ /dev/null @@ -1,211 +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 dedicated [#🤖searchers](https://discord.com/invite/7hvTycdNcK) channel on Discord! - -### What is Flashbots Auction? - -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. \ No newline at end of file diff --git a/docs/flashbots-auction/searchers/libraries/ethers-js-provider.md b/docs/flashbots-auction/searchers/libraries/ethers-js-provider.md deleted file mode 100644 index 82330dcc..00000000 --- a/docs/flashbots-auction/searchers/libraries/ethers-js-provider.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -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. - -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. - -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. - -Access the ethers-provider-flashbots-bundle repository [here](https://github.com/flashbots/ethers-provider-flashbots-bundle). diff --git a/docs/flashbots-auction/searchers/libraries/golang.md b/docs/flashbots-auction/searchers/libraries/golang.md deleted file mode 100644 index b8e3a977..00000000 --- a/docs/flashbots-auction/searchers/libraries/golang.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -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. - -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`). - -Golang libraries: - -* [github.com/metachris/flashbotsrpc](https://github.com/metachris/flashbotsrpc) -* [github.com/cryptoriums/flashbot](https://github.com/cryptoriums/flashbot) diff --git a/docs/flashbots-auction/searchers/quick-start.mdx b/docs/flashbots-auction/searchers/quick-start.mdx deleted file mode 100644 index 43d50563..00000000 --- a/docs/flashbots-auction/searchers/quick-start.mdx +++ /dev/null @@ -1,205 +0,0 @@ ---- -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). - -See you on-chain! ⚡🤖 - -### Who should use Flashbots Auction? - -1. Ethereum bot operators (we call them "searchers") looking for fast, and risk free access to blockspace (for example, arbitrage and liquidation bots) -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) - -### 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. - -Getting onboarded to Flashbots is easy for searchers; you simply need to update how you send transactions. - -### How to send your first Flashbots bundle - -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 -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. - -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: - - - - -```ts -const ethers = require("ethers.js"); -const { - FlashbotsBundleProvider, -} = require("@flashbots/ethers-provider-bundle"); -const provider = new ethers.providers.JsonRpcProvider({ - url: ETHEREUM_RPC_URL, -}); -// Standard json rpc provider directly from ethers.js. For example you can use Infura, Alchemy, or your own node. - -const authSigner = new ethers.Wallet( - "0x0000000000000000000000000000000000000000000000000000000000000000" -); -// `authSigner` is an Ethereum private key that does NOT store funds and is NOT your bot's primary key. -// This is an identifying key for signing payloads to establish reputation and whitelisting - -const flashbotsProvider = await FlashbotsBundleProvider.create( - provider, - authSigner -); -// Flashbots provider requires passing in a standard provider and an auth signer -``` - - - - -```python -import os - -from eth_account.account import Account -from eth_account.signers.local import LocalAccount -from flashbots import flashbot - from web3 import Web3, HTTPProvider - - -# Create a web3 object with a standard json rpc provider, such as Infura, Alchemy, or your own node. -w3 = Web3(HTTPProvider("http://localhost:8545/")) - -# ETH_ACCOUNT_SIGNATURE is an Ethereum private key that does NOT store funds and is NOT your bot's primary key. -# This is an identifying key for signing payloads to establish reputation and whitelisting -ETH_ACCOUNT_SIGNATURE: LocalAccount = Account.from_key(os.environ.get("ETH_SIGNATURE_KEY")) - -# Flashbots providers require both a standard provider and ETH_ACCOUNT_SIGNATURE (to establish reputation) -flashbot(w3, ETH_ACCOUNT_SIGNATURE) -``` - - - - -```go -package main - -import ( - "bytes" - "crypto/ecdsa" - "encoding/json" - "fmt" - "io/ioutil" - "math/big" - "net/http" - "time" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" -) - -const ( - j = "application/json" - flashbotURL = "https://relay.flashbots.net/" - stats = "flashbots_getUserStats" - flashbotXHeader = "X-Flashbots-Signature" - p = "POST" -) - -var ( - privateKey, _ = crypto.HexToECDSA( - "2e19800fcbbf0abb7cf6d72ee7171f08943bc8e5c3568d1d7420e52136898154", - ) -) - -func flashbotHeader(signature []byte, privateKey *ecdsa.PrivateKey) string { - return crypto.PubkeyToAddress(privateKey.PublicKey).Hex() + - ":" + hexutil.Encode(signature) -} - -func main() { - mevHTTPClient := &http.Client{ - Timeout: time.Second * 3, - } - currentBlock := big.NewInt(12_900_000) - params := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "method": stats, - "params": []interface{}{ - fmt.Sprintf("0x%x", currentBlock.Uint64()), - }, - } - payload, _ := json.Marshal(params) - req, _ := http.NewRequest(p, flashbotURL, bytes.NewBuffer(payload)) - headerReady, _ := crypto.Sign( - accounts.TextHash([]byte(hexutil.Encode(crypto.Keccak256(payload)))), - privateKey, - ) - req.Header.Add("content-type", j) - req.Header.Add("Accept", j) - req.Header.Add(flashbotXHeader, flashbotHeader(headerReady, privateKey)) - resp, _ := mevHTTPClient.Do(req) - res, _ := ioutil.ReadAll(resp.Body) - fmt.Println(string(res)) -} -``` - - - - -Now that we have a private key to identify ourselves with and a Flashbots provider we can create and send a bundle. Here's an example in node.js - -```js -const ethers = require("ethers.js"); -const { - FlashbotsBundleProvider, -} = require("@flashbots/ethers-provider-bundle"); -const provider = new ethers.providers.JsonRpcProvider({ - url: ETHEREUM_RPC_URL, -}); - -const authSigner = new ethers.Wallet( - "0x2000000000000000000000000000000000000000000000000000000000000000" -); -const flashbotsProvider = await FlashbotsBundleProvider.create( - provider, - authSigner -); - -const signedBundle = await flashbotsProvider.signBundle([ - { - signer: SOME_SIGNER_TO_SEND_FROM, - transaction: SOME_TRANSACTION_TO_SEND, - }, -]); - -const bundleReceipt = await flashbotsProvider.sendRawBundle( - signedBundle, - TARGET_BLOCK_NUMBER -); -``` - -That's it! - -### Next steps - -Congrats! You should now have everything you need to start sending transactions to the Flashbots network. - -- If you are looking to interact with the Flashbots Relay without using one of the libraries, check out the [RPC endpoint documentation](/flashbots-auction/searchers/advanced/rpc-endpoint) and other advanced concepts. -- For examples of advanced usage of Flashbots, check out the [example searchers](/flashbots-auction/searchers/example-searchers/simple-arbitrage-bot). -- For additional tools, check out the [searcher libraries.](/flashbots-auction/searchers/libraries/ethers-js-provider) -- For potential MEV opportunities, check out the [MEV job board](https://github.com/flashbots/mev-job-board) 🤠 diff --git a/docs/flashbots-data/blockapi.md b/docs/flashbots-data/blockapi.md deleted file mode 100644 index daa08887..00000000 --- a/docs/flashbots-data/blockapi.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: mev-blocks API ---- -mev-blocks is a a public API for displaying flashbots blocks and transactions. - -Access it here: https://blocks.flashbots.net/ diff --git a/docs/flashbots-data/dashboard.md b/docs/flashbots-data/dashboard.md deleted file mode 100644 index 1c74753f..00000000 --- a/docs/flashbots-data/dashboard.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: flashbots dashboard ---- -Flashbots Dashboard v0 is a near real-time analytics dashboard of Flashbots activity on Ethereum. - -You can access the dashboard here: https://dashboard.flashbots.net and more information about the data & metrics it uses here: https://dashboard.flashbots.net/data-metrics. - -Extra resources: -* [Tweetstorm](https://twitter.com/bertcmiller/status/1392871268953858057) introducing the dashboard diff --git a/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-codebase-deep-dive.mdx b/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-codebase-deep-dive.mdx deleted file mode 100644 index de7278f3..00000000 --- a/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-codebase-deep-dive.mdx +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: codebase - deep dive ---- - -A deep dive into the codebase, particularly for those who are looking to get familiar with both Rust and the inspect codebase - -_Notes courtesy of Will Drevo, [source](https://github.com/worldveil/mev-inspect-rs/blob/master/NOTES.md)_ - -## `main.rs` - -### `main()` - -This is where the execution begins, in the `main()` function. Note it is an async function, which returns a Future. [Read more here](https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html). - -The [gumdrop::Options](https://docs.rs/gumdrop/0.5.0/gumdrop/trait.Options.html) package (crate) is used for command line option parsing. The order of arguments here matters: - -```bash -# will work -./target/release/mev-inspect -u http://localhost:8080 tx 0xa72072f5041bcde89c560ba12cc00b22a87779ee369dbff81a78bba26d35e989 - -# won't parse url -./target/release/mev-inspect tx 0xa72072f5041bcde89c560ba12cc00b22a87779ee369dbff81a78bba26d35e989 -u http://localhost:8080 -# will return "unrecognized option `-u`" -``` - -We parse the arguments with `Opts::parse_args_default_or_exit()`. Next we want to retrieve a tx from a provider (ETH node), but we want to check if it's in the cache. - -We use this line `let Some(ref cache) = opts.cache` to test for this. `opts.cache` is an `Option`, meaning it either has no value (null), or is a `PathBuf`. `Some(&Option)` returns true if the reference is non-null. Additionally, these two are the same: - -```rust -// using ref operator -let Some(ref cache) = opts.cache -// is identical to -let Some(cache) = &opts.cache -``` - -Then we create a provider, either the [ethers::providers::Provider](https://docs.rs/ethers-providers/0.2.2/ethers_providers/struct.Provider.html), or the cached version, which reads from disk. - -### `run()` - -This is a complex function definition: - -```rust -async fn run(provider: M, opts: Opts) -> anyhow::Result<()> { ... } -``` - -* takes the provider & options as input -* returns an [anyhow:::Result](https://docs.rs/anyhow/1.0.0/anyhow/type.Result.html), which is some nice syntactic sugar around catching and printing context and a backtrace if something goes wrong. See [here](https://docs.rs/anyhow/1.0.0/anyhow/trait.Context.html) specifically for how to add context inside a function. -* defines a type `M` that accepts any type that implements the Middleware, Clone, and [static lifetime](https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html#trait-bound) traits. This is like an interface in Java. In our code, you can see how this was done for `CachedProvider` (src/cached_provider.rs). - -We wrap our provider in a reference counter [std::styc::Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html), which is the [C++ equvilent of std::shared_ptr](https://stackoverflow.com/a/49834496), inorder to prevent memory leaks. - -We create a `mev_inspect::HistoricalPrice` object, giving it a provider, the price coming from Uniswap. - -The inspectors are added to a vector. They are encased in `std::Box`es, which tells Rust to put these objects on the heap. This might seem silly at first (...after all, elements in a variable sized data structure like `Vec` (vector) [are stored in the heap](https://stackoverflow.com/a/43642518)), but since we are using generics to hold a list of objects of a different type but all implement the same interface (ie: `Vec>`), the Box has the additional benefit of preventing the compiler from complaining about not knowing how much memory to set aside a prioi. If you remove the std::Box encasement, you'll get: - -``` -the size for values of type `dyn mev_inspect::Inspector` cannot be known at compilation time - -doesn't have a size known at compile-time -``` - -The [`dyn` keyword](https://doc.rust-lang.org/std/keyword.dyn.html) isn't strictly necessary (the compiler will make this trait dynamically dispatched), but know that it's depcrated and you'll get a warning. - -Next we create a vector of reducers. - -After that, we create a processor. - -The connection between these different types seems to be: - -- **Inspectors** are "parsers" that know how a given contract is set up, and are able to extract necessary fields -- **Reducers** are "checkers" that examine extracted fields for different MEV actions -- **Processor** is a coordinating object that takes inspectors and parsers to inspect transactions - -Next we create a database connection. - -Next we match on command, but if it's a tx, we inspect. - -### Inspecting a tx - -We create a `mev_inspect::types::Inspection`. This seems to choose the correct inspector and from that extracts: - -- status (success/fail) -- actions that happened, which can be any of the ones described [here](inspect-codebase-design) -- protocols involved -- the sender, contract (if any), and proxy contract (if any) of the tx -- tx hsh & block height - -We query the provider for: - -- the gas_used (from receipt) -- the gas_price (from tx) - - -With the inspection, gas_price, gas_used, and pricing in hand, we can coalesce into a `mev_inspect::types::Evaluation` struct which holds: - -- the `mev_inspect::types::Inspection` object -- gas_used, gas_price -- actions involved -- profit made! - -Finally, we insert the evaluation into the database. - -### Inspecting a block - -If the command is instead for a range of blocks, we iterate through this range one by one and process the block given the usual suspects: - -```rust -process_block(&mut lock, block, &provider, &processor, &mut db, &prices).await? -``` - -### `src/prices.rs` - -First, generate the ABI with [ethers::contract::abigen](https://docs.rs/ethers-contract/0.1.3/ethers_contract/macro.abigen.html) macro for the Uniswap contract, and store it in the `abi/` folder. This will help us decode binary data from the transactions that interact with this contract. There are many resources on this, but see [SO answer here](https://ethereum.stackexchange.com/a/1171/34397). - - -### Sample inspector - `src/inspectors/aave.rs` - -This is the inspector for Aave. - -[As is customary in Rust](https://doc.rust-lang.org/std/keyword.impl.html), we define a `struct` for the data fields, and an `impl` for the methods on the object itself. - -Aave inspector doesn't need a provider because it can simply load the ABI included in the repo. - -Next we implment the Inspector interface for the Aave object, which is a function that takes in a mutable inspection object that we'll write fields to as a result of the inspection logic. - - -### Deriving from Traits - -It seems in rust that having structs derive from traits like `Debug` is universally a good idea, but there are some others to be careful of. [Good post on the subject here](https://users.rust-lang.org/t/what-traits-should-i-normally-derive/484/9). diff --git a/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-codebase-design.md b/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-codebase-design.md deleted file mode 100644 index dfa34456..00000000 --- a/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-codebase-design.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: codebase - design ---- - -mev-inspect aims to quantify a lower bound of MEV extracted on Ethereum from txs such as arbitrage and liquidations. The profits are denominated in Ether and for cases where the reward is extracted in a non-ETH token, we query the historical price (via uniswap) and convert it accordingly. Additionally, we also count as MEV txs transactions with failed arb attempts and liquidation checks (where they might decide to check if the position is still liquidatable and halt accordingly) as they still end up paying the miner a gas fee. - -Components: -* Inspectors - * Examines transactions to see if they belong to a relevant protocol we're interested in - are "parsers" that know how a given contract is set up, and are able to extract necessary fields -* Reducers and Processor - * Goes through the relavent fields to check for MEV, quantify/identify them, and store it into the `mev-inspections` table of the database - -Protocols supported (as defined in `src/inspectors`): -* Uniswap (+ forks with shared ABI) -* Balancer -* Curve -* 0x -* Aave -* Compound -* DyDx - -Action types stored (as defined in `src/reducers`): -* Arbitrage -* Liquidations - * Including LiquidationCheck -* Trades - * We store trades even if they're not a complete arb in order to identify arb captured across multiple transactions in subsequent blocks -* AddLiquidity -* WETH deposits/withdrawals -* Token Transfers - -### tracing: - -Direct ETH/token transfers, trades routed through an aggregator or a router are trivial to parse/filter (by looking at the tx input data + receipts) but contract interactions (which bots often employ) can be complex to identify. Transaction tracing allows us to dig deeper into the tx execution cycle to look through the state changes, internal calls and additional proxy contracts the tx interacts with. mev-inspect uses OpenEthereum archive node traces with the following types (by action_type): - -* `Call`, which happens when a method on the same contract or a different one is executed. We can identify the input parameters in each instance by looking at this trace. -* `Self-destruct`, when a arbitrage contract destroys the code at its address and transfers the ETH held in the contract to an EOA. Common pattern among searchers given gas refunds. -* `Create`, when a contract deploys another contract (and potentially transfers assets to it). -* `Reward`, pertaining to the block reward and uncle reward. - -On proxy implementation: - -Aside from the eoa that initiates the transaction and the recepient (which can be another eoa or a contract), we are also interested in identifying any proxy implementations used during MEV extraction. We do that by iterating over the traces to find delegate calls originating from the contract to any other proxy implementations. - -![delegate_call_illustration](https://camo.githubusercontent.com/7cde2d066ebfa7c38adc324dc955e42278fa114d253d3804f3f85d20f7ace39a/68747470733a2f2f692e696d6775722e636f6d2f30564a694562762e706e67) - - -More on delegate calls [here](https://medium.com/coinmonks/delegatecall-calling-another-contract-function-in-solidity-b579f804178c) - -Deeper dive into the rust implementation specifics [here](https://github.com/worldveil/mev-inspect-rs/blob/master/NOTES.md) diff --git a/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-inspector-example.md b/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-inspector-example.md deleted file mode 100644 index b6e3e5d3..00000000 --- a/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-inspector-example.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: sample flow - liquidation tx ---- - -### Sample flow of Aave inspector on liquidation tx [0xc8d2501d28800b1557eb64c5d0e08fd6070c15b6c04c39ca05631f641d19ffb2](https://etherscan.io/tx/0xc8d2501d28800b1557eb64c5d0e08fd6070c15b6c04c39ca05631f641d19ffb2) - -![tx_image](https://i.imgur.com/pwHNF2I.png) - -Command: `./target/release/mev-inspect --db-cfg postgresql://postgres:postgres@localhost -u tx 0xc8d2501d28800b1557eb64c5d0e08fd6070c15b6c04c39ca05631f641d19ffb2` - -Output: - - Found: 0xc8d2501d28800b1557eb64c5d0e08fd6070c15b6c04c39ca05631f641d19ffb2 - Revenue: 140406510074700360 WEI - Cost: 88544390000000000 WEI - Actions: {Liquidation} - Protocols: {Aave} - Status: Success - -mev-inspect parses the tx and identifies the tx to be a aave liquidation with a revenue of ~0.14 ETH and a cost of ~0.08 ETH (gas fees) - -Money markets like AAVE allow people to borrow assets using over-collateralization mechanism that includes liquidation incentives for bots that repay the debt, as defined [here](https://docs.aave.com/risk/asset-risk/risk-parameters). In this instance, 0x1acA borrowed USDT using ETH as collateral. When a liquidation bot (0x3abc here) repays the debt to the protocol, it receives the collateral at a discount. - -First, mev-inspect takes the transaction hash and fetches the traces using the provider here in [main.rs](https://github.com/flashbots/mev-inspect-rs/blob/2a5c015752f71ef27429d1e8b98a2380864f834f/src/main.rs#L131). - -Then, we pass each trace through our processor to attempt matching it with an existing protocol, using `inspect_one` here in [src/inspectors/batch.rs](https://github.com/flashbots/mev-inspect-rs/blob/2a5c015752f71ef27429d1e8b98a2380864f834f/src/inspectors/batch.rs#L56). If the actions identified by the inspector are not empty, we attempt inspection and finally reduce the revenue. - -In this particular instance, we identify a trace to the aave protocol that has the signature `liquidationCall` assosiated with liquidations, here in [inspectors/aave.rs](https://github.com/flashbots/mev-inspect-rs/blob/2a5c015752f71ef27429d1e8b98a2380864f834f/src/inspectors/aave.rs#L42). We then proceed to extract the token amounts (of asset paid back + collateral) alongside other relevant information. - -Finally, we evaluate all the inspection actions returned to categorize the MEV in a protocol agnostic way (either arbitrage, liquidation, or simply trades) to store it in the database, here in [evaluation.rs](https://github.com/flashbots/mev-inspect-rs/blob/2a5c015752f71ef27429d1e8b98a2380864f834f/src/types/evaluation.rs#L69) - -The net profit (if the liquidation is successful) is calculated here in [reducers/liquidation.rs](https://github.com/flashbots/mev-inspect-rs/blob/2a5c015752f71ef27429d1e8b98a2380864f834f/src/reducers/liquidation.rs#L80) diff --git a/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-quick-start.md b/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-quick-start.md deleted file mode 100644 index f6fce8c5..00000000 --- a/docs/flashbots-data/deprecated/mev-inspect-rs/inspect-quick-start.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: quick start ---- -This quickstart guide contains all the information necessary to get you up and running using [mev-inspect-rs](https://github.com/flashbots/mev-inspect-rs). If you have any questions, do not hesitate to ask in our [Discord](https://discord.gg/GezzK33W). - - -### requirements: -* Rust and Cargo, installation instructions [here](https://doc.rust-lang.org/cargo/getting-started/installation.html) -* OpenEthereum node running in archive mode with tracing enabled: - * `openethereum --pruning archive --tracing on` - * If you are interested in contributing to mev-inspect but do not have access to an archive node, please reach out to us in our discord. -* Postgres instance running locally - * Using docker: `docker run --name postgres -e POSTGRES_PASSWORD=postgres -p 127.0.0.1:5432:5432 -d postgres` - -### instructions: -* Fetch the repository: `git clone https://github.com/flashbots/mev-inspect-rs.git` -* Build: `cd mev-inspect-rs/ && cargo build --release` -* Run: - * To inspect a single tx, run `./target/release/mev-inspect --db-cfg postgresql://postgres:postgres@localhost -u tx 0x5243f353cf41f8394ba480e3c15fb57881a5d8ec985874520a1b322ecf2519f4` - * Note that the above command assumes postgres username + password to be "postgres", change credentials accordingly. - * Sample output: - - Found: 0x5243f353cf41f8394ba480e3c15fb57881a5d8ec985874520a1b322ecf2519f4 - Revenue: 3137921082854343002 WEI - Cost: 95196411000000000 WEI - Actions: {Liquidation} - Protocols: {Aave} - Status: Success - - * Similarly, to inspect all transactions in an entire range of blocks, use: `./target/release/mev-inspect --db-cfg postgresql://postgres:postgres@localhost -u blocks -f 12472860 -t 12472867` - * Blocks are inspected in parallel for efficiency -* Test: `cargo test` diff --git a/docs/flashbots-data/mev-explore.md b/docs/flashbots-data/mev-explore.md deleted file mode 100644 index 6ab38a84..00000000 --- a/docs/flashbots-data/mev-explore.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: mev-explore ---- -MEV-Explore v0 is a live dashboard of MEV activity on the Ethereum network and MEV transactions explorer. - -You can access the dashboard here: https://explore.flashbots.net and documentation about the metrics we are displaying here: https://explore.flashbots.net/data-metrics. - -Extra resources: -* Explore v0 launch blogpost: [Quantifying MEV: Introducing MEV-Explore v0](https://medium.com/flashbots/quantifying-mev-introducing-mev-explore-v0-5ccbee0f6d02) diff --git a/docs/flashbots-data/mev-inspect-py/data/arbitrages.md b/docs/flashbots-data/mev-inspect-py/data/arbitrages.md deleted file mode 100644 index 097b219a..00000000 --- a/docs/flashbots-data/mev-inspect-py/data/arbitrages.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: arbitrages ---- -### description - -an **arbitrage** is an circuit of swaps - -arbitrages are joined to their corresponding swaps in the **arbitrage_swaps** table - -### fields - -| Column | Type | Nullable | Description | -|----------------------|-----------------------------|----------|-----------------------------------------------------------------------| -| id | character varying(256) | not null | unique id | -| created_at | timestamp without time zone | not null | when the entry was added to the database | -| block_number | numeric | not null | block number | -| transaction_hash | character varying(256) | not null | transaction hash | -| account_address | character varying(256) | not null | address that took the profit of the arb - can be a contract or an EOA | -| profit_token_address | character varying(256) | not null | token that profit was taken in | -| profit_amount | numeric | not null | gross profit - note: this does not account for miner payment | -| start_amount | numeric | not null | starting amount of the profit token | -| end_amount | numeric | not null | end amount of the profit token | diff --git a/docs/flashbots-data/mev-inspect-py/data/classified_traces.md b/docs/flashbots-data/mev-inspect-py/data/classified_traces.md deleted file mode 100644 index 254d8254..00000000 --- a/docs/flashbots-data/mev-inspect-py/data/classified_traces.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: classified_traces ---- -### description - -a **classified trace** represents a single trace - -classified traces optionally include: -- a classification for the call (ex: transfer, swap, liquidation) -- decoded function name and inputs - -### fields - -| Column | Type | Nullable | Description | -|--------------------|-----------------------------|----------|-------------------------------------------------------------------------------------------| -| classified_at | timestamp without time zone | not null | when this trace was added to the database | -| block_number | numeric | not null | block number | -| transaction_hash | character varying(66) | not null | transaction hash | -| trace_address | integer[] | not null | trace address | -| trace_type | character varying(256) | not null | the type of call in the trace - one of `call`, `create`, `delegate_call`, `reward`, `suicide` | -| classification | character varying(256) | not null | classification for the trace - one of `unknown`, `swap`, `burn`, `transfer`, `liquidate` | -| protocol | character varying(256) | | the protocol associated with the trace | -| abi_name | character varying(1024) | | the ABI used to decode this trace | -| function_name | character varying(2048) | | the name of the function called | -| function_signature | character varying(2048) | | the signature of the function called | -| inputs | json | | inputs of the function | -| from_address | character varying(256) | | from address | -| to_address | character varying(256) | | to address | -| gas | numeric | | gas | -| value | numeric | | ETH value | -| gas_used | numeric | | gas used | -| error | character varying(256) | | error | diff --git a/docs/flashbots-data/mev-inspect-py/data/miner_payments.md b/docs/flashbots-data/mev-inspect-py/data/miner_payments.md deleted file mode 100644 index 89bd354c..00000000 --- a/docs/flashbots-data/mev-inspect-py/data/miner_payments.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: miner_payments ---- -### description - -a **miner payment** is how much was paid to a miner in a given transaction - -miner payment includes payment through gas and coinbase transfers - -### fields - -| Column | Type | Nullable | Description | -|----------------------------------|-----------------------------|----------|--------------------------------------------------------| -| created_at | timestamp without time zone | not null | when the entry was added to the database | -| block_number | numeric | not null | block number | -| transaction_hash | character varying(66) | not null | transaction hash | -| transaction_index | numeric | not null | transaction index | -| miner_address | character varying(256) | not null | address of the miner | -| coinbase_transfer | numeric | not null | amount of ETH was paid as direct transfer to the miner | -| base_fee_per_gas | numeric | not null | base fee for this block | -| gas_price | numeric | not null | gas price (excludes coinbase transfer) | -| gas_price_with_coinbase_transfer | numeric | not null | gas price (includes coinbase transfer) | -| gas_used | numeric | not null | total gas used by the transaction | -| transaction_to_address | character varying(256) | | to address of the transaction | -| transaction_from_address | character varying(256) | | from address of the transaction | diff --git a/docs/flashbots-data/mev-inspect-py/data/swaps.md b/docs/flashbots-data/mev-inspect-py/data/swaps.md deleted file mode 100644 index 2d6082ec..00000000 --- a/docs/flashbots-data/mev-inspect-py/data/swaps.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: swaps ---- -### description - -a **swap** is a swap between two ERC-20 tokens - -### fields -| Column | Type | Nullable | Description | -|-------------------|-----------------------------|----------|-------------------------------------------| -| created_at | timestamp without time zone | not null | when the entry was added to the database | -| block_number | numeric | not null | block number | -| transaction_hash | character varying(66) | not null | transaction hash | -| trace_address | integer[] | not null | trace address | -| abi_name | character varying(1024) | not null | name of the ABI used to decode the swap | -| pool_address | character varying(256) | not null | pool address | -| from_address | character varying(256) | not null | address where tokens are coming from | -| to_address | character varying(256) | not null | address where swapped tokens are going to | -| token_in_address | character varying(256) | not null | address of the token going in | -| token_in_amount | numeric | not null | amount of the token going in | -| token_out_address | character varying(256) | not null | address of the token going out | -| token_out_amount | numeric | not null | amount of the token going out | -| protocol | character varying(256) | | protocol | -| error | character varying(256) | | error | diff --git a/docs/flashbots-data/mev-inspect-py/data/transfers.md b/docs/flashbots-data/mev-inspect-py/data/transfers.md deleted file mode 100644 index 343f7bee..00000000 --- a/docs/flashbots-data/mev-inspect-py/data/transfers.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: transfers ---- -### description - -a **transfer** is an ERC-20 token transfer - -### fields - -| Column | Type | Nullable | Description | -|------------------|-----------------------------|----------|---------------------------------------------| -| created_at | timestamp without time zone | not null | when the transfer was added to the database | -| block_number | numeric | not null | block number | -| transaction_hash | character varying(66) | not null | transaction hash | -| trace_address | character varying(256) | not null | trace address | -| from_address | character varying(256) | not null | who the tokens are transfering from | -| to_address | character varying(256) | not null | who the tokens are transfering to | -| token_address | character varying(256) | not null | token address | -| amount | numeric | not null | amount | -| protocol | character varying(256) | | protocol associated with the transfer | -| error | character varying(256) | | error | diff --git a/docs/flashbots-data/mev-inspect-py/exploring.md b/docs/flashbots-data/mev-inspect-py/exploring.md deleted file mode 100644 index b7fa8eda..00000000 --- a/docs/flashbots-data/mev-inspect-py/exploring.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: exploring ---- - -All inspect output data is stored in Postgres. - -To connect to the local Postgres database for querying, launch a client container with: -``` -./mev db -``` - -When you see the prompt -``` -mev_inspect=# -``` - -You're ready to query! - -Try finding the total number of swaps decoded with UniswapV3Pool -``` -SELECT COUNT(*) FROM swaps WHERE abi_name='UniswapV3Pool'; -``` - -or top 10 arbs by gross profit that took profit in WETH -``` -SELECT * -FROM arbitrages -WHERE profit_token_address = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' -ORDER BY profit_amount DESC -LIMIT 10; -``` - -Postgres tip: Enter `\x` to enter "Expanded display" mode which looks nicer for results with many columns diff --git a/docs/flashbots-data/mev-inspect-py/inspecting.md b/docs/flashbots-data/mev-inspect-py/inspecting.md deleted file mode 100644 index f366cba1..00000000 --- a/docs/flashbots-data/mev-inspect-py/inspecting.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: inspecting ---- - -running inspect for a block will: -- pull down traces, receipts, and block data from the RPC endpoint -- decode the traces using known ABIs -- pull out structured objects like transfers and swaps -- and save them all to the database for querying - -### Inspect a single block - -Inspecting block [12914944](https://twitter.com/mevalphaleak/status/1420416437575901185): - -``` -./mev inspect 12914944 -``` - -### Inspect many blocks - -Inspecting blocks 12914944 to 12914954: - -``` -./mev inspect-many 12914944 12914954 -``` - -### Inspect all incoming blocks - -Start a block listener with: - -``` -./mev listener start -``` - -By default, it will pick up wherever you left off. -If running for the first time, listener starts at the latest block. - -Tail logs for the listener with: - -``` -./mev listener tail -``` - -And stop the listener with: - -``` -./mev listener stop -``` - -### Backfilling - -For larger backfills, you can inspect many blocks in parallel using kubernetes - -To inspect blocks 12914944 to 12915044 divided across 10 worker pods: -``` -./mev backfill 12914944 12915044 10 -``` - -You can see worker pods spin up then complete by watching the status of all pods -``` -watch kubectl get pods -``` - -To watch the logs for a given pod, take its pod name using the above, then run: -``` -kubectl logs -f pod/mev-inspect-backfill-abcdefg -``` - -(where `mev-inspect-backfill-abcdefg` is your actual pod name) diff --git a/docs/flashbots-data/mev-inspect-py/install.md b/docs/flashbots-data/mev-inspect-py/install.md deleted file mode 100644 index db34c3d1..00000000 --- a/docs/flashbots-data/mev-inspect-py/install.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: install ---- - -mev-inspect-py is built to run on kubernetes locally and in production - -### Install dependencies - -First, setup a local kubernetes deployment - we use [Docker](https://www.docker.com/products/docker-desktop) and [kind](https://kind.sigs.k8s.io/docs/user/quick-start) - -If using kind, create a new cluster with: -``` -kind create cluster -``` - -Next, install the kubernetes CLI [`kubectl`](https://kubernetes.io/docs/tasks/tools/) - -Then, install [helm](https://helm.sh/docs/intro/install/) - helm is a package manager for kubernetes - -Lastly, setup [Tilt](https://docs.tilt.dev/install.html) which manages running and updating kubernetes resources locally - -### Start up - -Set an environment variable `RPC_URL` to an RPC for fetching blocks -Example: -``` -export RPC_URL="http://111.111.111.111:8546/" -``` - -**Note: mev-inspect-py currently requires and RPC with support for OpenEthereum / Erigon traces (not geth 😔)** - -Next, start all servcies with: -``` -tilt up -``` - -Press "space" to see a browser of the services starting up - -On first startup, you'll need to apply database migrations. Apply with: -``` -./mev exec alembic upgrade head -``` - -### Tear down - -First stop the running tilt window with `Ctrl+C` - -Then run -``` -tilt down -``` diff --git a/docs/flashbots-data/mev-inspect-py/overview.md b/docs/flashbots-data/mev-inspect-py/overview.md deleted file mode 100644 index eded23e8..00000000 --- a/docs/flashbots-data/mev-inspect-py/overview.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: overview ---- - -**mev-inspect-py** is an MEV inspector for Ethereum - -Given a block, mev-inspect finds: -- miner payments (gas + coinbase) -- tokens transfers and profit -- swaps and [arbitrages](https://twitter.com/bertcmiller/status/1427632028263059462) -- ...and more - -All data is stored in Postgres for querying and analysis - -To get started, check out the [quick start](/flashbots-data/mev-inspect-py/quick-start) - -To see which data inspect produces, check out the [data](/flashbots-data/mev-inspect-py/data/classified_traces) section - -Access and contribute to the public mev-inspect-py repository [here](https://github.com/flashbots/mev-inspect-py) diff --git a/docs/flashbots-data/mev-inspect-py/quick-start.md b/docs/flashbots-data/mev-inspect-py/quick-start.md deleted file mode 100644 index 609a8bbf..00000000 --- a/docs/flashbots-data/mev-inspect-py/quick-start.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -title: quick start ---- - -Let's use mev-inspect to find the same arbitrage as [MEV Alpha Leak](https://twitter.com/mevalphaleak/status/1420416437575901185) - -### Install - -Get mev-inspect running by going through the [install section](/flashbots-data/mev-inspect-py/install) - -### Inspect a block - -Using the [linked etherscan transaction](https://etherscan.io/tx/0xfcf4558f6432689ea57737fe63124a5ec39fd6ba6aaf198df13a825dd599bffc), we can see the block number is 12914944. - -To inspect this block, run -``` -./mev inspect 12914944 -``` - -### Connect to Postgres - -We'll connect to the Postgres database to see the data inspect found in that block - -Let's start up a client container connected to the DB: -``` -./mev db -``` - -When you see the prompt -``` -mev_inspect=# -``` - -You're ready to query! - -To make the data display nice, switch into "Expanded display" mode by running -``` -\x -``` - -### Query for arbitrage data - -Let's find that arbitrage by querying the `arbitrages` table: -``` -SELECT * -FROM arbitrages -WHERE - block_number = 12914944 AND - transaction_hash = '0xfcf4558f6432689ea57737fe63124a5ec39fd6ba6aaf198df13a825dd599bffc' -``` - -You should see output like this: -``` -id | ff2deb13-c2c1-4ef5-a6ff-0ca813a07d6b -created_at | 2021-09-27 15:26:58.193263 -account_address | 0x0000fee6275dab194ab538a01dd8b18b02b20000 -profit_token_address | 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 -block_number | 12914944 -transaction_hash | 0xfcf4558f6432689ea57737fe63124a5ec39fd6ba6aaf198df13a825dd599bffc -start_amount | 70287643212620210176 -end_amount | 123848351154563483804 -profit_amount | 53560707941943273628 -``` - -We can see this matches the original tweet description! - -The `profit_token_address` is the address for WETH, our `start_amount` is 70 WETH (assuming 18 decimals), and our `end_amount` is 123 WETH - -### Query for arbitrage swaps - -We can learn about the swaps involed in this arbitrage by joining against the `arbitrage_swaps` and `swaps` tables - -**Note: you'll need to switch in the id you got in the first query for arbitrage_id** -``` -SELECT s.* -FROM swaps s -JOIN arbitrage_swaps arb_swaps ON - s.transaction_hash = arb_swaps.swap_transaction_hash AND - s.trace_address = arb_swaps.swap_trace_address -WHERE arb_swaps.arbitrage_id = 'ff2deb13-c2c1-4ef5-a6ff-0ca813a07d6b'; -``` - -You should see output like this: -``` --[ RECORD 1 ]-----+------------------------------------------------------------------- -created_at | 2021-09-27 15:26:58.180131 -abi_name | UniswapV3Pool -transaction_hash | 0xfcf4558f6432689ea57737fe63124a5ec39fd6ba6aaf198df13a825dd599bffc -block_number | 12914944 -protocol | -pool_address | 0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640 -from_address | 0x7ec0b75a98997c927ace6d87958147a105147ea0 -to_address | 0x0000fee6275dab194ab538a01dd8b18b02b20000 -token_in_address | 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 -token_in_amount | 283588902010 -token_out_address | 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 -token_out_amount | 123848351154563483804 -trace_address | {0,0} -error | --[ RECORD 2 ]-----+------------------------------------------------------------------- -... -``` - -### Query for miner payment - -Lastly, we can see how much was paid to the miner for this transaction by querying by the transaction hash: -``` -SELECT * -FROM miner_payments -WHERE transaction_hash = '0xfcf4558f6432689ea57737fe63124a5ec39fd6ba6aaf198df13a825dd599bffc'; -``` - -You should see results like this: -``` -created_at | 2021-09-27 15:26:58.245444 -block_number | 12914944 -transaction_hash | 0xfcf4558f6432689ea57737fe63124a5ec39fd6ba6aaf198df13a825dd599bffc -transaction_index | 1 -miner_address | 0x5A0b54D5dc17e0AadC383d2db43B0a0D3E029c4c -coinbase_transfer | 48204637147748941824 -base_fee_per_gas | 0 -gas_price | 0 -gas_price_with_coinbase_transfer | 200463421638605 -gas_used | 240466 -transaction_to_address | 0x00000000454a11ca3a574738c0aab442b62d5d45 -transaction_from_address | 0xd80276cd0348e9b3c5d017e1f7529f0a785fec3a -``` - -`gas_price` is the gas price paid directly as gas (it includes the EIP-1559 base fee) - -`coinbase_transfer` is the amount of ETH paid directly as a transfer to the miner's address - -`gas_price_with_coinbase_transfer` is the gas price including both original gas and coinbase transfers - -So in total, this searcher paid 48.2 ETH to make 53.5 ETH for a net profit of 5.3 ETh - -### Next steps - -To see what other data is available for querying, check out the [data](/flashbots-data/mev-inspect-py/data/classified_traces) section - -To learn about inspecting blocks in bulk or listening for new blocks as they come in, check out the [inspecting](/flashbots-data/mev-inspect-py/inspecting) section diff --git a/docs/flashbots-mev-boost/FAQ.md b/docs/flashbots-mev-boost/FAQ.md new file mode 100644 index 00000000..d5109ea3 --- /dev/null +++ b/docs/flashbots-mev-boost/FAQ.md @@ -0,0 +1,36 @@ +--- +title: FAQ +--- + +## 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. + +```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? + +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. diff --git a/docs/flashbots-mev-boost/architecture-overview/block-proposal.md b/docs/flashbots-mev-boost/architecture-overview/block-proposal.md new file mode 100644 index 00000000..ddf1f5d6 --- /dev/null +++ b/docs/flashbots-mev-boost/architecture-overview/block-proposal.md @@ -0,0 +1,12 @@ +--- +title: MEV-Boost Block Proposal +--- + +![MEV-Boost Block Proposal](https://raw.githubusercontent.com/flashbots/mev-boost/develop/docs/block-proposal.png) + +As depicted above and described in the [Builder — Honest Validator](https://github.com/ethereum/builder-specs) repository, the MEV-Boost block proposal process begins with a [registration step](https://github.com/ethereum/builder-specs) 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. diff --git a/docs/flashbots-mev-boost/architecture-overview/risks.md b/docs/flashbots-mev-boost/architecture-overview/risks.md new file mode 100644 index 00000000..bb54e00a --- /dev/null +++ b/docs/flashbots-mev-boost/architecture-overview/risks.md @@ -0,0 +1,23 @@ +--- +title: 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/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/architecture-overview/specifications.md b/docs/flashbots-mev-boost/architecture-overview/specifications.md new file mode 100644 index 00000000..064adc4d --- /dev/null +++ b/docs/flashbots-mev-boost/architecture-overview/specifications.md @@ -0,0 +1,27 @@ +--- +title: MEV-Boost Specifications +--- + + + +`mev-boost` implements the latest versions of the [Ethereum Builder Specification](https://github.com/ethereum/builder-specs). + +- 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) diff --git a/docs/flashbots-mev-boost/block-builders.md b/docs/flashbots-mev-boost/block-builders.md new file mode 100644 index 00000000..66f3288e --- /dev/null +++ b/docs/flashbots-mev-boost/block-builders.md @@ -0,0 +1,67 @@ +--- +title: Block Builders +--- + +## Builder Fundamentals + +### What is a Builder? + +Block builders are highly specialized actors who construct blocks from transaction orderflow (public transactions, 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. Builders then bid for and buy the validators’ blockspace, facilitated by one or more relays, so their execution payloads are proposed to the blockchain. + +### How do builders pay block proposers? + +Flashbots proposed 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 the `feeRecipient` of the payload block 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. + +### Determining the value of blocks + +A standard method for determining block value is crucial for multiple components of the MEV-Boost ecosystem; including relay monitoring, validator accounting, builder payments, block explorers, payment proofs, and MEV hiding. + +Various methods for defining block value were [considered](https://collective.flashbots.net/t/block-scoring-for-mev-boost-relays/202) by members of the community. It was determined that block level scoring was the most simple and intuitive method for scoring block value. + +### Block level scoring + +Block level scoring looks at the difference in the balance of the fee recipient account before and after the block execution. + +Note that a “block score” is not meant to be a formal definition of realized extractable value, since this is a difficult metric to quantify. For example, a Layer 2 transfer to a validator’ fee recipient address could be considered extractable value, but falls outside the scope of a block score calculation. + +Constructing a payment proof for this scoring method requires a Merkle Proof of the fee recipient balance in block _(n - 1)_, and a Merkle Proof of the fee recipient balance in block _n_. **Payment proofs have not yet been put into production.** Active discussion about payment proof implementation is still on-going. For more details or to participate in the discussion around payment proofs and block-level scoring, please check out to the [block scoring](https://collective.flashbots.net/t/block-scoring-for-mev-boost-relays/202) forum thread. + +## External Builders + +External builders can submit blocks to Mainnet and Sepolia Flashbots relays. The table below outlines Builder API methods available on each network. + +### Relay Block Submission Endpoints by Network + +| | | Mainnet | Sepolia | +| --- | --- | --- | --- | +| `getValidators` | GET Request - Returns an array of validator registrations with assigned duties in the current and next epoch | [Mainnet](https://boost-relay.flashbots.net/relay/v1/builder/validators)  | [Sepolia](https://boost-relay-sepolia.flashbots.net/relay/v1/builder/validators) | +| `submitBlock` | POST Request - submits a block to the relay | [Mainnet](https://boost-relay.flashbots.net/relay/v1/builder/blocks) | [Sepolia](https://boost-relay-sepolia.flashbots.net/relay/v1/builder/blocks)  | + +- See also the [Relay API documentation - Block Builder API](https://bit.ly/3BmGZ3T) for more details on the API and payloads. +- The example [Flashbots builder implementation](https://github.com/flashbots/boost-geth-builder) is a good external builder reference, and is currently used in production by several builders. + +### Rate-limits + +Submissions to all relays are currently rate-limited to 600 submissions / 5m / IP, which translates to in average 2 submissions / sec /IP. + +## BuilderNet Block Builders + +The keys used in BuilderNet are listed here: https://buildernet.org/docs/public-identity#bls-keys-for-submitting-blocks-to-mev-boost-relays + +## Additional Links & References + +- [rbuilder](https://github.com/flashbots/rbuilder) - Blazingly fast, cutting edge block builder written in Rust. +- [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). +- [Mevboost.pics](https://www.mevboost.pics/) - Tracking MEV-Boost relays and block builders, by [Toni Wahrstätter](https://twitter.com/nero_eth). +- [Relayscan.io](https://www.relayscan.io/) - Up-to-date stats on the MEV-Boost ecosystem, by [Chris Hager](https://twitter.com/metachris). + +_Note: Flashbots does not control and cannot verify the data coming from external people and organizations. Please direct questions or issues directly to the creators of external data sources._ diff --git a/docs/flashbots-mev-boost/block-proposers.md b/docs/flashbots-mev-boost/block-proposers.md new file mode 100644 index 00000000..7131b878 --- /dev/null +++ b/docs/flashbots-mev-boost/block-proposers.md @@ -0,0 +1,24 @@ +--- +title: Block Proposers +--- + +## 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. diff --git a/docs/flashbots-mev-boost/contributing.md b/docs/flashbots-mev-boost/contributing.md new file mode 100644 index 00000000..f10407a8 --- /dev/null +++ b/docs/flashbots-mev-boost/contributing.md @@ -0,0 +1,22 @@ +--- +title: Contributing +--- + +[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/develop/CONTRIBUTING.md) for further information. +- Please be kind and read our [code of conduct](https://github.com/flashbots/mev-boost/blob/develop/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. 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..3313ca12 --- /dev/null +++ b/docs/flashbots-mev-boost/getting-started/installation.md @@ -0,0 +1,143 @@ +--- +title: Installation +--- + +Get started with MEV-Boost installation with this guide. Whether you are looking to install it on a machine with the beacon client or multiple beacon clients, this guide will assist you in setting it up smoothly. + +## Prerequisites + +- For a comprehensive guide on preparing for the merge, refer to [Rémy Roy's guide](https://github.com/remyroy/ethstaker/blob/main/prepare-for-the-merge.md#installing-mev-boost). +- Ensure you have [Go 1.18+](https://go.dev/doc/install) installed for source-based installations. + +## Installation Methods + +### Using Binaries + +For convenience, each release includes binaries suitable for Linux, Windows, and macOS (both amd and arm). Find the latest releases [here](https://github.com/flashbots/mev-boost/releases). + +### From Source + +#### Build and install with `go install` + +The easiest way to build and install MEV-Boost from sources is to use `go install`. You can simply execute the `go install` command as shown below: + +```bash +go install github.com/flashbots/mev-boost@latest +mev-boost -help +``` + +This would install the latest version of MEV-Boost in your `$GOPATH/bin` directory. You can then run the `mev-boost` command from anywhere in your terminal. + +If you want to install a specific version, you can use the `@` syntax: + +```bash +go install github.com/flashbots/mev-boost@VERSION +``` + +Simply look up the specific version you want to install in the [releases](https://github.com/flashbots/mev-boost/releases) page. + +#### Clone and Build + +You can also clone the repository and build the software yourself without using `go install`. + +1. Clone the repository: + + ```bash + git clone https://github.com/flashbots/mev-boost.git + cd mev-boost + ``` + +2. (Optional) To build a specific release, refer to the available [releases](https://github.com/flashbots/mev-boost/releases) and checkout the desired tag: + + ```bash + git checkout tags/YOUR_VERSION + ``` + +3. Build the software: + + ```bash + make build + ``` + +4. If you experience issues, use the portable build: + + ```bash + make build-portable + ``` + +5. Verify your installation: + + ```bash + ./mev-boost -help + ``` + +### From Docker Image + +Flashbots provides maintained Docker images for MEV-Boost. + +1. [Install Docker Engine](https://docs.docker.com/engine/install/). + +2. Pull the latest MEV-Boost image: + + ```bash + docker pull flashbots/mev-boost:latest + ``` + + Or pull the portable version: + + ```bash + docker pull flashbots/mev-boost:latest-portable + ``` + +3. Run the Docker image: + + ```bash + docker run flashbots/mev-boost -help + ``` + +## Systemd Configuration + +To keep MEV-Boost running as a service, configure systemd by creating the systemd config file `/etc/systemd/system/mev-boost.service`. + +Below is an example of a config file: + + ```ini + [Unit] + Description=mev-boost + Wants=network-online.target + After=network-online.target + + [Service] + User=mev-boost + Group=mev-boost + WorkingDirectory=/home/mev-boost + Type=simple + Restart=always + RestartSec=5 + ExecStart=/home/mev-boost/bin/mev-boost \ + -mainnet \ + -relay-check \ + -relays YOUR_RELAY_CHOICE + + [Install] + WantedBy=multi-user.target + ``` + +## Troubleshooting + +If you encounter an error: [`"SIGILL: illegal instruction"`](https://github.com/flashbots/mev-boost/issues/256), you'll need to use the portable build. + +There are three ways to install the portable build: + +1. Use the [portable Docker image](https://hub.docker.com/r/flashbots/mev-boost/tags). +2. Build the portable version from source: + + ```bash + make build-portable + ``` + +3. Using `go install`: + + ```bash + CGO_CFLAGS="-O -D__BLST_PORTABLE__" go install github.com/flashbots/mev-boost@latest + ``` 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..5b8688bf --- /dev/null +++ b/docs/flashbots-mev-boost/getting-started/system-requirements.md @@ -0,0 +1,42 @@ +--- +title: 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: [Coincashew](https://www.coincashew.com/coins/overview-eth/archived-guides/guide-or-how-to-setup-a-validator-on-eth2-mainnet/part-i-installation/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) + +## Requirements for different systems + +### 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 + +:::tip +There are variations in client resource usage. Please review [CoinCashew’s Client Usage Guide](https://eth-docker.net/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. + +## Consensus client configuration guides + +| | MEV-Boost Client Guides | +| ---------- | ------------------------------------------------------------------------------------------------------------- | +| Teku | [Guide](hthttps://docs.teku.consensys.net/Concepts/Builder-Network/tps://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/pages/beacon-management/mev-and-builder-integration.md) | +| Nimbus | [Guide](https://nimbus.guide/external-block-builder.html) | 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..c57e76d5 --- /dev/null +++ b/docs/flashbots-mev-boost/getting-started/usage.md @@ -0,0 +1,90 @@ +--- +title: Usage +--- + +When connecting to different networks using mev-boost, specify the desired network using its dedicated flag. Here are the available Network Flags: + +| Network | Flag | +| --------------- | -------- | +| Mainnet | -mainnet | +| Sepolia Testnet | -sepolia | +| Kiln | -kiln | + +You can add multiple relays comma-separated to the `-relays` flag, like this: `-relays RELAY_URL_1,RELAY_URL_2`. Refer to ETH staker [Relay List](https://github.com/eth-educators/ethstaker-guides/blob/main/MEV-relay-list.md) for a list of available relays. + +### Mainnet Relay + +Run mev-boost pointed at our [Mainnet Relay:](https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net/) + +```bash +./mev-boost -mainnet -relay-check -relays https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net +``` + +### Sepolia testnet + +Run mev-boost pointed at our [Sepolia Relay](https://builder-relay-sepolia.flashbots.net/): + +```bash +./mev-boost -sepolia -relay-check -relays https://0x845bd072b7cd566f02faeb0a4033ce9399e42839ced64e8b2adcfc859ed1e8e1a5a293336a49feac6d9a5edb779be53a@builder-relay-sepolia.flashbots.net +``` + +## mev-boost CLI arguments + +```bash +$ ./mev-boost -help +Usage of ./mev-boost: + -addr string + listen-address for mev-boost server (default "localhost:18550") + -debug + shorthand for '-loglevel debug' + -genesis-fork-version string + use a custom genesis fork version + -json + log in JSON format instead of text + -loglevel string + minimum loglevel: trace, debug, info, warn/warning, error, fatal, panic (default "info") + -mainnet + use Mainnet + -relay-check + check relay status on startup and on the status API call + -relay-monitors string + relay monitor urls - single entry or comma-separated list (scheme://host) + -relays string + relay urls - single entry or comma-separated list (scheme://pubkey@host) + -request-timeout-getheader int + timeout for getHeader requests to the relay [ms] (default 950) + -request-timeout-getpayload int + timeout for getPayload requests to the relay [ms] (default 4000) + -request-timeout-regval int + timeout for registerValidator requests [ms] (default 3000) + -sepolia + use Sepolia + -version + only print version +``` + +## Verifying Your Setup + +You can check if you setup works by looking up the validator registration of your proposer using the [Relay Data API](https://flashbots.github.io/relay-specs/#/Data). + +For example, let's suppose that your validator's public key is `0xb606e206c2bf3b78f53ebff8be8e8d4af2f0da68646b5642c4d511b15ab5ddb122ae57b48eab614f8ca5bafbe75a5999`. You can check if your validator is registered by querying the following endpoint: + +```url +https://boost-relay.flashbots.net/relay/v1/data/validator_registration?pubkey=0xb606e206c2bf3b78f53ebff8be8e8d4af2f0da68646b5642c4d511b15ab5ddb122ae57b48eab614f8ca5bafbe75a5999 +``` + +Below is the response: + +```json +{ + "message": { + "fee_recipient": "0x6db5c947ba388f0e708c03339d534af9fae5679c", + "gas_limit": "30000000", + "timestamp": "1663063595", + "pubkey": "0xb606e206c2bf3b78f53ebff8be8e8d4af2f0da68646b5642c4d511b15ab5ddb122ae57b48eab614f8ca5bafbe75a5999" + }, + "signature": "0x94f1f635336f8c38909842f06550026bbc198f892c6a79c22a3365e547e87665e31feccfacda3533ef3cf8e2c965e03d1594cf8e981dfc75011b4d237552386377bcea714bcfb78d303fe5624625e1bbb8b23f3a6d1b7c9efb3d76cad4ca01a5" +} +``` + +The `fee_recipient` field should match the address you provided when registering your validator. If it does, then your setup is working correctly. diff --git a/docs/flashbots-mev-boost/glossary.md b/docs/flashbots-mev-boost/glossary.md new file mode 100644 index 00000000..0a5e0c46 --- /dev/null +++ b/docs/flashbots-mev-boost/glossary.md @@ -0,0 +1,26 @@ +--- +title: Glossary +--- + +- **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. +- **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. +- **block builder (builder)**: party specialized in MEV extraction and the construction of execution payloads. Builders are trusted by searchers and users for fair transaction inclusion. +- **block proposer (proposer)**: a validator selected to sign and submit a beacon block to the network. +- **builder API specification**: an [interface](https://github.com/ethereum/builder-specs) for consensus layer clients to source blocks built by external entities. +- **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. +- **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). +- **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. +- **liveness:** state of ethereum which is valid \*\*\*\*if the set of finalized blocks can grow. +- **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. +- **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. +- **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. +- **searcher**: advanced Ethereum user specialized in detecting and extracting MEV by submitting advanced transactions in batches called bundles. +- **staker:** actor that submit any amount of Ethereum to be staked. +- **user**: a normal Ethereum user who sends transactions for block inclusion. +- **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 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 which replaced proof-of-work miners at [The Merge](https://ethereum.org/en/upgrades/merge/). +- **validator pubkey**: The validator's BLS public key, uniquely identifying them. *48-bytes, hex encoded with 0x prefix, case insensitive.* diff --git a/docs/flashbots-mev-boost/introduction.md b/docs/flashbots-mev-boost/introduction.md new file mode 100644 index 00000000..07904c05 --- /dev/null +++ b/docs/flashbots-mev-boost/introduction.md @@ -0,0 +1,33 @@ +--- +title: Overview +--- + +## 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. + +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). + +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? + +![MEV Boost Integration Overview](/img/mev-boost-integration-overview.jpg) + +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/relay.md b/docs/flashbots-mev-boost/relay.md new file mode 100644 index 00000000..8fc06dad --- /dev/null +++ b/docs/flashbots-mev-boost/relay.md @@ -0,0 +1,58 @@ +--- +title: Relay Fundamentals +--- + +## 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: + +![Relay Architecture](/img/relay_architecture.jpg) + +### [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, payloads delivered to proposers as well as insights into validator registrations. + +## [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 (such as the chain) to determine whether clients should stop sourcing blocks from an external block builder network and fallback to local block production instead. Each consensus client implements different circuit breaker conditions and once the circuit breaker condition is met, clients have different behaviour regarding when to resume sourcing external blocks. + +For the exact behavior and available configuration around circuit breaker conditions for a specific client, please refer to the documentation for the specific consensus client. + +## [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. This is an ongoing proposal and 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/understanding-mev-boost-liveness-risks). \ No newline at end of file diff --git a/docs/flashbots-mev-boost/resources.md b/docs/flashbots-mev-boost/resources.md new file mode 100644 index 00000000..3f271a1e --- /dev/null +++ b/docs/flashbots-mev-boost/resources.md @@ -0,0 +1,33 @@ +--- +title: Resources +--- + +**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.eth.limo/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/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/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/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/Flashbots-Relay-open-sourcing) +- [Understanding liveness risks from mev-boost](https://writings.flashbots.net/understanding-mev-boost-liveness-risks) + +**Validator Guides** + +- [Validator Checklist - launchpad.ethereum.org](https://launchpad.ethereum.org/en/merge-readiness) +- [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/) diff --git a/docs/flashbots-mev-boost/security.md b/docs/flashbots-mev-boost/security.md new file mode 100644 index 00000000..217175a8 --- /dev/null +++ b/docs/flashbots-mev-boost/security.md @@ -0,0 +1,12 @@ +--- +title: 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/develop/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..e01ea4d3 --- /dev/null +++ b/docs/flashbots-mev-boost/troubleshooting.md @@ -0,0 +1,5 @@ +--- +title: Troubleshooting +--- + +Please refer to the [Troubleshooting Wiki](https://github.com/flashbots/mev-boost/wiki/Troubleshooting) for the most updated guidance. diff --git a/docs/flashbots-mev-share/for-users.mdx b/docs/flashbots-mev-share/for-users.mdx new file mode 100644 index 00000000..16e46888 --- /dev/null +++ b/docs/flashbots-mev-share/for-users.mdx @@ -0,0 +1,11 @@ +--- +title: For Users +--- + +import WhatIsMevShare from "@site/docs/specs/mev-share/blurbs/_whatsMevShareBasic.mdx" + + + +MEV-Share Nodes generally accept transactons using the `eth_sendRawTransaction` or `eth_sendPrivateTransaction` json rpc requests. Flashbots runs a MEV-Share Node that can be used by sending transactions to [Flashbots Protect](/flashbots-protect/quick-start). + + diff --git a/docs/flashbots-mev-share/introduction.mdx b/docs/flashbots-mev-share/introduction.mdx new file mode 100644 index 00000000..4b83384f --- /dev/null +++ b/docs/flashbots-mev-share/introduction.mdx @@ -0,0 +1,27 @@ +--- +title: Introduction +--- + +import WhatsMevShareAdvanced from "../specs/mev-share/blurbs/_whatsMevShareAdvanced.mdx" + +> The MEV-Share Matchmaker was renamed to the MEV-Share Node to better reflect the role we envision this actor will play in SUAVE. This change will be reflected in our documentation after June 2023. The client library previously named `matchmaker-ts` has also been renamed to `mev-share-client-ts`. + +## What is MEV-Share? + + +To start earning MEV refunds from MEV-Share, submit your transactions to the Flashbots **MEV-Share Node**, either by [connecting your wallet to the Protect RPC](/flashbots-protect/quick-start/#using-flashbots-protect), or sending a [private transaction](/flashbots-auction/advanced/rpc-endpoint#eth_sendprivatetransaction) to the MEV-Share Node API. + +## Why MEV-Share? +MEV-Share redistributes MEV back to the party that creates it in the first place: users. It does so through a design that is built to scale and be decentralized, which means that it is permissionless for searchers to integrate and it does not enshrine a single block builder. + +## How does MEV-Share work? +Users send their transactions to a specialized actor called a MEV-Share Node. The MEV-Share Node selectively shares information about the user's transaction according to their privacy preferences. Seeing this information, searchers submit partial bundles to the MEV-Share Node to attempt to extract MEV from user's transactions without seeing the full transaction data. MEV-Share Nodes simulate each of these searcher bundles and forward the successful ones on to builders along with a condition that the user must be paid back specified percentage (by default 90%) of the MEV their transactions create. + +At the moment, MEV-Share Nodes only accept backruns. + +## How do I use MEV-Share? +The simplest way to use MEV-Share is by sending transactions to [Flashbots Protect](/flashbots-protect/quick-start), which leverages the [Flashbots MEV-Share Node](/flashbots-protect/mev-refunds). Wallet and application developers should check out the [Flashbots Protect MEV-Share section](/flashbots-protect/mev-refunds) for information about integrating and configuring the Flashbots MEV-Share Node. + + +## How do I search on MEV-Share? +Searchers should see the [Getting Started](/flashbots-mev-share/searchers/getting-started) guide for a walkthrough of MEV-Share and how it differs from traditional searching. diff --git a/docs/flashbots-mev-share/orderflow-providers.mdx b/docs/flashbots-mev-share/orderflow-providers.mdx new file mode 100644 index 00000000..391a02b8 --- /dev/null +++ b/docs/flashbots-mev-share/orderflow-providers.mdx @@ -0,0 +1,5 @@ +--- +title: For Orderflow Providers +--- + +Flashbots runs a MEV-Share Node that can be used by sending transactions to [Flashbots Protect](/flashbots-protect/quick-start). Wallets and application developers should see the [Protect MEV-Share Node guide](/flashbots-protect/mev-refunds) to configure your integration. \ No newline at end of file diff --git a/docs/flashbots-mev-share/release-notes/2023-03.mdx b/docs/flashbots-mev-share/release-notes/2023-03.mdx new file mode 100644 index 00000000..056d35a9 --- /dev/null +++ b/docs/flashbots-mev-share/release-notes/2023-03.mdx @@ -0,0 +1,19 @@ +# April 2023 (beta launch) + +## MEV-Share Protocol Specification + +https://github.com/flashbots/mev-share + +## `mev_` RPC endpoints + +New endpoints added to Flashbots bundle relay (relay.flashbots.net): + +- `mev_sendBundle` - send bundles with a [new format](https://github.com/flashbots/mev-share/blob/main/specs/bundles/v0.1.md), enabling modular privacy settings and sets the stage for future innovations. +- `mev_simBundle` - simulate bundles in the context of MEV-Share using the new format. + +## SSE Event Stream + +Events containing one or more transactions with varying data shared via hints, broadcast via SSE stream. + +- https://mev-share.flashbots.net +- https://mev-share-goerli.flashbots.net diff --git a/docs/flashbots-mev-share/release-notes/2023-06.mdx b/docs/flashbots-mev-share/release-notes/2023-06.mdx new file mode 100644 index 00000000..b43d3421 --- /dev/null +++ b/docs/flashbots-mev-share/release-notes/2023-06.mdx @@ -0,0 +1,47 @@ +# June 2023 + +## simBundle options + +New options to override the simulation state for `mev_simBundle`: + +```typescript +interface SimBundleOptions { + /** Block used for simulation state. Defaults to latest block on chain. + * + * Block header data will be derived from parent block by default. + * Specify other params in this interface to override the default values. + * + * Can be a block number or block hash. + */ + parentBlock?: number | string, + + // override the default values for the parentBlock header + /** default = parentBlock.number + 1 */ + blockNumber?: number, + /** default = parentBlock.coinbase */ + coinbase?: string, + /** default = parentBlock.timestamp + 12 */ + timestamp?: number, + /** default = parentBlock.gasLimit */ + gasLimit?: number, + /** default = parentBlock.baseFeePerGas */ + baseFee?: bigint, + /** default = 5 (defined in seconds) */ + timeout?: number, +} +``` + +## event history api + +Query past events with `/history`, get info about query params to use from `/history/info`. + +- https://mev-share.flashbots.net/api/v1/history/info +- https://mev-share.flashbots.net/api/v1/history + +## tx_hash bundle hint + +Enables searchers to share the transaction hashes of their bundle's transactions with other searchers, allows other searchers to backrun them without compromising bundle privacy or atomicity. + +## public mev-share-node release + +Open-sourced the backend node for MEV-Share: https://github.com/flashbots/mev-share-node diff --git a/docs/flashbots-mev-share/release-notes/2023-07.mdx b/docs/flashbots-mev-share/release-notes/2023-07.mdx new file mode 100644 index 00000000..9ca987c0 --- /dev/null +++ b/docs/flashbots-mev-share/release-notes/2023-07.mdx @@ -0,0 +1,28 @@ +# July 2023 + +## customized refunds + +Configure the percent(s) and recipient(s) for MEV-Share refunds by adding the [`refund`](/flashbots-protect/settings-guide#refunds) query parameter to Protect RPC requests +or by adding `preferences.validity.refund` argument to the `eth_sendPrivateTransaction` JSON-RPC [method](/flashbots-auction/advanced/rpc-endpoint#eth_sendprivatetransaction). + +## builder sharing +Share transactions and bundles with additional builders for faster inclusion. + +- Users: [Opt in to share with registered builders](/flashbots-protect/settings-guide#builders) +- Builders: [Register to receive bundles](https://github.com/flashbots/dowg#builders) + +## debugging guide + +Follow this [guide](/flashbots-mev-share/searchers/debugging) for debugging bundles as a searcher on MEV-Share. + +## simple-limit-order-bot + +New tutorial for searching on MEV-Share, using a simple limit order bot as an example. + +- [Step by step tutorial with full code examples](/flashbots-mev-share/searchers/tutorials/limit-order/introduction) +- [Open source bot repository](https://github.com/flashbots/simple-limit-order-bot) + +### eth_sendPrivateRawTransaction + +- [eth_sendPrivateRawTransaction](/flashbots-auction/advanced/rpc-endpoint#eth_sendprivaterawtransaction) +is now supported on relay endpoint. Its behavior is identical to `eth_sendPrivateTransaction` but its format is similar to `eth_sendRawTransaction`. diff --git a/docs/flashbots-mev-share/release-notes/2023-09.mdx b/docs/flashbots-mev-share/release-notes/2023-09.mdx new file mode 100644 index 00000000..ee9e6b18 --- /dev/null +++ b/docs/flashbots-mev-share/release-notes/2023-09.mdx @@ -0,0 +1,18 @@ +# September 2023 + +## default logs hint + +A new hint which shares a subset of logs, as described in the [hints] settings(/flashbots-protect/settings-guide#hints). + +Previously these logs were shared by default. Now, users of the private transaction API, Protect RPC, and bundle relay can also request to share these logs when customizing their settings. + +## simple-limit-order-bot + +New tutorial for searching on MEV-Share, using a flashloan arbitrage bot as an example. + +- [Step by step tutorial with full code examples](/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/introduction) +- [Open source bot repository](https://github.com/flashbots/simple-blind-arbitrage) + +## SSE stability updates + +Made several improvements to the SSE stream endpoint to reduce client timeouts and hanging connections. The SSE stream now scales better under dynamic workloads and can handle a greater number of client connections. diff --git a/docs/flashbots-mev-share/searchers/debugging.mdx b/docs/flashbots-mev-share/searchers/debugging.mdx new file mode 100644 index 00000000..5d4a080f --- /dev/null +++ b/docs/flashbots-mev-share/searchers/debugging.mdx @@ -0,0 +1,234 @@ +--- +title: Debugging +--- + +If you find that your bundles aren't landing when you think they should, we have some tips to help you figure out why. + +> Note: Some examples you see in the code here are based on the [limit order bot tutorial](/flashbots-mev-share/searchers/tutorials/limit-order/introduction). The same tactics can be used to debug any MEV-Share bundle. + +## Simulate your bundle + +The simplest way to find out what happened with your bundle is to simulate it. MEV-Share nodes offer the `mev_simBundle` [json rpc](/flashbots-auction/advanced/rpc-endpoint#mev_simbundle). Typically, MEV-Share Nodes will not return simulation results unless the private transaction being backrun has already landed on-chain. + +## Using a client + +The [mev-share-client](https://www.npmjs.com/package/@flashbots/mev-share-client) library has a function `simulateBundle` which executes your bundle in a virtual environment based on the block which the bundle was targeting. + +In our project, we can simply call the `simulateBundle` function with our original bundle. The block we choose is the block before the first transaction (the one we tried to backrun) lands on-chain, because we want the state as close as possible to when the transaction actually landed; this is the most accurate representation of the state of the blockchain (i.e. prices) when our bundle was supposed to have landed. + +```tsx +// after you call sendBundle(bundleParams) +let simResult: SimBundleLogs = await mevshare.simulateBundle(bundleParams) +console.log("simResult", simResult) +``` + +Here's a breakdown of the simulation result: + +```tsx +type SimBundleLogs = { + /* True if the simulation executes without error. */ + success: boolean, + /* The error message, if there is an error; otherwise undefined. */ + error?: string, + /* The block that the simulation derived its state from. */ + stateBlock: number, + /* (profit) / (gasUsed) */ + mevGasPrice: bigint, + /* Coinbase profit; the amount paid to the builder after user receives kickback. */ + profit: bigint, + /* Total ETH paid by searcher to coinbase (gas fees + coinbase transfers). */ + refundableValue: bigint, + /* Total gas used by transactions in the bundle. */ + gasUsed: bigint, + logs?: Array<{ + /* ETH transaction logs. */ + txLogs?: Array, + /* Logs for nested bundles. */ + bundleLogs?: Array, + }>, +} +``` + +`LogParams` are defined in the [Ethers documentation](https://docs.ethers.org/v6/api/providers/formatting/#LogParams). + +:::info Simulating private Transactions + +The backend endpoint for simulating bundles (`mev_simBundle`) only accepts signed transactions, not private transactions (specified by `{hash}`). The mev-share-client library automatically waits for the transactions in a bundle specified by `{hash}` to land on-chain by querying for the full signed transactions with `provider.getTransaction` before it calls `mev_simBundle`. If the private transaction(s) in your bundle don't land on-chain, you won't be able to simulate your bundle with them. + +::: + +There are several things you want to look for when debugging your bundles: + +### 'invalid inclusion' + +When simulating your bundles, you might see a result like this: + +```tsx +{ + success: false, + error: 'invalid inclusion', + stateBlock: 17674041, + mevGasPrice: 0n, + profit: 0n, + refundableValue: 0n, + gasUsed: 0n, + logs: undefined +} +``` + +This happens when `bundleParams.inclusion.block` (and `bundleParams.inclusion.maxBlock` if you set it) target a block (range) that doesn't overlap with the simulation state block. + +To remedy this, you can adjust your `bundleParams` when you call `simulateBundle` to target more blocks — Protect transactions target 25 blocks starting from when they were submitted, so you may want to set your bundleParams like this: + +```tsx +const bundleParams = { + inclusion: { block: currentBlockNumber + 1 }, + body: [ + { hash: pendingTxHash }, + { tx: backrunSignedTx, canRevert: false } + ] +} +// ... +sendBundle(bundleParams) +// ... +simulateBundle({ + ...bundleParams, + inclusion: { + ...bundleParams.inclusion, + maxBlock: bundleParams.inclusion.block + 24, + } +}) +``` + +We would just set the `maxBlock` parameter to `inclusion.block + 25`, but we have to subtract 1 since `inclusion.block` was `currentBlockNumber + 1` when we initially defined it. + +You can also simply modify your original `bundleParams` to target more blocks, but note that this opens up the possibility of bundles using an outdated price landing on-chain. + +### 'tx failed' + +```tsx +{ + success: false, + error: 'tx failed', + stateBlock: 17674503, + mevGasPrice: 0n, + profit: 472614000000000n, + refundableValue: 472614000000000n, + gasUsed: 157538n, + logs: undefined +} +``` + +This happens when one of your transactions reverts. Since our `simulateBundle` function waits for private transactions to land on chain before simulating the bundle, we know that in our example, this error means that our backrun transaction failed. + +If you see this error when running the bot, it most likely means that the transaction you tried to backrun didn't affect the price enough to meet our target. This is expected — it's a feature, not a bug! + +However, if you want to be sure, a good way to further verify what's happening is to simulate transactions in a local development environment. Toolkits such as [foundry](https://github.com/foundry-rs/foundry) or [hardhat](https://hardhat.org/docs) give you tools to compile contracts, create local nodes that fork their state from public nodes, and simulate transactions locally, with stack traces to show you where things went wrong. + +## Did it pay enough gas? + +One of the most common reasons a bundle doesn't land is that it didn't pay enough gas. Of course, you need to pay at least the base fee (the current minimum gas price on Ethereum), but you may also be facing competition. If there are other searchers trying to include the same transaction as you in a bundle, then only one of these bundles can land, because the transaction specified in multiple bundles can only be included on-chain once. The one that lands is determined by who pays the most. + +Increasing the priority fee (`maxPriorityFeePerGas`) on your backrun transaction is a reliable way to improve your chances of inclusion. Note that we also increase `maxFeePerGas` by the same amount — this ensures that the builder/validator gets the tip, and it isn't consumed by the base fee. See this [blog post from Blocknative](https://www.blocknative.com/blog/eip-1559-fees) for a detailed explanation of gas fees on Ethereum. + +Here's one example of how we can set higher gas fees in our code: + +```tsx +async function getSignedBackrunTx( outputAmount: bigint, nonce: number, gasTip: bigint ) { + const backrunTx = await uniswapRouterContract.swapExactTokensForTokens.populateTransaction(SELL_TOKEN_AMOUNT, outputAmount, [SELL_TOKEN_ADDRESS, BUY_TOKEN_ADDRESS], executorWallet.address, 9999999999n) + const backrunTxFull = { + ...backrunTx, + chainId: 1, + maxFeePerGas: MAX_GAS_PRICE * GWEI + gasTip, + maxPriorityFeePerGas: MAX_PRIORITY_FEE * GWEI + gasTip, + gasLimit: TX_GAS_LIMIT, + nonce: nonce + } + return executorWallet.signTransaction(backrunTxFull) +} +``` + +Then we'd call it like this: + +```tsx +// tip: +5 gwei per gas +const tip = 5n * GWEI; +const backrunTx = await getSignedBackrunTx(outputAmount, nonce, tip) +``` + +You'll notice that we set our gas prices (`maxFeePerGas` and `maxPriorityFeePerGas`) to constant values. If you don't mind waiting for the gas price on Ethereum to go down, then you can safely ignore these errors. However, if you want to ensure that your trade goes through regardless of the gas price, then you'll have to track the base fee on Ethereum and adjust your transactions' gas prices accordingly. + +Here's how we can do that in our project: + +```tsx +async function getSignedBackrunTx( outputAmount: bigint, nonce: number, tip: bigint ) { + const gasFees = await provider.getFeeData() + const backrunTx = await uniswapRouterContract.swapExactTokensForTokens.populateTransaction(SELL_TOKEN_AMOUNT, outputAmount, [SELL_TOKEN_ADDRESS, BUY_TOKEN_ADDRESS], executorWallet.address, 9999999999n) + const backrunTxFull = { + ...backrunTx, + chainId: 1, + maxFeePerGas: gasFees.maxFeePerGas! + tip, + maxPriorityFeePerGas: gasFees.maxPriorityFeePerGas! + tip, + gasLimit: TX_GAS_LIMIT, + nonce: nonce + } + return executorWallet.signTransaction(backrunTxFull) +} +``` + +We start off by fetching the gas fees using `provider.getFeeData` — this queries the RPC provider. You may want to do this in a background thread (once per block) to avoid making redundant calls. But it's OK for demonstration's sake. +In `backrunTxFull`, we set our gas parameters with `gasFees`. We use the `!` suffix operator to coerce the value, which is possibly null, into a bigint. This is safe to do when you're sure that your network has EIP-1559 integrated, which Ethereum mainnet does. The values will only be null on old, deprecated networks. + +## Did any transactions fail? If so, which one(s)? + +It's possible that one of the transactions in your bundle encountered an error and was not able to execute. If this is the case, you'll see `false` in the `success` parameter of the simulation response, along with an error message, and some data about gas usage and payment. + +For example, a simulation result for a bundle including a transaction with its gas price set too low might look like this: + +```tsx +{ + success: false, + error: 'max fee per gas less than block base fee: address 0x2326Bd2F29a6004D31344a1FE2329F2C13284f0d, maxFeePerGas: 2000000000 baseFee: 13077974866', + stateBlock: 17674455, + mevGasPrice: 0n, + profit: 288942000000000n, + refundableValue: 288942000000000n, + gasUsed: 192628n, + logs: undefined +} +``` + +If `mevGasPrice` is 0, it just means that the transaction didn't use any gas (in this case, because it reverted). + +When a simulation succeeds, it looks something like this: + +```tsx +{ + success: true, + error: undefined, + stateBlock: 17674443, + mevGasPrice: 9485937386n, + profit: 2731874079688143n, + refundableValue: 2731874079688143n, + gasUsed: 287992n, + logs: [ { txLogs: [Array] }, { txLogs: [Array] } ] +} +``` + +This means that your bundle *could have* landed in a block, but it isn't a guarantee. If your `mevGasPrice` is not high enough, your bundle may not be included in a block. Refer back to [Did it pay enough gas?](#did-it-pay-enough-gas) for info on setting your gas price. + +There is also one more factor that often comes into play… + +## Did the Flashbots builder have a chance to include my bundle? + +Another common reason a bundle doesn't land is simply because the builders on MEV-Share didn't have an opportunity to build a block for the desired slot. For more details about how builders work, and why this happens, see [Searching Post-Merge](https://writings.flashbots.net/searching-post-merge). You can check to see if your target block was built by any of the builders connected to MEV-Share by checking the block's `miner` parameter. The Flashbots builder address is `0xDAFEA492D9c6733ae3d56b7Ed1ADB60692c98Bc5` + +```tsx +async function isBlockBuiltByFlashbots(blockNum: number) { + const flashbotsCoinbase = "0xDAFEA492D9c6733ae3d56b7Ed1ADB60692c98Bc5" + const block = await provider.getBlock(blockNum) + return block?.miner === flashbotsCoinbase +} +``` + +With this function, look at each block from `bundleParams.inclusion.block` through `bundleParams.inclusion.maxBlock` (if you set it) for a bundle to determine whether it was possible for the bundle to land in that block. diff --git a/docs/flashbots-mev-share/searchers/event-stream.mdx b/docs/flashbots-mev-share/searchers/event-stream.mdx new file mode 100644 index 00000000..431e4da4 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/event-stream.mdx @@ -0,0 +1,293 @@ +--- +title: Event Stream +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' +import StreamEvent from '@site/docs/specs/mev-share/_streamEvent.mdx' +import RemoteCodeBlock from "@site/src/components/RemoteCodeBlock" + +Events on MEV-Share are distributed via an Server-Sent Events (SSE) streaming endpoint. Searchers listen to this endpoint to receive a stream of new events, which contain data they can use in their bundles. Currently, the events refer to Ethereum transactions. + +## Quickstart + +Subscribe to the stream by making an HTTP GET request on the stream endpoint. The [mev-share-client-ts](https://npmjs.com/@flashbots/mev-share-client) library implements this as an asynchronous event handler. + + + + +```typescript +import MevShareClient, { IPendingTransaction, IPendingBundle } from '@flashbots/mev-share-client' + +const mevShareClient = MevShareClient.useEthereumMainnet(authSigner) + +const txHandler = mevShareClient.on("transaction", async (tx: IPendingTransaction) => { + /* + Do something with the pending tx here. + */ +}) + +const bundleHandler = mevShareClient.on("bundle", async (tx: IPendingBundle) => { + /* + Do something with the pending bundle here. + */ +}) + +// call before your program terminates: +txHandler.close() +bundleHandler.close() +``` + + + + + + + + +```bash +curl https://mev-share-goerli.flashbots.net +``` + +This will block until terminated manually (CTRL-C). + +_Response:_ + +```bash +:ping + +data: {"hash":"0xc7dc06c994400830054ab815732d91275bc1241f9be62b62b687b7882f19b8d4","logs":null,"txs":[{"to":"0x0000c335bc9d5d1af0402cad63fa7f258363d71a","functionSelector":"0x696d2073","callData":"0x696d20736861726969696969696e67"}]} +``` + + + + +:::info Event Data + +Events currently represent pending transactions, but eventually may be expanded to support other event types. For this reason we refer to this endpoint as an _event stream_, rather than a _transaction stream_. + +::: + +### Event Stream Endpoints + +| Network | URL | +|-|-| +| Mainnet | https://mev-share.flashbots.net | +| Sepolia | https://mev-share-sepolia.flashbots.net | + +The endpoint sends an event with the message `:ping` every 15 seconds if no other messages were sent in the last 15 seconds. + +## Event Scheme + +Events dispatched via the SSE endpoint are JSON-encoded objects that adhere to the following scheme: + + + +Note that each of these properties are optional; if a field is not present, it means that the transaction sender chose not to share that information. + +Below is an example of a transaction event received from the stream: + +```json +{ + "hash":"0xb756c9f6c34309d32c32daf1289c96d64a1068dfc2ead5e9bd0504640b91249e", + "logs":[ + { + "address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "topics":[ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000001b59718eafa2bffe5318e07c1c3cb2edde354f9c", + "0x0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c5" + ], + "data":"0x000000000000000000000000000000000000000000000000161545fdcf782a85" + }, + { + "address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "topics":[ + "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", + "0x0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c5" + ], + "data":"0x000000000000000000000000000000000000000000000000161545fdcf782a85" + }, + { + "address":"0x5c7bcd6e7de5423a257d81b442095a1a6ced35c5", + "topics":[ + "0x8ab9dc6c19fe88e69bc70221b339c84332752fdd49591b7c51e66bae3947b73c", + "0x0000000000000000000000000000000000000000000000000000000000000089", + "0x0000000000000000000000000000000000000000000000000000000000117363", + "0x0000000000000000000000003a23f943181408eac424116af7b7790c94cb97a5" + ], + "data":"0x000000000000000000000000000000000000000000000000161fb772f99eaf7a000000000000000000000000000000000000000000000000161fb772f99eaf7a000000000000000000000000000000000000000000000000161fb772f99eaf7a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000005216e484d6dde00000000000000000000000000000000000000000000000000016b90ac92248e000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001b59718eafa2bffe5318e07c1c3cb2edde354f9c000000000000000000000000b658ba58f7153e99c05c9b7610f17bfeeab6bff5000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b658ba58f7153e99c05c9b7610f17bfeeab6bff500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000005216e484d6dde000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + ], + "txs":[ + { + "to":"0x5c7bcd6e7de5423a257d81b442095a1a6ced35c5", + "functionSelector":"0x44b8be68", + "callData":"0x44b8be680000000000000000000000003a23f943181408eac424116af7b7790c94cb97a5000000000000000000000000b658ba58f7153e99c05c9b7610f17bfeeab6bff5000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000161fb772f99eaf7a000000000000000000000000000000000000000000000000161fb772f99eaf7a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008900000000000000000000000000000000000000000000000000016b90ac92248e0000000000000000000000000000000000000000000000000005216e484d6dde00000000000000000000000000000000000000000000000000000000001173630000000000000000000000000000000000000000000000000000000000000180ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000" + } + ] +} +``` + +### Understanding double-hash + +Note that the `hash` field is actually a keccak256 hash of the underlying bundle/transaction hash, essentially a double-hash. + +Below is code-snippet in golang to calculate double-hash for testing purposes. + +```go +package main + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "golang.org/x/crypto/sha3" +) + +func main() { + underlyingHash := common.HexToHash("0xd2d662b8aa0e8d86ea75d363522c9ede42ef538ae353da564d501c044a885293") + doubleHasher := sha3.NewLegacyKeccak256() + doubleHasher.Write(underlyingHash.Bytes()) + dHash := doubleHasher.Sum(nil) + matchingHash := common.BytesToHash(dHash) + fmt.Println(matchingHash.String()) //prints 0x90b4f5664cc201c3aa112d6bb2fa414c4aee10f00994692b282c1d14a1db6e4d +} +``` + +--- + +Now that you've started listening to transactions, you're almost ready to start searching! Read on to the next page to learn [about bundles](/flashbots-mev-share/searchers/understanding-bundles). + + +## Historical Data + +Historical hints can be retrieved from the historical hint API supported by the event stream endpoint. +Each hint is associated with a block number and timestamp. Block number is the latest Ethereum block number at the time the hint was generated. +Timestamp is the timestamp at the time the hint was generated. + +### GET /api/v1/history/info + +Returns information about the available historical hint data. + +#### Response + +| Field | Type | Description | +|-|-|-| +| count | number | The number of historical hints available. | +| minBlock | number | The earliest block number for which historical hints are available. | +| maxBlock | number | The latest block number for which historical hints are available. | +| minTimestamp | number | The earliest timestamp for which historical hints are available. | +| maxTimestamp | number | The latest timestamp for which historical hints are available. | +| maxLimit | number | The maximum number of historical hints that can be requested in a single request. | + + +### GET /api/v1/history + +#### Query Parameters + +| Field | Type | Description | +|-|-|-| +| blockStart (optional) | number | The block number to start retrieving historical hints from. | +| blockEnd (optional) | number | The block number to end retrieving historical hints from. | +| timestampStart (optional) | number | The timestamp to start retrieving historical hints from. | +| timestampEnd (optional) | number | The timestamp to end retrieving historical hints from. | +| limit (optional) | number | The maximum number of historical hints to retrieve. Default limit is `maxLimit`. | +| offset (optional) | number | The offset to start retrieving historical hints from. | + +#### Response + +Returns an array of historical hints. + +| Field | Type | Description | +|-|-|-| +| block | number | The block number associated with the historical hint. | +| timestamp | number | The timestamp associated with the historical hint. | +| hint | Hint | Hint as it was sent to the live streaming endpoint in the past. | + + +### Example + +#### Get information about historical hint data + +```bash +curl https://mev-share-goerli.flashbots.net/api/v1/history/info +``` + +_Response:_ + +```json +{ + "count": 20146, + "minBlock": 9091377, + "maxBlock": 9143624, + "minTimestamp": 1685452445, + "maxTimestamp": 1686225251, + "maxLimit": 500 +} +``` + +#### Get historical event data beginning at start of stream history + +```bash +curl https://mev-share-goerli.flashbots.net/api/v1/history +``` + +#### Get historical hint data from a specific block range + +```bash +curl 'https://mev-share-goerli.flashbots.net/api/v1/history?blockStart=9091377&blockEnd=9091379' +``` + +_Response:_ + +```json +[ + { + "block": 9091377, + "timestamp": 1685452445, + "hint": { + "txs": [ + { + "to": "0x8d460b72eaf3d63830e16c22d1fc6908d0834abe", + "callData": "0x", + "functionSelector": "0x00000000" + } + ], + "hash": "0x50df4922dd5f9adee91d44119132da85b50fe61f0c77556b039261f7828e1794", + "logs": null, + "gasUsed": "0x5208", + "mevGasPrice": "0x3b9aca00" + } + }, + { + "block": 9091379, + "timestamp": 1685452489, + "hint": { + "txs": null, + "hash": "0x40a85a6e37b449033924da72c0cf9dabcf2ac726b5a88f0ceff330f11bd01913", + "logs": null, + "gasUsed": "0xaae60", + "mevGasPrice": "0x45a9b5b00" + } + } +] +``` + +#### Querying with Offset & Limit + +Event history results are returned in chunks whose size are defined by `limit`, the maximum limit being specified in the [`/history/info` endpoint](#get-apiv1historyinfo). + +```bash +# assuming the limit is 500 +curl 'https://mev-share-goerli.flashbots.net/api/v1/history?blockStart=9091377' +curl 'https://mev-share-goerli.flashbots.net/api/v1/history?blockStart=9091377&offset=500' +curl 'https://mev-share-goerli.flashbots.net/api/v1/history?blockStart=9091377&offset=1000' +curl 'https://mev-share-goerli.flashbots.net/api/v1/history?blockStart=9091377&offset=1500' + +# or with a custom limit +curl 'https://mev-share-goerli.flashbots.net/api/v1/history?blockStart=9091377&limit=100' +curl 'https://mev-share-goerli.flashbots.net/api/v1/history?blockStart=9091377&limit=100&offset=100' +curl 'https://mev-share-goerli.flashbots.net/api/v1/history?blockStart=9091377&limit=100&offset=200' +curl 'https://mev-share-goerli.flashbots.net/api/v1/history?blockStart=9091377&limit=100&offset=300' +``` diff --git a/docs/flashbots-mev-share/searchers/getting-started.mdx b/docs/flashbots-mev-share/searchers/getting-started.mdx new file mode 100644 index 00000000..4bff2f01 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/getting-started.mdx @@ -0,0 +1,82 @@ +--- +title: Getting Started +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +To start searching on MEV-Share, you will first need to connect to a MEV-Share Node. As a reminder, the MEV-Share Node is responsible for receiving transactions and bundles from users, and selectively sharing information ("hints") about them with searchers. When a searcher wants to include a transaction in their bundle, they use that transaction's hash. The MEV-Share Node replaces it with the original transaction before sending the bundle to a block builder. + +## Connect to MEV-Share Node + +Flashbots operates an MEV-Share Node on the Ethereum mainnet. This Node provides endpoints for user transactions and searcher bundles. Additionally, it offers a Server-Sent Events (SSE) streaming endpoint, broadcasting pending events/transactions to searchers. + +The simplest way to connect to the Flashbots MEV-Share Node is to use a [client library](/flashbots-auction/libraries/mev-share-clients). For this guide, we'll refer to [mev-share-client-ts](https://github.com/flashbots/mev-share-client-ts). + + + + +_Add library to your project:_ + +```bash +yarn add @flashbots/mev-share-client +``` + +_Use the following code to import the library_ (Replace ALL_CAPS placeholders with your data): + +```typescript +import {Wallet, JsonRpcProvider} from 'ethers'; +import MevShareClient, { + BundleParams, + IPendingBundle, + IPendingTransaction, + TransactionOptions, +} from '@flashbots/mev-share-client'; + +const provider = new JsonRpcProvider(RPC_URL); +const authSigner = new Wallet(FB_REPUTATION_PRIVATE_KEY, provider); +const mevShareClient = MevShareClient.useEthereumMainnet(authSigner); +``` + +To use custom network parameters, you can instantiate a new MevShareClient instance directly. This example is what the client uses to connect to mainnet: + +```typescript +// connect to MEV-Share on mainnet +const mevShareClient = new MevShareClient(authSigner, { + name: 'mainnet', + chainId: 1, + streamUrl: 'https://mev-share.flashbots.net/', + apiUrl: 'https://relay.flashbots.net/', +}); +``` + +Further documentation on the client library can be found in the [mev-share-client-ts](https://github.com/flashbots/mev-share-client-ts). + + + + +For Rust users, thanks to Paradigm's effort, we have a Rust MEV-Share client [mev-share-rs](https://github.com/paradigmxyz/mev-share-rs). + +If you want a complete MEV bot framework, you could also directly go for [Artemis](https://github.com/paradigmxyz/artemis), which has built-in support for MEV-Share as outlined in this [example](https://github.com/paradigmxyz/artemis/blob/main/examples/mev-share-arb/src/main.rs). + + + +### A note on other languages + +If you're coding in a language that doesn't yet have a MEV-Share Node client library, you can send transactions and bundles directly with the [JSON-RPC endpoint](/flashbots-auction/advanced/rpc-endpoint). To listen for transactions, all you need is an HTTP client. More details on that in the [Event Stream](/flashbots-mev-share/searchers/event-stream) page. + +--- + +Now you should be connected to the Flashbots MEV-Share Node. Continue reading on the next page to learn how to [listen for hints](/flashbots-mev-share/searchers/event-stream) about pending transactions shared by the MEV-Share Node. + +:::note A note for experienced searchers getting acquainted with MEV-Share + +Searching on MEV-Share is different from searching on the mempool in that only certain parts of a transaction are shared with searchers. In the mempool, we can see all parts of a transaction, such as its calldata or who the transaction is from. But on MEV-Share, a transaction might only reveal its function selector, making a traditional arbitrage calculation infeasible. + +There are three primary strategies for searching on MEV-Share: + +- Probabilistically: send many bundles that probabilistically backrun MEV-Share orderflow. +- On-chain: perform more of your searching on-chain instead of off-chain. +- Existing: only search on transactions which share all the information you need. + +To maximally leverage MEV-Share searchers will need to employ new strategies. diff --git a/docs/flashbots-mev-share/searchers/ratelimiting.mdx b/docs/flashbots-mev-share/searchers/ratelimiting.mdx new file mode 100644 index 00000000..37d3d63f --- /dev/null +++ b/docs/flashbots-mev-share/searchers/ratelimiting.mdx @@ -0,0 +1,24 @@ +--- +title: Rate Limits +--- + +In order to protect our services from abuse we have rate limits on the number of requests that can be made. Currently, the rate limits are set as follows. + +## `relay.flashbots.net` - Bundles + +| Method | Limit | +|---------------------|--------------------| +| `eth_sendBundle` | 1800 / IP / 1 min | +| `mev_sendBundle` | 1800 / IP / 1 min | +| `eth_cancelBundle` | 600 / IP / 1 min | +| `mev_simBundle` | 300 / IP / 1 min | +| `eth_callBundle` | 300 / IP / 1 min | +| All others | 120 / IP / 1 min | + +Note that this is _requests_ and not _transactions_ submitted per second. There is no limitation on the number of transactions in a request. + +RPC rate limits for retail user transactions sent to `rpc.flashbots.net` [can be found here](../../flashbots-protect/ratelimiting). + +## Rate limit exceptions + +If you require a higher rate limit please reach out to [Shea Ketsdever](https://twitter.com/SheaKetsdever). diff --git a/docs/flashbots-mev-share/searchers/sending-bundles.mdx b/docs/flashbots-mev-share/searchers/sending-bundles.mdx new file mode 100644 index 00000000..812aa89b --- /dev/null +++ b/docs/flashbots-mev-share/searchers/sending-bundles.mdx @@ -0,0 +1,201 @@ +--- +title: Sending Bundles +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' +import SendBundleRpc from '@site/docs/specs/mev-share/_mev_sendBundle.mdx' +import BuilderInheritance from '@site/docs/specs/mev-share/blurbs/_builderInheritance.mdx' + +While the new [bundle spec](/flashbots-mev-share/searchers/understanding-bundles#bundle-definition) may look complex, a bundle can be sent with default parameters using a client library, which ends up looking quite similar to sending bundles on mev-boost. + +## Sending a Bundle + +:::info Placeholders + +Variables in `ALL_CAPS` are placeholders. To use this code, replace them with your own data. + +::: + + + + +```typescript +import MevShareClient, { BundleParams } from '@flashbots/mev-share-client' + +const mevShareClient = MevShareClient.useEthereumMainnet(authSigner) + +// ... + +const bundle = [ + {hash: PENDING_TX_HASH}, + {tx: await wallet.signTransaction(BACKRUN_TX), canRevert: false}, +] + +const params: BundleParams = { + inclusion: { + block: targetBlock, + // target several blocks with `maxBlock` + maxBlock: targetBlock + 3, + }, + body: bundle, + // send the bundles to more builders to speed up inclusion + privacy: { + builders: ["flashbots", "beaverbuild.org", "rsync", "Titan"] + } +} + +const bundleResult = await mevShareClient.sendBundle(params) +``` + +The first transaction in the bundle contains the hash of a pending transaction, which we presumably got from listening to the [event stream](/flashbots-mev-share/searchers/event-stream). The second transaction is one we sign ourself, which backruns the first transaction, presumably for a profit. + +:::info Bundle endpoint + +MEV-Share bundles are sent to the same RPC endpoint as MEV-Boost bundles: `https://relay.flashbots.net` + +::: + +See [mev-share-client-ts](https://github.com/flashbots/mev-share-client-ts/blob/main/src/examples/sendBackrunBundle.ts) for a full working example. + + + + +--- + +The params not included in the previous example can be used to configure more advanced conditions for your bundle's execution and the MEV refunds you earn. + +### Share bundle data + +To earn more MEV refunds and improve your bundle's chances of inclusion, you can specify data about your bundle's transactions that you wish to share with other searchers. The data that is shared is specified via the `privacy` parameter. + +:::caution bundles with signed txs only + +Note that bundles with transactions including the `hash` parameter are considered "unmatched", and will throw an error. + +::: + + + + +```typescript +const params: BundleParams = { + inclusion: { + block: 17539448, + maxBlock: 17539450 + }, + body: [ + {tx: "0x02...", canRevert: false}, + //can only include one backrun tx + ], + privacy: { + hints: { + calldata: true, + logs: true, + txHash: true, + }, + }, +} +``` + + + + +```bash +curl -X POST -H "Content-Type: application/json" -H "X-Flashbots-Signature: $FB_SIG" -d '{ + inclusion: { + block: "0x10ba178", + maxBlock: "0x10ba17a", + }, + body: [ + {tx: "0x02...", canRevert: false}, + {tx: "0x02...", canRevert: false}, + ], + privacy: { + hints: ["calldata", "logs", "tx_hash"], + }, +}' +``` + + + +Even sharing only the `tx_hash` hint can be enough to earn some extra MEV. The only requirement to earn it is that your bundle is included in another searcher's bundle. + +This strategy is particularly relevant to searchers who operate on public mempool transactions, and/or employ strategies that leave leftover MEV on the table (for example, if your strategy changes prices enough for a backrun arbitrage to be profitable). + +### Nest bundles (be a MEV-Share Node) + +MEV-Share Nodes nest bundles to build composite bundles that are more profitable. + + + + +```typescript +const params: BundleParams = { + inclusion: { + block: TARGET_BLOCK, + }, + body: { + {hash: PENDING_TX_HASH}, + {bundle: { + inclusion: {...}, + body: {...}, + privacy: {...}, + validity: {...}, + }} + }, +} +``` + + + + +### Builder Inheritance + + + +## Simulating Bundles + +Bundles matched by the MEV-Share Node can be simulated to check MEV profits. To simulate a bundle, we use the [`mev_simBundle`](/flashbots-auction/advanced/rpc-endpoint#mev_simbundle) endpoint. + +:::caution only matched bundles can be simulated + +Bundle simulations can only be executed on matched bundles, which contain only signed transactions, or nested bundles which also contain only signed transactions. Bundles with transactions including the `hash` parameter are considered "unmatched", and will throw an error. + +::: + + + + +```typescript +const params: BundleParams = { + inclusion: { + block: TARGET_BLOCK + }, + body: [ + {bundle: { + version: "beta-1", + inclusion: { + block: TARGET_BLOCK, + maxBlock: TARGET_BLOCK + 3, + }, + body: [{tx: SIGNED_TX_1}], + privacy: { + hints: {calldata: true}, + }, + validity: { + refundConfig: [{address: REFUND_ADDRESS, percent: 100}] + } + }}, + {tx: SIGNED_TX_2}, + ], + validity: { + refund: [{bodyIdx: 0, percent: 90}] + } +} + +const simResult = await mevShareClient.simulateBundle(params) +``` + + + diff --git a/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/bot.mdx b/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/bot.mdx new file mode 100644 index 00000000..3bb02282 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/bot.mdx @@ -0,0 +1,377 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import UniV2FactoryABI from "@site/docs/specs/contracts/abi/_uniswapV2Factory.mdx"; +import FlashLoanArbABI from "@site/docs/specs/contracts/abi/_flashLoanArb.mdx"; + +# Automated Arbitrage Bot + +With the flash-loan arbitrage smart contract finished, our last task is to automate the process of finding and back-running other users' trades. + +Since we already have a full bot that you can look at for a complete example, we'll just lay out the core principles and methods here, without walking through a whole bot step by step. This guide aims to give you everything you need to write your own edition of [simple-blind-arbitrage](https://github.com/flashbots/simple-blind-arbitrage). + +For a more in-depth guide on writing a bot from scratch, check out the [MEV-Share Limit Order Bot tutorial](/flashbots-mev-share/searchers/tutorials/limit-order/introduction). + +## Client Libraries + +To write your own bot, you'll need a way to interact with Flashbots APIs. Client libraries implement all the functionality of the APIs in their native programming language. If your preferred language doesn't have a MEV-Share client library already, you can interact with the APIs directly, effectively implementing your own client (let us know if you do!). Information about Flashbots APIs can be found in the [RPC docs](/flashbots-auction/advanced/rpc-endpoint) and [Event Stream docs](/flashbots-mev-share/searchers/event-stream). + +Client libraries have been developed for the following programming languages (more to come soon): + +||| +|-|-| +| typescript/javascript | [mev-share-client-ts](https://github.com/flashbots/mev-share-client-ts) ([npm](https://www.npmjs.com/package/@flashbots/mev-share-client)) | +| rust | [mev-share-rs](https://github.com/paradigmxyz/mev-share-rs) ([crates.io](https://crates.io/crates/mev-share)) | + +## Finding Pending Transactions + +To reiterate our goal, we need to find pending transactions from other Ethereum users and backrun them (send our transaction immediately after the user's transaction). If the user's trade moves the price enough, we'll arbitrage the trading pair between two exchanges for a profit. + +As MEV-Share receives new transactions, it broadcasts them to searchers via the [Event Stream](/flashbots-mev-share/searchers/event-stream). Each transaction shares varying amounts of data via [hints](/flashbots-protect/mev-refunds#hints), but by default, transactions that trade on Uniswap, Balancer, or Curve will expose the trading pair's contract address in the log topics. + +Here's an example of an event generated by a user who's (most likely) using MEV-Share's default privacy settings: + +### Example Event + +```json noInline +{ + "hash": "0x0c459dce812747c643f06c82eeca2a2f584b4e30af79b2b546fd015e4aac4541", + "logs": [ + { + "address": "0xca25091555d36ac0be8119ad967898ac30223b41", + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x" + }, { + "address": "0xca25091555d36ac0be8119ad967898ac30223b41", + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x" + } + ], + "txs": null +} +``` + +If we [look up the address](https://etherscan.io/address/0xca25091555d36ac0be8119ad967898ac30223b41) specified in the log topics, we'll see that it's a trading pair contract for QPEPE/WETH on Uniswap V2. This tells us that the user is buying/selling QPEPE on Uniswap, which means that we may be able to arbitrage it with Sushiswap or another Uni-V2 derivative. + +![](/img/mevshare-flashloan-arb-guide/qpepe5.jpg "arbitrage profit per amount_in") + +To detect events yourself, listen to the SSE Event Stream at [https://mev-share.flashbots.net](https://mev-share.flashbots.net). + +Events are comprised of either a single **transaction** or a **bundle** (multiple transactions): + +- In a **bundle** event, the `hash` field is the _bundle hash_ and the `txs` field will be populated with transaction-related data for each tx in the bundle. +- In a single-**transaction** event, `hash` represents the _transaction hash_ and the `txs` field is `null`. + + + + + +```typescript +const authSigner = new Wallet(Env.authKey).connect(provider) +const mevshare = MevShareClient.useEthereumMainnet(authSigner) + +mevshare.on("transaction", async (pendingTx: IPendingTransaction) => { + // handle tx event +}) +``` + +In this library, transactions are natively differentiated from bundles, so if you want to detect bundles too, just add another handler using `on("bundle", ...)`: + +```typescript +mevshare.on("bundle", async (pendingBundle: IPendingBundle) => { + // handle bundle event +}) +``` + +Check out the [implementation](https://github.com/flashbots/mev-share-client-ts/blob/main/src/api/interfaces.ts#L222-L282) for a closer look at how events are defined. + + + + + +```rust +let mainnet_sse = "https://mev-share.flashbots.net/"; +let client = EventClient::default(); +let mut stream = client.events(mainnet_sse).await.unwrap(); +while let Some(event) = stream.next().await { + // handle event +} +``` + +In this library, an event whose `txs` field is null is encoded as an empty array, so in practice, we need to check if `event.txs` is empty to see if we have a transaction or a bundle. + +```rust +while let Some(event) = stream.next().await { + if event.txs.len() == 0 { + // handle single tx + } else { + // handle bundle + } +} +``` + + + + +```bash +curl https://mev-share.flashbots.net +``` + +The Event Stream is streamed via SSE over a simple HTTP GET request, which may seem confusing. It's not terribly important for the purpose of building bots, but if you're curious, SSE was [added to HTML](https://html.spec.whatwg.org/multipage/server-sent-events.html) in HTML5. + + + + + +--- + +_To read more about how the SSE stream works, see the [Event Stream docs](/flashbots-mev-share/searchers/event-stream)._ + +## Filtering Relevant Transactions + +MEV-Share uses [**hints**](/flashbots-protect/mev-refunds#hints) to selectively share information about a transaction. Based on the hint preferences specifies by the user when connecting, the transactions (or bundles) they send will trigger events containing information about their transaction which is filtered according to their hint preferences. + +In this guide, we're only concerned with the fields in `logs`: `address` and `topics`. Other fields not covered in this guide are detailed in the [Event Scheme docs](/flashbots-mev-share/searchers/event-stream#event-scheme). + +_Snippet from an example event:_ + +```json +{ + ..., + "logs": [ + { + "address": "0xca25091555d36ac0be8119ad967898ac30223b41", + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x" + }, ... + ], +} +``` + +**`address`** tells us which contract address the user is interacting with. Looking back at the [example event](/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/bot#example-event), you'll notice that the `address` is the [trading pair](https://etherscan.io/address/0xca25091555d36ac0be8119ad967898ac30223b41), and not a router contract. This is likely because the user is using the default hints, which expose the trading pair instead of whatever router they might be interacting with. It's also possible that the user is another searcher, and they're trading on the pair directly. At any rate, it makes no difference to us. + +Given the default hint preferences, MEV-Share also exposes _only_ swap-related function signatures (if present) in the `topics`. The [simple-blind-arbitrage](https://github.com/flashbots/simple-blind-arbitrage/blob/main/execute/index.js#L54) bot uses the [Uniswap V2 Swap event signature](https://docs.uniswap.org/contracts/v2/reference/smart-contracts/pair#swap) to find pending Uniswap V2 trades. + +To find event signatures yourself, you need to take the keccak256 hash of the event signature. A nice tool to use for this is [**`cast`** from Foundry](https://github.com/foundry-rs/foundry): + +```bash +# get the hash of the UniV2 Swap event +cast sig-event "event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to +);" +0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822 +``` + +To filter our results so that we only deal with Swap events, we can simply check the `logs` field. If it isn't empty, each entry should contain `topics`. If our event signature hash is in those topics, then we know we're looking at a swap that we can backrun. For events generated by Protect users, the relevant signature hash is the first topic in the array, so we check `log.topics[0]`. + +Once we find a pending swap on one exchange, we need to find another exchange to arbitrage with. For example, if we detect a Uniswap V2 event, then we should try to arbitrage with Sushiswap. To get the trading pair on the other exchange, we need to use that exchange's [Factory](https://docs.uniswap.org/contracts/v2/reference/smart-contracts/factory) contract, which maps pairs of token addresses to [Pair](https://docs.uniswap.org/contracts/v2/reference/smart-contracts/pair) contract addresses. + + + + +```typescript +import {Contract} from "ethers" +import uniV2FactoryABI from "./abi/uniswapV2Factory.json" + +const swapTopic = "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822" + +// instantiate factory contracts +const uniV2FactoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f" +const uniV2Factory = new Contract(uniV2FactoryAddress, uniV2FactoryABI) +const sushiFactoryAddress = "0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac" +const sushiFactory = new Contract(sushiFactoryAddress, uniV2FactoryABI) + +mevshare.on("transaction", async (tx: IPendingTransaction) => { + for (const log of tx.logs) { + // skip if it isn't a swap event + if (log.topics[0] !== swapTopic) { + continue + } + + // data needed to find arb pair on another exchange + const pair = new ethers.Contract(log.address, pairABI) + const token0 = await pair.token0() + const token1 = await pair.token1() + // primitive differentiator between uniswap & sushiswap. ideally you'd use an enum to support >2 exchanges. + const isUniswap = pair.factory === uniV2FactoryAddress + + const altFactory = isUniswap ? sushiFactory : uniV2Factory + const altPair = await altFactory.getPair(token0, token1) + if (altPair === "0x0000000000000000000000000000000000000000") { + console.error("pair not found on alternative exchange") + continue + } + + // placeholder: send backrun bundle + await tryBackrun(pair.address, altPair) + } +}) +``` + +Note: querying the blockchain can cost precious time -- a better design would be to store arb-ready pairs somewhere fast, like in memory or a fast DB, and only query the blockchain when a stored pair alternative can't be found. + + + + +```rust +let swap_topic = "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822" + .parse::() + .unwrap(); +while let Some(event) = stream.next().await { + dbg!(&event); + // handle tx or bundle events containing swap logs + let event = event.unwrap(); + for log in event.logs { + // skip if it isn't a swap event + if log.topics[0] != swap_topic { + continue; + } + + // get data needed to find arb pair + // TODO + + // placeholder: send backrun bundle + tryBackrun(pair.address, altPair.address).await?; + } +} +``` + + + + +Note that the Sushiswap factory uses the same ABI as the Uniswap contract. Sushiswap is just a Uniswap V2 clone, so we know that the code is the same, which means the ABIs are also the same. + +:::info blind backruns + +Note that we potentially send a bundle for every log in the array. This is because some trades affect many trading pairs. Because we don't know which one was affected, we just attempt to backrun them all. The bundles we'll send for a given opportunity will use the same nonce for every backrun tx, so only the most profitable one will land. + +::: + +## Sending Backrun Bundles + +So far we've seen how to find the events we want to backrun, and we have a placeholder (`tryBackrun`) in place to send our backrun bundles. Once we implement `tryBackrun`, we'll have everything we need to send backrun bundles. + +A backrun bundle is an array consisting of two or more transactions: the user's transaction, and the following "backrun transactions." The backrun transaction we'll send is a call to `makeFlashLoan` on our arbitrage contract. If you recall from the implementation of the [flash loan arbitrage contract](https://github.com/flashbots/simple-blind-arbitrage/blob/main/src/BlindBackrunFlashLoan.sol), the [`receiveFlashLoan`](https://github.com/flashbots/simple-blind-arbitrage/blob/main/src/BlindBackrunFlashLoan.sol#L54-L87) function calls `_executeArbitrage` before paying back the loan. So all we have to do is get a flash loan, and then our contract will try to execute an arbitrage with the tokens it receives. If it's profitable, we pay the loan back, pay the builder, and keep the rest. If not, it reverts and is discarded by the builder. + +_This is the function we need to call:_ + +```solidity +function makeFlashLoan( + IERC20[] memory tokens, + uint256[] memory amounts, + bytes memory userData +) +``` + +To call `makeFlashLoan`, we specify the `tokens` we want to borrow, the respective `amounts` of tokens to borrow, and the ABI-encoded `userData` which will contain the arguments to the `_executeArbitrage` function. + + + + + + +This function sends a backrun given two pair addresses and a pending tx hash from the Event Stream: + +```typescript +import ArbContractAbi from ".abi/blindBackrunFlashLoan.json" + +const arbContractAddress = "0xTODO" +const arbContract = new Contract(arbContractAddress, ArbContractAbi, provider) + +async function tryBackrun(startPair, endPair, txHash) { + let blockNumber = Number(await this.signer.provider.getBlockNumber()) + console.log("Current block number:", blockNumber) + console.log("Building bundles") + + let bundleTransactionOptions = { + gasPrice: (await this.signer.provider.getGasPrice()), // This is *extremely* naive. + gasLimit: ethers.BigNumber.from(400000), + nonce: await this.signer.getTransactionCount(), + } + const types = [ + 'address', + 'address', + 'uint256' + ] + const values = [ + startPair, + endPair, + this.percentageToKeep + ] + let params = Web3EthAbi.encodeParameters(types, values) + + let bundleTransaction = await arbContract.populateTransaction.makeFlashLoan( + config.mainnetWETHAddress, + ethers.BigNumber.from(10**21).toString(), + params, + bundleTransactionOptions + ) + let bundle = [ + {hash: txHash}, + {tx: await this.signer.signTransaction(bundleTransaction), canRevert: false}, + ] + let fullBundle = { + inclusion: { + block: blockNumber + 1, // try to land in next block + maxBlock: ethers.utils.hexValue(blockNumber + 24) // Protect txs expire after 25 blocks + }, + body: bundle, + } + + return await mevshare.sendBundle(fullBundle) + + // for the reader: also send another bundle that calls `makeFlashLoan` + // with `startPair` and `endPair` in switched in `values`. +} +``` + +We get `blockNumber` at the start to set the target block in our bundle params. `bundleTransactionOptions` is pretty self-explanatory -- we use this because we're signing our backrun transaction manually, so it needs these params to be set manually. + +`types` and `values` define the function params that are passed via `userData` (as the variable `params`) in `makeFlashLoan`, and then decoded in `receiveFlashLoan` and passed to `_executeArbitrage`. + +We use `arbContract.populateTransaction.makeFlashLoan` to construct the backrun transaction, and then build a bundle with it and the user's pending tx hash. Lastly, we add the full bundle params for the MEV-Share `sendBundle` call, and then call it and return its result. + + + + +[mev-share-rs](https://github.com/paradigmxyz/mev-share-rs) + +```typescript +// rs +``` + +// TODO: Explain specific rust code here. + + + + +Put these examples together and you should have a working flash-loan arbitrage bot. If you get stuck, checkout [simple-blind-arbitrage](https://github.com/flashbots/simple-blind-arbitrage/blob/main/execute/index.js), written in javascript. diff --git a/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/flash-loan-basics.mdx b/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/flash-loan-basics.mdx new file mode 100644 index 00000000..882762e5 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/flash-loan-basics.mdx @@ -0,0 +1,33 @@ +import RemoteCodeBlock from "@site/src/components/RemoteCodeBlock" + +# Flash Loan Basics (Balancer) + +To recap, flash loans allow us to borrow vast amounts of tokens, which we can use to pay for trades. If we make a profit from executing an arbitrage, we pay the loan back and keep what's left over. If the arbitrage fails or does not produce enough profit to repay the loan, the transaction reverts and Flashbots prevents it from landing onchain, so we don't pay any fees. The only fees we pay are gas fees for successful arbitrage trades. + +Flash loans work because of [**transaction atomiticy**](https://www.webopedia.com/definitions/atomic-operation/). Ethereum implements this notion of atomicity over a single transaction: either all steps of the transaction succeed, or the entire transaction fails. So we say "the transaction reverts." The obvious example is a flash loan: if you borrow tokens with a flash loan, and then exit the transaction without paying it back, that transaction would be forced to revert. This is because the flash loan code itself is designed to revert if the borrower doesn't send the borrowed tokens back. + +We'll implement flash loans using Balancer because they don't charge any loan fees, and have plenty of capital with which we can perform our arbitrage trades. Typically, flash loans (including Balancer) work by using callbacks. Callbacks are just functions that _other_ smart contracts call on _your_ smart contract. A callback in solidity is implemented by declaring a function in your smart contract with the exact function signature (name, arguments, return type) of the callback. The function must also be `external` (we'll see why soon), but we won't make it `public` since we don't plan to call it ourselves. + +In the case of a flash loan on Balancer, the callback we have to create is the `receiveFlashLoan` function. When we want to get a flash loan, we'll call `vault.flashLoan`, where `vault` is the Balancer Vault smart contract, which holds the capital used for flash loans. In turn, the vault contract will call the `receiveFlashLoan` callback on our smart contract (this is why the function is `external`). In this function, the contract will have received the funds from the flash loan, so that's where we'll performs an arbitrage trade and pay back the loan. That's all there is to it! + +## Adding Flash Loans to Your Contract + +Flash loan capabilities can be added to any smart contract by simply implementing the `receiveFlashLoan` function. The only requirement for this function is that it pays back the flash loan, but we'll also call our arbitrage function here, since we only need flash loans for executing arbitrages. Add this function to your existing smart contract, and then add a function that calls `vault.flashLoan`. Here's an example we borrowed from the [Balancer docs](https://docs.balancer.fi/reference/contracts/flash-loans.html#example-code): + +```solidity +function makeFlashLoan( + IERC20[] memory tokens, + uint256[] memory amounts, + bytes memory userData + ) external { + vault.flashLoan(this, tokens, amounts, userData); +} +``` + +We'll call `makeFlashLoan` to get a flash loan, which will in turn trigger the `receiveFlashLoan` function, which will execute the arbitrage trade and pay the loan back. + +Here's a finished smart contract from [simple-blind-arbitrage](https://github.com/flashbots/simple-blind-arbitrage/blob/main/src/BlindBackrunFlashLoan.sol) for reference: + + + +Now that our contract is ready, we need to watch for new pending transactions and send arbitrage bundles to Flashbots when we find them. See the next page for instructions on writing a bot to do this for you. diff --git a/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/introduction.mdx b/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/introduction.mdx new file mode 100644 index 00000000..b1eb2b9c --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/introduction.mdx @@ -0,0 +1,9 @@ +# Introduction + +In this guide, we show you how to run an atomic arbitrage bot that uses flash loans. Flash loans allow you to borrow vast amounts of capital, which we'll use to pay for arbitrage trades. If you make a profit, then you pay back the loan and keep what's left over. If you don't, then the transaction simply reverts. Thanks to Flashbots, we don't pay for reverted transactions; we only have to pay gas for successful transactions. In sum, this is an ultra-low-risk strategy that requires very little upfront capital. + +We'll start with a [turnkey bot](https://github.com/flashbots/simple-blind-arbitrage) you can run yourself. For a detailed description of how it works, see the next page. + +--- + +- [simple-blind-arbitrage walkthrough video](https://youtu.be/Twcr2vZ1tRU?si=krmJbMH5htNTd-HK) diff --git a/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/simple-blind-arbitrage.mdx b/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/simple-blind-arbitrage.mdx new file mode 100644 index 00000000..7aad97d1 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/simple-blind-arbitrage.mdx @@ -0,0 +1,209 @@ +import RemoteCodeBlock from "@site/src/components/RemoteCodeBlock"; +import Admonition from "@theme/Admonition"; + +# Breakdown: simple-blind-arbitrage + +Our goal is to make an _arbitrage bot_ that uses flash loans to fund its trades. Arbitrage opportunities arise when one user makes a trade that results in a significant price shift on one exchange. If there is a trading pair on another exchange for the same tokens, and the difference in price between the two exchanges is large enough, we can turn a profit by sending a two trades immediately after the one that caused the price shift: one to buy tokens on one exchange, one to sell them on another. Sending one or more transactions immediately after another is known as **backrunning**. + +The goal of backrunning is to guarantee that our trades are first in line to execute after the result of some transaction (e.g. a price shift). This allows us to calculate the optimal trade at execution-time with certainty that it will either execute the ideal arbitrage, or revert. + +> This guide is based off of [simple-blind-arbitrage](https://github.com/flashbots/simple-blind-arbitrage). Before you continue with this guide, we recommend skimming the [README](https://github.com/flashbots/simple-blind-arbitrage#readme) for a technical overview of the system. If this raises more questions than it answers, that's OK! This guide will break down each component of the bot in detail. + +Before we backrun any transactions, we need to create a smart contract to make trades for us. The backrun transaction we send will call a function on the contract that executes the arbitrage. So how does the smart contract execute an arbitrage? + +To find out, let's examine this bot's strategy: _onchain searching_. + +## Onchain Searching + +MEV-Share introduces some key differences from more common strategies that you may have seen elsewhere (e.g. [simple-arbitrage](https://github.com/flashbots/simple-arbitrage), [subway](https://github.com/libevm/subway), [rusty-sando](https://github.com/mouseless-eth/rusty-sando)). These bots rely on _full transaction simulations_ (with signatures) to calculate the optimal trade _off-chain_. Calculating trades off-chain saves gas, but comes at the cost of uncertainty. Based on your bundle's placement in the block, the state your transaction relies on may change, which could potentially invalidate your transaction. + +On MEV-Share, pending transactions typically expose _less data_ than transactions in the public mempool. Transaction signatures are _always_ hidden from searchers. Simulation-based strategies (e.g. rusty-sando) on these transactions are usually not possible, since the amount traded by the user is typically hidden. That being said, users can choose to reveal more data to searchers, so all the classic strategies can still be used; they'll just land less often. + +The strategy we'll use is called "onchain" searching: we calculate how much to trade within the "trade" itself, effectively executing the searching strategy & algorithm _on the blockchain_ ("onchain"). The advantage of this strategy is that it has direct access to onchain state, meaning it can _always_ calculate the most optimal arbitrage trade parameters, unlike off-chain strategies. + +We send a backrun for every transaction that touches the tokens we're interested in trading, and rely on Flashbots to prevent unprofitable trades from landing on-chain. The _amount_ we buy & sell in our arbitrage trades is derived from the prices of the assets on the blockchain at the time of execution. Because we place our transaction behind another user's transaction ("backrunning"), the price that our transaction sees is the price which has been changed by the user's trade. This is where we get our arbitrage opportunity. + +## Arbitrage Contract + +We'll start by looking at a ready-made smart contract, and then break it down piece by piece. + +This is the **core logic contract**, which contains functions for performing arbitrage between Uniswap-V2-like exchanges (e.g. UniV2 / Sushiswap). Later on, we'll create other contracts that inherit this one, so that we can add custom asset management logic (flash loans, where to store profits, etc.) without having to rewrite all the Uniswap-centric logic, which you likely won't need to change. + + + +This may look complicated, but by the end we'll have explained every line of code. We'll start at the top with Imports & Interfaces. + +### Imports & Interfaces + +We start by importing some contract interfaces [`openzeppelin/access/Ownable.sol`](https://github.com/flashbots/simple-blind-arbitrage/blob/main/lib/openzeppelin-contracts/contracts/access/Ownable.sol) and [`./IWETH.sol`](https://github.com/flashbots/simple-blind-arbitrage/blob/main/src/IWETH.sol). Ownable allows us to restrict certain functions to the contract owner. IWETH allows us to deposit/withdraw ETH for [WETH](https://cointelegraph.com/news/what-is-wrapped-ethereum-weth-and-how-does-it-work). We need WETH because Uniswap (V2/V3) only supports ERC20 tokens. + +We also define a couple interfaces ourselves: `IUniswapV2Pair` and `IPairReserves`. We could import these from the official Uniswap contract library like we did with OpenZeppelin for the Ownable contract, but that comes with a lot of bloat for our project. In this case, we only need four functions from `IUniswapV2Pair`, and the struct definition of `PairReserves` from `IPairReserves`. + +Defining these interfaces allows us to interact with other smart contracts directly, as we'll see in the next sections. + +### Abstract Contract + +It's important to remember that this is an abstract contract, meaning that to use it, we'll need to write another smart contract that extends it (using the `is` keyword). This contract is responsible for implementing the capital-management strategy; where to keep money, where/how to get it; as well as any other custom logic such as fee payments, etc. We'll do a walkthrough of a finished implementation with flash loans after we break down the core logic contract. Read on to learn how our arbitrage algorithm works. + +### Calculating the Optimal Arbitrage + +To illustrate what the algorithm does, we plot profit (in ETH) from an arbitrage, where we buy `amount_in` tokens for WETH on one exchange and sell them all for WETH on another. + +![](/img/mevshare-flashloan-arb-guide/arb-profit-plot.png "arbitrage profit per amount_in") + +As you can see, the optimal amount_in to buy is approximately 35 ETH, but that's just eyeballing. How do we calculate the exact optimal point? + +The following function calculates the optimal trade amount such that gross profit is as high as possible: + +- let $F$ = `FEE` = 997 +- let $D$ = `FEE_DIVISOR` = 1000 +- let ${R_i}_{A|B}$ = `reserveIn` for exchange A or B + - this refers to the reserves of the token that we're paying _into_ the trade +- let ${R_o}_{A|B}$ = `reserveOut` for exchange A or B + - this refers to the reserves of the token that we're getting _out_ of the trade + +$$ +profit_{gross} = { + \left(\sqrt{F^2 \cdot {R_o}_A \cdot {R_o}_B \over {R_i}_B \cdot {R_i}_A} - D\right) \cdot {R_i}_B \cdot {R_i}_A \cdot D + \over + \left(F \cdot {R_i}_B \cdot D \right) + \left( F^2 \cdot {R_o}_A \right) +} +$$ + +_For example, if we're arbitraging WETH -> TKN on exchange A, then TKN -> WETH on exchange B, our variables would be:_ + +- ${R_i}_A$ = `WETH.reserves` +- ${R_o}_A$ = `TKN.reserves` +- ${R_i}_B$ = `TKN.reserves` +- ${R_o}_B$ = `WETH.reserves` + +How to derive this formula is beyond the scope of this document, but if you want to dig deeper, check out [this paper](https://arxiv.org/pdf/1911.03380.pdf). + +This formula is implemented by the `getAmountIn` function [in our smart contract](https://github.com/flashbots/simple-blind-arbitrage/blob/main/src/BlindBackrunLogic.sol#L116C14-L130), which relies on [`getNumerator`](https://github.com/flashbots/simple-blind-arbitrage/blob/main/src/BlindBackrunLogic.sol#L132-L173) and [`getDenominator`](https://github.com/flashbots/simple-blind-arbitrage/blob/main/src/BlindBackrunLogic.sol#L175-L206) to do the math (and to avoid "stack too deep" errors). + +Now that we know how to calculate the optimal amount of WETH to send for an arbitrage, let's put it to use. + +### `_executeArbitrage` + +`_executeArbitrage` is the core function responsible for looking up trading prices, calculating the optimal buy/sell amounts, and executing the two trades that make up the arbitrage. It only takes three arguments: + +```solidity +function _executeArbitrage( + address firstPairAddress, + address secondPairAddress, + uint percentageToPayToCoinbase +) ... +``` + +We just tell it which token pairs to trade, and how much profit to tip the validator. We choose to make `percentageToPayToCoinbase` a function argument because as competition increases, you may have to pay more to the validator to be selected over another competing bundle. This may change frequently, so it's important to monitor the bot and adjust the tip as needed. + +The function starts by reading the smart contract's own WETH balance. This is used later to verify our profits. We use the pair addresses to instantiate uniswap Pair contracts, which we pass to `getPairData` to read the reserves, which we then use to calculate the optimal arbitrage with `getAmountIn(firstPairData, secondPairData)`. + +Uniswap token pairs refer to their tokens as `token0` and `token1`; `token0` being the one whose address is numerically less than the other (e.g. 0x0123 < 0x0234); so we need to discern which token of the pair's two tokens is WETH. Our `getPairData` function sets this in the `isWETHZero` field. If WETH is token0, then we'll trade token0 -> token1 on exchange A, then token1 -> token0 on exchange B. If WETH is token1, then we just switch "token0" with "token1" and apply the same formula. + +Once we know which token is which, we can make assertions about our profits and calculate how much to send for the second trade. To calculate how many tokens we'll receive from a single trade, we use a [custom `getAmountOut` function](https://github.com/flashbots/simple-blind-arbitrage/blob/main/src/BlindBackrunLogic.sol#L249C1-L258C6). It's adapted from the [UniswapV2 Library contract](https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol#L43-L50); we just removed the safety checks to save gas. We don't need guard rails since Flashbots will prevent reverting transactions from landing onchain. + +We use the values calculated from `getAmountOut` as inputs to the token pairs' swap functions: we use `amountIn` (the "optimal arbitrage" value) as the amount (of WETH) to send for the first trade, then use the output (`firstPairAmountOut`) of the first trade as the input to the second trade, selling all the tokens we bought from the first exchange to the other. + +Once we've executed our trades, we should expect to have more ETH (or WETH) than we started with. But that won't always be the case. To ensure that we don't pay for an unprofitable trade, we check the WETH balance at the end of the `_executeArbitrage` function. If the balance isn't greater than when we first called the function, the transaction will revert. This protects us from malicious tokens, unforeseen market conditions, and a variety of other ways you can lose your money. + +When we do turn a profit, we need to pay some of it to the validators/builders in order to get our transactions on-chain. Block builders have differing preferences & ordering algorithms, but a good rule of thumb is to use `maxBaseFeePerGas` and `maxPriorityFeePerGas` values that are slightly higher than the market average, and then tip a percentage of your profits to the builder. MEV-Share uses this builder tip to pay the user; this is the "MEV kickback." + +### Fee Considerations + +If you have no competition, you only need to send as much as is required to pay the user's kickback, which includes the gas cost of the payment transaction and a non-zero kickback. + +To prevent negligible-value tips from being sent, MEV-Share uses 30,000 gas to represent the cost of the user payment transaction, instead of 21,000. The minimum tip payment required for a MEV-Share bundle to be eligible for inclusion is as follows: + +- let $F_B$ = `block.baseFee` + +$$ +T_{min} = 30000 \cdot F_B +$$ + +This represents the **total surplus ETH** that the coinbase must have received _in addition to gas fees_ for all transactions in the bundle. Note that we don't include a priority fee for the tip; this is because the builder will send the transaction that pays the user with a priority fee of 0. + +Bots that only send two-transaction bundles will probably want send this tip in the backrun tx. However, this may also be paid by multiple transactions. +Also note: sending your tip via `block.coinbase.transfer` is not technically necessary; it is possible to achieve the same effect by simply increasing the gas price (`maxBaseFeePerGas` and `maxPriorityFeePerGas`) of your backrun transaction(s). + + + +Tipping the minimum is unlikely to result in your bundle landing on-chain unless you have zero competition. If there are other searchers competing to include the same transaction in their bundles, you will have to pay a higher percentage of your profits to outbid them. + +You may try tipping low to start, but over time, you should expect competition to increase. With healthy competition, your tip is likely to be around 80-90%. + +- let $P_{net}$ = net profit (profit after paying gas fees) +- let $\gamma$ ($\gamma \in \R; \gamma > 0, \gamma < 1$) = percentage of profit sufficient to outbid competition + +$$ +T_{optimal} = (30000 \cdot F_B) + (P_{net} \cdot \gamma) +$$ + +How you find the exact optimal value of $\gamma$ is a matter of trial-and-error, and will continually change, but you'll probably find success between 50-90%. + + + +By default, 90% of the tip $T$ is sent to the user whose transaction was included by your bundle. This can be changed with the `validity` parameter in the `mev_sendBundle` params, but it suffices for now to keep the default settings and just send less from the smart contract. + +### Compile & Deploy (optional) + +If you want to run a capital-intensive strategy (not using flash loans) you'll have to deploy your own contract. This is not required if you use our flash loan contract. The flash loan contract is designed to send profits to the caller when the arbitrage is done. This allows anyone to execute arbitrages without paying to deploy the contract. The tradeoff with this is that it costs more gas to transfer the profit to your wallet than it does to keep the money in the contract. However, if you decide to deploy your own contract, its transactions will use less gas (at the risk of your contract containing a bug that might compromise the funds), but will only land bundles if it holds enough capital to buy the required tokens. + +A simple way to deploy contracts is to use [**`forge`** from Foundry](https://github.com/foundry-rs/foundry): + +```bash +# compile contracts +forge build + +# to test with a local fork: +anvil -f $MAINNET_RPC_URL --chain-id 1 & + +# these vars are set to deploy on local fork; change as/if needed +export PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +export WETH_ADDRESS="0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" +export RPC_URL="http://localhost:8545/" + +# deploy flashloan arb contract +forge create -r $RPC_URL --private-key $PRIVATE_KEY BlindBackrunFlashLoan --constructor-args $WETH_ADDRESS + +# or deploy capital-intensive contract +forge create -r $RPC_URL --private-key $PRIVATE_KEY BlindBackrun --constructor-args $WETH_ADDRESS +``` + +_output:_ + +``` +No files changed, compilation skipped +Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +Deployed to: 0xc075BC0f734EFE6ceD866324fc2A9DBe1065CBB1 +Transaction hash: 0xe9567cce60dfdc1f815f4724340228f2af77ee5cc157a69d07c4b270fcab3a30 +``` + +## Tradeoffs + +Our onchain searching strategy is relatively straightforward, but it has its drawbacks: + +- calculating trade amounts onchain costs gas, making the strategy less efficient +- only Uniswap-V2-like trading pairs are compatible with this strategy + - Uniswap V3 uses a different algorithm, which is very costly to compute onchain + +### Offchain Searching + +The more data you can compute offchain, the less gas you have to spend. This gives you more ETH to tip with; better profit margins or a competitive edge. + +However, off-chain data is not always as accurate as on-chain data. This is because other transactions may affect the state of the blockchain (e.g. the price of a trading pair) if they are placed before your bundle in the block. +The very first position in an upcoming block ("top of the block") is the only one that's guaranteed to match the state of the last block. + +Unless you're the block builder (or have privileged access to their orderflow), you have no way of knowing where in the block your transaction will be placed, so you have no way of knowing whether the off-chain state used to calculate your strategy's parameters (e.g. your trade amounts) is still accurate. You may add logic in your smart contract that reverts if the transaction isn't placed in the first position, which will guarantee that your information is accurate, but may lower your chances of being included, depending on the builder's transaction-sorting algorithm. + +### Other Exchanges + +We strictly use Uniswap V2 in this guide/bot because its pricing algorithm is simple, making arbitrages easily calculable. Uniswap V2 and Sushiswap use the same pricing algorithms, so we efficiently arb between those two exchanges. Uniswap V3 math is more complicated, making arbitrages on V3 very inefficient to calculate onchain. + +However, Uniswap V3+ processes much more trade volume than V2. To improve your profits, consider developing a strategy that integrates Uniswap V3 into your own contract. It will likely involve probabilistic methods. Also note: Uniswap V4 uses the same pricing math as V3. + +MEV-Share also shares hints for swaps on Balancer and Curve, from users with the default hint settings. + +--- + +Now that the core contract is ready, let's add flash loans. Read on in the next page. diff --git a/docs/flashbots-mev-share/searchers/tutorials/limit-order/debugging.mdx b/docs/flashbots-mev-share/searchers/tutorials/limit-order/debugging.mdx new file mode 100644 index 00000000..68fea6cc --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/limit-order/debugging.mdx @@ -0,0 +1,5 @@ +--- +title: Debugging +--- + +If your bundles aren't landing, there could be a few reasons why. Take a look at our [debugging guide](/flashbots-mev-share/searchers/debugging) for tips on how to simulate and interpret bundle failures. \ No newline at end of file diff --git a/docs/flashbots-mev-share/searchers/tutorials/limit-order/introduction.mdx b/docs/flashbots-mev-share/searchers/tutorials/limit-order/introduction.mdx new file mode 100644 index 00000000..c9a0a668 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/limit-order/introduction.mdx @@ -0,0 +1,49 @@ +--- +title: Introduction +--- + +MEV-Share is a new protocol for sending and searching on Ethereum transactions. In this guide, we'll write our own bot to see first-hand how MEV-Share works, and how to find profitable opportunities. + +This guide assumes you have some programming experience, but we've tried to make it as beginner-friendly as possible! No prior searching experience will be required. + +We'll provide full examples with code so you can follow along and run the bot yourself! + +## Limit Orders + +In this guide, we'll be making a version of a [limit order](https://www.investor.gov/introduction-investing/investing-basics/how-stock-markets-work/types-orders#:~:text=A%20limit%20order%20is%20an,for%20no%20more%20than%20%2410.) bot. Limit orders are a common feature on exchanges which let you fill an order when the price of a trading pair (e.g. ETH/DAI) reaches a target that you specify. For example, if I wanted to buy DAI when the price reaches 1800 DAI/ETH, I could place a limit order for to buy 1800 DAI for 1 ETH, and the trade would automatically execute when the price reached 1800. If the price was over 1800, then we'd want to fill our order at the higher price — since we're buying DAI, we want more DAI out for a fixed amount of ETH in. + +Limit orders are useful if you are sensitive to price but not time. For example, I might have a lot of ETH and I want to make sure I get a good price for it. But it's okay if it takes week to complete the trades. + +The bot we're building works like a traditional limit order — we'll buy when the price reaches our target. But in this case, we'll have an additional edge: private orderflow (and some clever code). + +## MEV-Share Bot + +We'll use the MEV-Share event stream to watch for pending transactions (private orderflow) that change the price of our trading pair. Then we'll backrun each of those transactions with our ideal trade. When a transaction sufficiently shifts the price in our favor, our backrun will be first in line to buy the tokens at a discounted rate. + +Our backrun transaction will specify an exact price at which the order can be filled, otherwise the transaction reverts. Because we're sending to Flashbots, reverted transactions won't land on chain and we won't pay any fees for failed attempts. + +In short, we'll attempt to backrun all trades for the assets we care about — but only land the backruns that execute at a desirable price. + +> This guide is based on the [simple-limit-order-bot repo](https://github.com/flashbots/simple-limit-order-bot). If you want to get straight to the code, the repo contains a fully-operational bot that only requires a `.env` file for you to run. + +## Glossary + +*Remember the following terminology (because we use it a lot!):* + +- **MEV**: [Maximal Extractable Value](https://ethereum.org/en/developers/docs/mev/). +- **bundle**: an array of transactions that execute in order and [atomically](https://en.wikipedia.org/wiki/Atomicity_(database_systems)). +- **backrun**: a transaction sent immediately after another transaction. + - example: a “backrun bundle” is an array with two or more transactions; the first transaction (presumably chosen from a public pool of pending transactions) creates an MEV opportunity, which the following transactions try to capture. +- **orderflow**: umbrella term for transactions or bundles. +- **searcher**: a bot operator (or bot) that attempts to extract MEV. +- **on-chain**: a transaction that lands “on chain” (or on-chain, or onchain) is permanently included on the blockchain. +- **WETH**: “Wrapped ETH” — ERC-20 version of ETH, used by Uniswap in trading pairs +- **MEV-Share**: “a protocol that lets users selectively share orderflow and information with searchers”. + +:::info Running this bot requires that you have an Ethereum account with some ETH and WETH. + +Our example uses 1/10000000000 of an ETH — you may want more. If you don't have any WETH, you can wrap ETH into WETH on Uniswap: + +![Example weth swap](/img/weth-swap.png) + +::: info \ No newline at end of file diff --git a/docs/flashbots-mev-share/searchers/tutorials/limit-order/more-resources.mdx b/docs/flashbots-mev-share/searchers/tutorials/limit-order/more-resources.mdx new file mode 100644 index 00000000..9c23b257 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/limit-order/more-resources.mdx @@ -0,0 +1,30 @@ +--- +title: More Resources +--- + +We hope you found this guide useful! This is only the first of several, in which we'll show you more exciting ways to use MEV-Share, and all its unique features. In future guides, we'll talk about how to write more advanced bots that extract MEV opportunities, how to maximize your profits by using hints, and cover advanced features and techniques that are made possible by MEV-Share. + +While we work on more guides, we encourage you to check out our other resources on MEV-Share, and get in touch with us on Discord, on our Forum, or @ one of us on Twitter! + +- [Discord](https://discord.gg/flashbots) +- [Forum](https://collective.flashbots.net/) +- Twitter handles for MEV-Share: [@SheaKetsdever](https://twitter.com/SheaKetsdever) [@epheph](https://twitter.com/epheph) [@drog_v](https://twitter.com/drog_v) [@zeroXbrock](https://twitter.com/zeroxbrock) + +**Specifications** + +- [MEV-Share Spec](https://github.com/flashbots/mev-share) + +**Code Examples** + +- https://github.com/flashbots/simple-limit-order-bot (Typescript) +- https://github.com/flashbots/simple-blind-arbitrage (Javascript) ([Video walk through](https://www.youtube.com/watch?v=Twcr2vZ1tRU)) +- https://github.com/paradigmxyz/artemis (Rust) + +**MEV-Share Client Libraries** + +- https://github.com/flashbots/matchmaker-ts (Typescript) +- https://github.com/paradigmxyz/mev-share-rs (Rust) + +**MEV-Share Backend Node** + +- https://github.com/flashbots/mev-share-node \ No newline at end of file diff --git a/docs/flashbots-mev-share/searchers/tutorials/limit-order/sending-bundles.mdx b/docs/flashbots-mev-share/searchers/tutorials/limit-order/sending-bundles.mdx new file mode 100644 index 00000000..4c5b6f8e --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/limit-order/sending-bundles.mdx @@ -0,0 +1,235 @@ +--- +title: Sending Bundles +--- + +## Getting our trade ready + +After we find a transaction that touches the trading pair we're targeting, we need to calculate how many tokens we should expect to receive. In this project, we are specifically *buying* DAI with ETH (technically WETH, because Uniswap only trades ERC-20 tokens), so we want the price of DAI/WETH to be as low as possible. In code, we define our price requirements in terms of the *amount of tokens we receive* from the trade — so we want the *highest* amount of tokens possible, but we have a definite minimum (1800 DAI). + +In terms of a limit order, we're saying that we want our order to be filled when the price is *at most* 1800 DAI, but if the price is lower, then we want to fill at the lower price, which yields more DAI per WETH. + +To find our token's market price, we simulate our trade by calling the `swapExactTokensForTokens` function with a static call. A static call simply simulates the transaction, so we can see what it would do if we were to actually send it. We set our buy/sell amounts that we defined earlier to see how much we'd get from the swap. Add this function to your code — we'll add it to our main function later. + +`src/index.ts` + +```tsx +async function getBuyTokenAmountWithExtra() { + const resultCallResult = await uniswapRouterContract + .swapExactTokensForTokens + .staticCallResult( + SELL_TOKEN_AMOUNT, + 1n, + [SELL_TOKEN_ADDRESS, BUY_TOKEN_ADDRESS], + executorWallet.address, + 9999999999n + ) + const normalOutputAmount = resultCallResult[0][1] + const extraOutputAmount = normalOutputAmount * (10000n + DISCOUNT_IN_BPS) / 10000n + return extraOutputAmount +} +``` + +The minimum amount we can expect to receive from a swap is defined by `normalOutputAmount`. Then, we calculate how much we'd get if with a 40 basis-points discount, which we should expect if we successfully backrun a transaction that shifts the price in our favor, and assign this value to `extraOutputAmount`. + +When we detect a new transaction, we'll need to check the going price and set up our trade accordingly. If the price is lower than our target, and because we're trying to *buy* tokens, we want to make sure our trade expects more tokens out; as many as we can get at the lower price with our fixed sell amount (the ETH we'll spend to buy the tokens). If the price is higher than our target, then we'll just set the expected output to the minimum amount we'd expect to if the price were at our target, in hopes that the transaction we backrun will move the price enough for us to make a trade. + +Let's add a couple more functions to implement this logic: + +`src/index.ts` + +```tsx +async function getSignedBackrunTx( outputAmount: bigint, nonce: number ) { + const backrunTx = await uniswapRouterContract.swapExactTokensForTokens.populateTransaction(SELL_TOKEN_AMOUNT, outputAmount, [SELL_TOKEN_ADDRESS, BUY_TOKEN_ADDRESS], executorWallet.address, 9999999999n) + const backrunTxFull = { + ...backrunTx, + chainId: 1, + maxFeePerGas: MAX_GAS_PRICE * GWEI, + maxPriorityFeePerGas: MAX_PRIORITY_FEE * GWEI, + gasLimit: TX_GAS_LIMIT, + nonce: nonce + } + return executorWallet.signTransaction(backrunTxFull) +} + +async function backrunAttempt( currentBlockNumber: number, nonce: number, pendingTxHash: string ) { + let outputAmount = await getBuyTokenAmountWithExtra() + if (outputAmount < BUY_TOKEN_AMOUNT_CUTOFF) { + console.log(`Even with extra amount, not enough BUY token: ${ outputAmount.toString() }. Setting to amount cut-off`) + outputAmount = BUY_TOKEN_AMOUNT_CUTOFF + } + const backrunSignedTx = await getSignedBackrunTx(outputAmount, nonce) + try { + const sendBundleResult = await mevshare.sendBundle({ + inclusion: { block: currentBlockNumber + 1 }, + body: [ + { hash: pendingTxHash }, + { tx: backrunSignedTx, canRevert: false } + ] + },) + console.log('Bundle Hash: ' + sendBundleResult.bundleHash) + } catch (e) { + console.log('err', e) + } +} +``` + +The `getSignedBackrunTx` function creates the transaction we'll send to execute our trade on Uniswap. We set a fixed gas price here for simplicity. If you prefer, you could replace it with dynamic fees that track the base fee of the chain. But constant gas prices may work better if you don't want to spend a lot on gas, and don't mind having to wait if the network's base fee exceeds your settings. + +The `backrunAttempt` function defines our price requirement logic: we make sure that `outputAmount` is at least our previously-defined cutoff amount. However, if the simulated output amount is higher, then we set `outputAmount` to expect that much, which protects us from [slippage](https://en.wikipedia.org/wiki/Slippage_(finance)) in case other transactions in the block happen to trade on the same pair. This function then sends our bundle to MEV-Share. If the bundle was received successfully, we should see a bundle hash logged to our console. + +Using `getBuyTokenAmountWithExtra`, we define `outputAmount`, the amount we expect to receive from the trade. We create our backrun transaction `backrunSignedTx` and send it to MEV-Share in a bundle by calling `mevshare.sendBundle`. + +*Real quick, let's break down the bundle we passed to `sendBundle`:* + +The `block` parameter in `inclusion` specifies which block we want the bundle to land in. We indicate here that we want our bundle to land in the next block. + +The `body` parameter is where we set our bundle's transactions. The order in which they're specified is the order in which they'll execute on chain. Each transaction is specified as an object, with either a `hash` parameter, or a `tx` parameter (paired with `canRevert` to specify whether this transaction is allowed to revert and land on chain). The transaction we specify with `hash` is the pending transaction from the event stream that we want to backrun. We have to use its hash because the MEV-Share event stream does not reveal the entire signed transaction. Naturally, the following transaction, specified by `tx`, is our trade. + +Once we stitch all these new functions into our main loop, our bot will be done! + +## Sending a backrun bundle + +When we detect a new pending transaction in the `mevshare.on("transaction")` callback that affects the price of our target pair, we need to send a bundle using the `backrunAttempt` function. This bundle checks our target price and sets up our trade to get us the best price possible. + +`src/index.ts` + +```tsx +mevshare.on("transaction", (pendingTx) => { + // ... + // TODO: backrun the user tx + if (!transactionIsRelatedToPair(pendingTx, PAIR_ADDRESS)) { + console.log('skipping tx: ' + pendingTx.hash) + return + } + console.log(`It's a match: ${ pendingTx.hash }`) + const currentBlockNumber = await provider.getBlockNumber() + backrunAttempt(currentBlockNumber, nonce, pendingTx.hash) +}) +``` + +We'll also want to set up a callback that watches for new blocks and retries previous backrun attempts. Our bundles only target one block, but Protect transactions (which make up the transactions in the event stream) are valid for 25 blocks from when they're received. This means that if our backrun wasn't successful before, we can try again up to 24 more times. + +Add this code to your `main` function: + +```tsx +let recentPendingTxHashes: Array<{ txHash: string, blockNumber: number }> = [] +provider.on('block', ( blockNumber ) => { + for (const recentPendingTxHash of recentPendingTxHashes) { + console.log(recentPendingTxHash) + backrunAttempt(blockNumber, nonce, recentPendingTxHash.txHash) + } + // Cleanup old pendingTxHashes + recentPendingTxHashes = recentPendingTxHashes.filter(( recentPendingTxHash ) => + blockNumber > recentPendingTxHash.blockNumber + BLOCKS_TO_TRY) +}) +``` + +And in your `mevshare.on` callback, add this piece at the end: + +```tsx +recentPendingTxHashes.push({ txHash: pendingTx.hash, blockNumber: currentBlockNumber }) +``` + +When you're done, your main function should look like this: + +`src/index.ts` + +```tsx +async function main() { + console.log('mev-share auth address: ' + authSigner.address) + console.log('executor address: ' + executorWallet.address) + const PAIR_ADDRESS = (await uniswapFactoryContract.getPair(SELL_TOKEN_ADDRESS, BUY_TOKEN_ADDRESS)).toLowerCase() + await approveTokenToRouter(SELL_TOKEN_ADDRESS, UNISWAP_V2_ADDRESS) + const nonce = await executorWallet.getNonce('latest') + let recentPendingTxHashes: Array<{ txHash: string, blockNumber: number }> = [] + + mevshare.on('transaction', async ( pendingTx: IPendingTransaction ) => { + if (!transactionIsRelatedToPair(pendingTx, PAIR_ADDRESS)) { + console.log('skipping tx: ' + pendingTx.hash) + return + } + console.log(`It's a match: ${ pendingTx.hash }`) + const currentBlockNumber = await provider.getBlockNumber() + backrunAttempt(currentBlockNumber, nonce, pendingTx.hash) + recentPendingTxHashes.push({ txHash: pendingTx.hash, blockNumber: currentBlockNumber }) + }) + provider.on('block', ( blockNumber ) => { + for (const recentPendingTxHash of recentPendingTxHashes) { + console.log(recentPendingTxHash) + backrunAttempt(blockNumber, nonce, recentPendingTxHash.txHash) + } + // Cleanup old pendingTxHashes + recentPendingTxHashes = recentPendingTxHashes.filter(( recentPendingTxHash ) => + blockNumber > recentPendingTxHash.blockNumber + BLOCKS_TO_TRY) + }) +} +``` + +> For a full, working code example, check out https://github.com/flashbots/simple-limit-order-bot + +![Mario finish](/img/mario-finish.jpg) + +*That's all you need!* This code will listen for new transactions and blocks, and trigger our code to send bundles when we find a transaction that changes the price. + +Run the code and you should see something like this: + +```bash +$ npx ts-node src/index.ts +mev-share auth address: 0xE52A621a647A1013cE44EEBB37676F4c7205F87e +executor address: 0x5b2c1E34C3Be923c123Ec858F474645B1Fcee0A3 +skipping tx: 0x8ec57508495115338395a0de7cb9b85956845c83047bc523fc5b169fc9820251 +skipping tx: 0xbe8be3ddfe27c03d79d44bf5f46a40e3491960c85fc29ceb9b9d7b968e3c7760 +skipping tx: 0xd8bdceffde345bf71fb8058c0baae04eee58c25739dd31d3354c9777162be769 +skipping tx: 0xfdc9ed3cd98e15d9e2b6bcea832f7f178d23f7c20d7900de5cf23af9051337c3 +skipping tx: 0x4878de9bf339cffd8facb5037698839f97e8624806dec97f39d71254101ed712 +skipping tx: 0x0b1964af41ddf4d4082f6d68073f200b1d72ffc9852441aa7621feba34c4e045 +skipping tx: 0x23494341ec01dd3797778958e02cf9a8dbb8bb91989150b162cc7c16fe177267 +skipping tx: 0xb201acbfe4c140a14cdd90b84d3a2c277d14bbb53e9bbacc095282c7b5e93c93 +skipping tx: 0x8777978ea1c14af518d32ce74c8671905619ee8b6008c4c6f9a94e83fa2dda15 +skipping tx: 0x6f25db574493009c6a9a22f3c15370038f80b8c86f3547f72811c0c58dfc6160 +skipping tx: 0xb98f1e587f9a292043738f5c70e6532a6cd94a2f530a060556ce99256ca52e05 +skipping tx: 0x0c347e08df1fee8bb0f4fafe606b1a1b8159804623bbcd78c03097dc316ca47a +skipping tx: 0x2081950a40ca29cbc46c043f846a1e3205f3baaa09a8e531a20ff63c649617ed +skipping tx: 0x8ccc554df02cf2c8880bde8ea4b7dcfecc533ec4c799e2a14a55282937934abf +skipping tx: 0x7258bf29fb9879f10ee859ae80f491a7a652caf0825a1b2196cb2b39747e9a77 +skipping tx: 0x8d49b3d723457845484c16b1d637265821a63c601dc0184417c2a20789ec2881 +skipping tx: 0xfacd7b58b52184724fc1d8ad688544d0f45fb005110f49b790d320997e5ba79e +skipping tx: 0x176d69b0353ea5cb421f7218f94ec54191bdca3cc1d659587546235d73ae8837 +skipping tx: 0x518f3b9844a92d617146520b61face546aa399358f40136827fc24db8827b9ea +skipping tx: 0x58da384fd342fdc8d8ba96faf3e12bc89417c7099888eaedfd77a00bcf10f701 +skipping tx: 0x1431112c598a1a7969f048d6893b3ad72424fcc7a1de0b880ffc98585fcd2e7d +skipping tx: 0x55bb0a2209665e464a385b188d0dcc1d91c93bae1509368cdc5abf9cb38afdfe +skipping tx: 0x0978078667fd1bd834c5b8ca20e06b403e0df6311455de6dc6651c33542a594d +skipping tx: 0xed23e27981fba7b4e661c10c9d4e70ada3eafb9cd4197a24f4566c1c5266e601 +skipping tx: 0x3734c599be31a485a84376cf108fd76d5edc9637f834a9982a1600f0abd533d0 +skipping tx: 0xc932320f77f8436037ab27ead89c004acc8f8bc52e0c19dcb6ecea103bc2973a +skipping tx: 0xe880ce068eba29657bf14c535f421adefc43933fe84ef157cf4cdf7524edd22e +skipping tx: 0x350aaae85d6167e219480fb60104d27a773675ff387c2634da44f1b36bbeba6b +skipping tx: 0xfddcfb509e19be4500e4a1a03c97d77b2261fe41d8f019d48e0c0cea11cd1cc8 +skipping tx: 0x08867976aecc2b09c57cf17d2e16dda9e3c3026da9c2ca3fed3187c7b577fa91 +``` + +And after some time… + +```bash +skipping tx: 0x82b46667867fd7e1684f14dd34503ee9b9bbe106352c00006592ceae8e58a9d7 +skipping tx: 0x51c79454c4e86df176b51524fc254ab2e04c0861c329cdeab7a90d2e3309c3b7 +skipping tx: 0xf0977236782c93462ea442514a28be64f11cd5feee647929b74834adff0b527a +skipping tx: 0x8d5273f1eefa3a6daa40355df621e488dcf434e7bffb6201e0d98c26709ea35b +skipping tx: 0x382ba4c5d62557277f494032b2578ba52435cccef7fd236f02278df337fa0f7b +skipping tx: 0x04b40010c4a986f19fdedde1c2b0b92bf146074fae98693dc53a10d32a15bbba +skipping tx: 0x7c89acc455e040f8690933af2fa40cac714f5f2790758972a35d4ea39ced32c9 +skipping tx: 0xfcb49a980017cc3e0e5d5d4a0ff40aa170dc2e32021f81319c8d2b117b12bf52 +skipping tx: 0x1861b5afc21a2e82dbdb8bc26777ced087c6a4830482b2f65273ba7159c204c8 +skipping tx: 0x0817d834d6a537b6839858465f5e7ce2f95c9c5e353cf85282cd0f1da5b90e50 +skipping tx: 0x387dd96be2b59da5f6e991b41d670f752fecd4d6571198729f1037996a4e2d3c +skipping tx: 0x6b8577d861ce46f1e780c7ce59925ac9be40fd5428954c15a7e115cacaf974e2 +skipping tx: 0xc41d53c886897aeda1fc401f337a2d8b3ef737e78f06a52cbbe29b501a1c7736 +skipping tx: 0x52f2f383b4af41aa47f09ed8fd237358b32f33a0f471fc7be40b83179e513458 +skipping tx: 0xbcc799ad42925730cbb724c0fe5ed7b8444e7fbc8a4219d7346a2a03e8ac5131 +It's a match: 0xf76ce750b75ccd34b9174fdf8b574d129630d51422f3ca84f4f308952a4ea3b4 +``` + +It may take a while to find a match — remember, the code scans for a trade on the ETH/DAI pair on Uniswap V2. There are lots of other events to consider for future improvements to this bot! + +You may also consider removing the code that checks the event to see if it matches our pair address. It's possible that the price could move to our target level without us seeing an event to backrun. If we simply backrun every transaction we see, then we can potentially benefit from opportunities that we can't yet see. However, it is essential to understand how to use logs on MEV-Share, as they provide critical data that can be used for a multitude of other purposes, so we've introduced it here as a practical example. diff --git a/docs/flashbots-mev-share/searchers/tutorials/limit-order/setup.mdx b/docs/flashbots-mev-share/searchers/tutorials/limit-order/setup.mdx new file mode 100644 index 00000000..a16056b5 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/limit-order/setup.mdx @@ -0,0 +1,159 @@ +--- +title: Set Up +--- + +We'll be writing this bot in Typescript. Client libraries and examples for other languages will be available soon. + +## Starting a new bot project + +First, some boilerplate project setup. Run these commands to set up a new typescript project. + +```bash +mkdir simple-limit-order-bot && cd simple-limit-order-bot +yarn init +# install typescript & eslint dev dependencies +yarn add -D @types/node @typescript-eslint/eslint-plugin @typescript-eslint/parser dotenv eslint eslint-plugin-tsdoc ts-node typescript +# install ethers & mev-share client +yarn add ethers @flashbots/mev-share-client +``` + +Now in your editor, make a `src` directory and add a new file called `index.ts` + +Then, import the required dependencies. + +`src/index.ts` + +```tsx +import MevShareClient, {IPendingTransaction} from '@flashbots/mev-share-client' +import { Contract, JsonRpcProvider, Wallet } from 'ethers' +``` + +We'll use the mev-share-client library to listen for new pending transactions, and we'll use ethers to create and sign our own transactions, and query the blockchain. + +Lastly, we'll create a file called `.env` in the project root directory to store our private variables, such as private keys and RPC endpoints. + +`.env` + +``` +RPC_URL= +EXECUTOR_KEY= +FB_REPUTATION_KEY= +``` + +Fill this in with your own values. + +- `RPC_URL` is the Ethereum RPC endpoint we'll use to query smart contract values and account balances. [Alchemy](https://www.alchemy.com/), [Quicknode](https://www.quicknode.com/), and [Infura](https://www.infura.io/) are popular options for free RPC endpoints. +- `EXECUTOR_KEY` is the private key that will send transactions; it should have at least 0.05 ETH in it to pay for our trade (or more, if you want to make a larger trade than our example). +- `FB_REPUTATION_KEY` is the private key used to sign the payload sent to Flashbots, and is used for tracking searcher reputation. If you earn a high reputation, you may be placed in a high-priority queue, which is prioritized during periods of high traffic. This account *should not* have any ETH in it. + +Your project should now look like this: + +![Project setup](/img/limit-order-project-setup.png) + +:::info *Use [cast](https://github.com/foundry-rs/foundry#readme) to generate private keys for cool addresses like this:* + +```bash +cast wallet vanity --starts-with babe +``` + +``` +Starting to generate vanity address... +Successfully found vanity address in 0 seconds. +Address: 0xbabe32A9112Dc37a0A9274c86CAD0D1676fEA55a +Private Key: 😉 +``` + +::: info + +Next we'll read in the variables from our .env file with `dotenv`. + +Add the following code to your project: + +`src/index.ts` + +```tsx +import dotenv from "dotenv" +dotenv.config() + +const RPC_URL = process.env.RPC_URL || 'http://127.0.0.1:8545/' +const EXECUTOR_KEY = process.env.EXECUTOR_KEY || Wallet.createRandom().privateKey +const FB_REPUTATION_PRIVATE_KEY = process.env.FB_REPUTATION_KEY || Wallet.createRandom().privateKey +``` + +> Notice we set default values with the **||** operator. You can omit these if you prefer the variables to remain undefined when they're not set in the .env file. +> + +## Connecting to smart contracts to get prices and make trades + +To get the price of our trading pair and make trades, we'll need to interact with a few smart contracts: the Uniswap V2 Router, the ERC20 token contracts, and the factory contract. + +- **Uniswap V2 Router contract**: smart contract to trade tokens on Uniswap V2. We also use it to get the market price of the trading pair, by simulating a small trade. +- **factory contract**: this is where Uniswap trading pairs are created. We use it to find the pair address for the tokens we want to trade (e.g. WETH/DAI). +- **ERC20 token contract**: the tokens themselves; in our example, we use the WETH contract to call `approve`, so that the router can transfer our WETH tokens for us. + +To do this in our code, we'll create contract instances using ethers. We instantiate contracts with the ABI and contract address of each contract we want to use. The ABI specifies the functions that can be called on the contract. + +For convenience, we've gathered the ABIs required to create ethers contracts for Uniswap V2. Copy these into a new file `src/abi.ts`. + +`src/abi.ts` + +```tsx +export const UNISWAP_V2_ABI = [{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] +export const UNISWAP_FACTORY_ABI = [{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"name":"setFeeToSetter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}] +export const ERC20_ABI = [{ "constant": true, "inputs": [], "name": "name", "outputs": [{ "name": "", "type": "string" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [{ "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }], "name": "approve", "outputs": [{ "name": "", "type": "bool" }], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "totalSupply", "outputs": [{ "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [{ "name": "_from", "type": "address" }, { "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }], "name": "transferFrom", "outputs": [{ "name": "", "type": "bool" }], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "decimals", "outputs": [{ "name": "", "type": "uint8" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [{ "name": "_owner", "type": "address" }], "name": "balanceOf", "outputs": [{ "name": "balance", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "symbol", "outputs": [{ "name": "", "type": "string" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [{ "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }], "name": "transfer", "outputs": [{ "name": "", "type": "bool" }], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [{ "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" }], "name": "allowance", "outputs": [{ "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "payable": true, "stateMutability": "payable", "type": "fallback" }, { "anonymous": false, "inputs": [{ "indexed": true, "name": "owner", "type": "address" }, { "indexed": true, "name": "spender", "type": "address" }, { "indexed": false, "name": "value", "type": "uint256" }], "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "name": "from", "type": "address" }, { "indexed": true, "name": "to", "type": "address" }, { "indexed": false, "name": "value", "type": "uint256" }], "name": "Transfer", "type": "event" }] +``` + +We need to add this import in `src/index.ts`, and then write just a little more boilerplate code. It should look like this all together: + +```tsx +import MevShareClient, {IPendingTransaction} from '@flashbots/mev-share-client' +import { Contract, JsonRpcProvider, Wallet } from 'ethers' +import { UNISWAP_V2_ABI, UNISWAP_FACTORY_ABI, ERC20_ABI } from './abi' // <-- new import +import dotenv from "dotenv" +dotenv.config() + +const RPC_URL = process.env.RPC_URL || 'http://127.0.0.1:8545/' +const EXECUTOR_KEY = process.env.EXECUTOR_KEY || Wallet.createRandom().privateKey +const FB_REPUTATION_PRIVATE_KEY = process.env.FB_REPUTATION_KEY || Wallet.createRandom().privateKey + +// create web3 provider & wallets, connect to mev-share +const provider = new JsonRpcProvider(RPC_URL) +const executorWallet = new Wallet(EXECUTOR_KEY, provider) +const authSigner = new Wallet(FB_REPUTATION_PRIVATE_KEY, provider) +const mevshare = MevShareClient.useEthereumGoerli(authSigner) +// if you want to connect to mainnet instead: +// const mevshare = MevShareClient.useEthereumMainnet(authSigner) + +// create contract instances +const UNISWAP_V2_ADDRESS = '0x7a250d5630b4cf539739df2c5dacb4c659f2488d' +const UNISWAP_FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f' +const uniswapRouterContract = new Contract(UNISWAP_V2_ADDRESS, UNISWAP_V2_ABI, executorWallet) +const uniswapFactoryContract = new Contract(UNISWAP_FACTORY_ADDRESS, UNISWAP_FACTORY_ABI, provider) + +/* While we're here, let's also set some useful constants we'll use later */ +// discount we expect from the backrun trade (basis points): +const DISCOUNT_IN_BPS = 40n +// try sending a backrun bundle for this many blocks: +const BLOCKS_TO_TRY = 24 +// WETH: +const SELL_TOKEN_ADDRESS = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' +const SELL_TOKEN_AMOUNT = 100000000n +// DAI: +const BUY_TOKEN_ADDRESS = '0x6b175474e89094c44da98b954eedeac495271d0f' +const BUY_TOKEN_AMOUNT_CUTOFF = SELL_TOKEN_AMOUNT * 1800n + +const TX_GAS_LIMIT = 400000 +const MAX_GAS_PRICE = 20n +const MAX_PRIORITY_FEE = 5n +const GWEI = 10n ** 9n +``` + +`uniswapRouterContract`is the contract we use to execute trades. + +`uniswapFactoryContract` is used to find the contract address of the token pair we trade on (e.g. [WETH/DAI](https://etherscan.io/address/0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11)). + +`SELL_TOKEN_ADDRESS` is the token we want to sell (in this case, WETH). The token we're buying in this example is [DAI](https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f). Choose whichever tokens you want to trade if you're following along — you can check to see if your tokens have a pair by calling the `getPair` function with your token addresses on the Uniswap [factory contract](https://etherscan.io/address/0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f#readContract). + +`SELL_TOKEN_AMOUNT` specifies 0.1 gwei of WETH to spend, and in `BUY_TOKEN_AMOUNT_CUTOFF` we specify that we want to buy when the token price is **1800** DAI/WETH. + +*We set our gas fees (see `MAX_GAS_PRICE` and `MAX_PRIORITY_FEE`) to constant values for the example. If you don't mind possibly paying more gas, we recommend setting your gas parameters so that they follow the base fee. Ethers has a function for this called [getFeeData](https://docs.ethers.org/v5/single-page/#/v5/api/providers/provider/-%23-Provider-getFeeData).* \ No newline at end of file diff --git a/docs/flashbots-mev-share/searchers/tutorials/limit-order/using-events.mdx b/docs/flashbots-mev-share/searchers/tutorials/limit-order/using-events.mdx new file mode 100644 index 00000000..a8454e32 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/tutorials/limit-order/using-events.mdx @@ -0,0 +1,186 @@ +--- +title: Using Events +--- + +## Finding pending transactions with MEV-Share Event Stream + +Now that we have all the setup done, we need to find some transactions to backrun. Remember, we're looking for transactions that affect the price of our trading pair (WETH/DAI), so that we can take advantage of the price impact created by the transaction to get a better price for our trade. By placing the two transactions in a bundle (the transaction we found on the event stream, and our backrun trade), we ensure that our trade only executes if it gets placed immediately behind the transaction that causes the price impact that benefits us. + +We'll start by listening to the MEV-Share event stream. The event stream shares data about pending transactions (and bundles). We can use this information to deduce whether a transaction affects the price of our trading pair. + +In our project, we add a main function at the bottom, and in it, use the mev-share client's `.on` function to execute our own code when we receive new pending transaction events. To start, let's just look at the event stream by printing each event to the console. + +`src/index.ts` + +```tsx +// ... previous code still up here ^ + +async function main() { + console.log("mev-share auth address: " + authSigner.address) + console.log("executor address: " + executorWallet.address) + + // bot only executes one trade, so get the nonce now + const nonce = await executorWallet.getNonce("latest") + + mevshare.on('transaction', async ( pendingTx: IPendingTransaction ) => { + // callback to handle pending transaction + console.log(pendingTx) + }) +} +main() +``` + +Try running this: + +```bash +npx ts-node src/index.ts +``` + +You should see events popping up in the console. Something like this: + +```tsx +PendingTransaction { + hash: '0x26aba6f3c5083d58915161efb0cd0f713418cdd7a95425cdde451efd1dfb5dff', + logs: [ + { + address: '0x8255ffbb54bbb825cc544b67ccf36526e6101f5e', + topics: [Array], + data: 'Ox' + }, + { + address: '0x8255ffbb54bbb825cc544b67ccf36526e6101f5e' + topics: [Array], + data: 'Ox' + } + ], + to: null, + functionSelector: null, + callData: null, + gasUsed: undefined, + mevGasPrice: undefined +} +PendingTransaction { + hash: '0xeb0d75030e0c7253b60a17a58eb2a2e66a6e3ca58343cadece70a528dfd378a1', + logs: [ + { + address: 'Oxdac17f958d2ee523a2206206994597c13d831ec7', + topics: [Array], + data: '0x0000000000000000000000000000000000000000000000000000000253f52170' + }, + { + address: 'Oxdac17f958d2ee523a2206206994597c13d831ec7', + topics: [Array], + data: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + }, + { + address: 'Oxdac17f958d2ee523a2206206994597c13d831ec7', + topics: [Array], + data: '0x0000000000000000000000000000000000000000000000000000000253f52170' + }, + { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + topics: [Array], + data: '0x00000000000000000000000000000000000000000000021e08ad287c5f8d3bff' + } + ] +} +``` + +> Traffic is often low on goerli, so you may want to try connecting to mainnet with `MevShareClient.useEthereumMainnet(authSigner)` to see more events. + +The logs filling up your console are all transactions which we can backrun. You'll notice that some share more data than others. We'll cover how to include these transactions in our bundles soon, but first we need to go a little deeper to understand these events, and how we might use them to our advantage. + +## Finding backrun opportunities using event data + +Transactions on MEV-Share can share a wide variety of data with searchers. They can choose to only share their transaction hash to maintain the most privacy, or they can share logs, calldata, the function selector, and/or the `to` address of their transaction. Sharing more data gives searchers more options for running MEV strategies with those transactions, and so improves the chances of those transactions landing on chain quickly. + +:::info For the Adventurous + +💡 Bundles can also be shared on MEV-Share. If you query the raw stream (you can view it in your web browser here: https://mev-share.flashbots.net), you'll see that each event actually has a `txs` property, which itself may contains transaction events. In the client library, we convert the events into transaction or bundle types for you. To listen for bundles with the client lib, call the function `.on("bundle", ...)`. We'll talk more about this in a later guide. + +:::info + +In our project, we want to know whether a transaction interacts with the token pair that we want to trade on (in our case, WETH/DAI). We want to know this because these transactions might move the price towards our target price. + +To find out which trading pair a transaction is interacting with, we need to look at one of two fields: `to` and `logs`, depending on which is shared by the sender of the transaction. + +The `to` address is the actual recipient of the transaction. Typically, this would be a router contract like the [Uniswap Universal Router](https://etherscan.io/address/0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD), which allows users of the Uniswap web app to split trades between multiple Uniswap liquidity pools. However, we're not interested in any Uniswap routers. We're looking for the token pair contract (e.g. [WETH/DAI](https://etherscan.io/address/0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11)). If the `to` field is the pair address, the transaction sender is trading directly on the pair, which may mean that the transaction is from another searcher, as web UI users would most likely be interacting with the router contract. Nevertheless, if someone is trading on the token pair, we want to try to backrun it. + +If the `logs` field is specified, we look for the pair address in the `address` field of one of the logs. MEV-Share, by default, shares the pair address in logs for swaps on Uniswap V2/V3 (V4 coming soon), Curve and Balancer. We'll look more in depth at decoding logs in a later guide, but for now it's sufficient to simply look for the pair address — if a log contains this address, then we can be confident that the transaction in the event is a good candidate to backrun. + +Add the following code in your project: + +`src/index.ts` + +```tsx +// preceding code omitted for brevity + +function transactionIsRelatedToPair(pendingTx: IPendingTransaction, PAIR_ADDRESS: string) { + return pendingTx.to === PAIR_ADDRESS || + ((pendingTx.logs || []).some(log => log.address === PAIR_ADDRESS)) +} +``` + +Additionally, we'll need to approve the router to spend our WETH. Add this function: + +```tsx +async function approveTokenToRouter( tokenAddress: string, routerAddress: string ) { + const tokenContract = new Contract(tokenAddress, ERC20_ABI, executorWallet) + const allowance = await tokenContract.allowance(executorWallet.address, routerAddress) + const balance = await tokenContract.balanceOf(executorWallet.address) + if (balance == 0n) { + console.error("No token balance for " + tokenAddress) + process.exit(1) + } + if (allowance >= balance) { + console.log("Token already approved") + return + } + await tokenContract.approve(routerAddress, 2n**256n - 1n) +} +``` + +Then at the start of your `main` function, find the smart contract address for the token pair we want to trade, and call our function to approve the router to trade our WETH: + +```tsx +const PAIR_ADDRESS = (await uniswapFactoryContract.getPair( + SELL_TOKEN_ADDRESS, + BUY_TOKEN_ADDRESS + )).toLowerCase() +await approveTokenToRouter(SELL_TOKEN_ADDRESS, UNISWAP_V2_ADDRESS) +``` + +Then, where we handle new pending transactions, call `transactionIsRelatedToPair` to see if we should backrun the transaction. + +Your main function should similar to this when you're done: + +```tsx +async function main() { + console.log('mev-share auth address: ' + authSigner.address) + console.log('executor address: ' + executorWallet.address) + const PAIR_ADDRESS = (await uniswapFactoryContract.getPair(SELL_TOKEN_ADDRESS, BUY_TOKEN_ADDRESS)).toLowerCase() + await approveTokenToRouter(SELL_TOKEN_ADDRESS, UNISWAP_V2_ADDRESS) + const nonce = await executorWallet.getNonce('latest') + + mevshare.on('transaction', async ( pendingTx: IPendingTransaction ) => { + if (!transactionIsRelatedToPair(pendingTx, PAIR_ADDRESS)) { + console.log('skipping tx: ' + pendingTx.hash) + return + } + console.log(`It's a match: ${ pendingTx.hash }`) + }) +} +``` + +If you run the code now, you'll probably see a lot of skipped transactions, but eventually you'll find a match! If you're not seeing any activity, try switching to mainnet: + +```tsx +// const mevshare = MevShareClient.useEthereumGoerli(authSigner) +// if you want to connect to mainnet instead: +const mevshare = MevShareClient.useEthereumMainnet(authSigner) +``` + +:::info For the Adventurous +Try logging `pendingTx` in its entirety; look at all the fields. Or in code, check out the [interface](https://github.com/flashbots/matchmaker-ts/blob/main/src/api/interfaces.ts#L258) directly. See if you can find any patterns in the `logs` parameter. + +:::info diff --git a/docs/flashbots-mev-share/searchers/understanding-bundles.mdx b/docs/flashbots-mev-share/searchers/understanding-bundles.mdx new file mode 100644 index 00000000..74469ab8 --- /dev/null +++ b/docs/flashbots-mev-share/searchers/understanding-bundles.mdx @@ -0,0 +1,86 @@ +--- +title: Understanding Bundles +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' +import SendBundleRpc from '@site/docs/specs/mev-share/_mev_sendBundle.mdx' +import BuilderInheritance from '@site/docs/specs/mev-share/blurbs/_builderInheritance.mdx' +import Hints from '@site/docs/specs/mev-share/HintsTable' + +Bundles on MEV-Share are conceptually the same as bundles on MEV-Boost: they are an ordered array of transactions that execute atomically. However, their structure is a bit different. MEV-Share bundles use a new method called [`mev_sendBundle`](https://github.com/flashbots/mev-share/blob/main/specs/bundles/v0.1.md) which has additional fields used to specify privacy preferences and introduce other new features like post-execution validity checks. + +## Bundle Definition + +MEV-Share Bundles have the following structure: + + + +Key Fields: +* **inclusion**: Defines the pre-inclusion predicates to check (e.g. block range). +* **body**: Contains transactions, bundle hashes, or transaction hashes. +* **validity**: (Optional) Defines the post-inclusion predicates to check, which are just refund parameters at the moment. +* **privacy**: (Optional) Sets privacy configurations, including which builders to submit to. NOTE: the Flashbots builder is submitted to by default even if only other builders are specified. +Optional properties are denoted with a ?. + +:::info Note to searchers on builders + + + +::: + +This is the generic bundle structure used in MEV-Share. This comprehensive specification enables several exciting features, outlined in the next section. + +## Sharing hints +MEV-Share bundles can share hints with searchers, which can be used to backrun the bundle. This is done by setting the `privacy` parameter in `mev_sendBundle`. The `privacy` parameter is an object with the following fields: + + +Searchers can share hints to give other searchers information about their bundle that would allow them to be backrun. If your bundle gets backrun by another searcher, you get paid a cut of the MEV they extract! + +## Builders +MEV-Share bundles can be sent to multiple builders at once. This is done by setting the `builders` field in the `privacy` parameter of `mev_sendBundle`. + +## Bundle composition (backrunning other bundles) +With the `privacy` parameter in `mev_sendBundle` you can share select information about your bundle with other searchers, who can then use that to try to extract MEV. Should they succeed, you get paid some of the MEV they extracted! + +One example that works well with bundle composition is a liquidation bot. Liquidations often cause a price shift, leaving MEV on the table which can be captured by arbitrage with a backrun bundle. If you run a liquidation bot, you can earn more MEV by sending your bundles to MEV-Share with the `tx_hash` hint enabled, which will allow other searchers to backrun your bundle. + +An example would look something like this: + + + + +```typescript +const params: BundleParams = { + inclusion: { + block: 17539448, + maxBlock: 17539458 + }, + body: [ + {tx: "0x02...", canRevert: false}, + {tx: "0x02...", canRevert: false}, + ], + privacy: { + hints: { + txHash: true, + }, + }, +} +``` + + + + +Specifying the `tx_hash` hint in your bundle shares the hashes of your bundle's transactions with searchers on MEV-Share, which is what allows them to backrun your bundle. Again, when they do this, you earn a cut of the profit! + +You may also try experimenting with other hints to give searchers more data with which to formulate a backrun. Sharing more data will lower your privacy, but will make your bundle easier to backrun, and increase the likelihood of your bundles earning extra MEV. + +:::caution only original transactions are supported + +Bundles that set the `privacy` parameter can only contain original signed transactions in the `body` parameter. Bundles using transactions specified by `{hash}` are not allowed to use the privacy parameter (full bundle privacy is maintained in this case). Allowing such bundles to share data using the `privacy` parameter would compromise the privacy guarantees of user transactions. + +::: + +See [Sending Bundles](/flashbots-mev-share/searchers/sending-bundles#share-bundle-data) for more information. +-- +Now that we know all the different ways in which we can send and share bundles, we're finally ready to [send a bundle](/flashbots-mev-share/searchers/sending-bundles). diff --git a/docs/flashbots-protect/rpc/bundle-cache.md b/docs/flashbots-protect/additional-documentation/bundle-cache.md similarity index 58% rename from docs/flashbots-protect/rpc/bundle-cache.md rename to docs/flashbots-protect/additional-documentation/bundle-cache.md index 9a4d02d9..c1bd5c1a 100644 --- a/docs/flashbots-protect/rpc/bundle-cache.md +++ b/docs/flashbots-protect/additional-documentation/bundle-cache.md @@ -1,5 +1,5 @@ --- -title: bundle cache API +title: Bundle Cache API --- To create a bundle iteratively (e.g. by signing & sending transactions one at a time with Metamask), you can use the bundle cache API to cache signed transactions and retrieve them with a bundle ID. @@ -8,13 +8,13 @@ This will be used for whitehat recoveries. By enabling users to sign transaction ## Create a Bundle ID -To start addding transactions to a bundle, first create a bundle ID. We recommend using a UUID (v4). You can generate a UUID at [uuidgenerator.net](https://www.uuidgenerator.net/version4) or with any uuid library. +To start adding transactions to a bundle, first create a bundle ID. We recommend using a UUID (v4). You can generate a UUID at [uuidgenerator.net](https://www.uuidgenerator.net/version4) or with any UUID library. ## Connect to Flashbots Protect with Bundle ID Connecting to the Flashbots Protect RPC Endpoint with a bundle ID parameter will automatically add incoming transactions to a queue without sending them. -```txt +```url https://rpc.flashbots.net?bundle= ``` @@ -22,13 +22,13 @@ 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 +```bash curl https://rpc.flashbots.net/bundle?id= ``` @@ -36,11 +36,8 @@ This will return a JSON object with your signed transactions: ```json { - "bundleId":"cbd900bf-44c5-4f6b-bf14-9b8d2ae27510", - "rawTxs": [ - "0x02f879827a6901849502...", - "0x02f875827a6960849502..." - ] + "bundleId": "cbd900bf-44c5-4f6b-bf14-9b8d2ae27510", + "rawTxs": ["0x02f879827a6901849502...", "0x02f875827a6960849502..."] } ``` @@ -48,13 +45,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. +If you want to send a bundle directly, check out the [Flashbots Builder Docs](/flashbots-auction/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/additional-documentation/eth-sendPrivateTransaction.mdx b/docs/flashbots-protect/additional-documentation/eth-sendPrivateTransaction.mdx new file mode 100644 index 00000000..b238c4a7 --- /dev/null +++ b/docs/flashbots-protect/additional-documentation/eth-sendPrivateTransaction.mdx @@ -0,0 +1,308 @@ +--- +title: eth_sendPrivateTransaction +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import Hints from "../../specs/mev-share/HintsTable"; +import Builders from "../../specs/mev-share/_builders.mdx"; + +## Introduction + +The `eth_sendPrivateTransaction` method allows for the sending of individual private transactions. This provides users with the ability to customize their transactions beyond the default configurations. + +## Implementation + +Below are some details about the implementation of `eth_sendPrivateTransaction`: + +- Endpoint: Send your eth_sendPrivateTransaction requests to https://relay.flashbots.net. +- Header: Use the X-Flashbots-Signature header. +- Cancellation: Private transactions can be halted using eth_cancelPrivateTransaction. + +You can access this method using the following libraries: + +- For JavaScript, use [ethers-provider-flashbots-bundle.js](/flashbots-auction/libraries/ethers-js-provider). +- For Python, use [web3-flashbots.py](/flashbots-auction/libraries/web3py-provider). +- Additionally, [`eth_sendPrivateTransaction`](https://docs.alchemy.com/reference/eth-sendprivatetransaction?a=fb) is freely supported on [Alchemy](https://alchemy.com?a=fb). + +## Priority fee + +When sending transaction using `eth_sendPrivateTransaction` or `eth_sendPrivateRawTransaction` methods you should set +priority fee (tips) to be strictly greater than zero. Transactions with 0 priority fee will not be shared with block +builders and included on chain, unless they are bundled by a searcher via MEV-Share. + +## Examples + +The following code examples show how to use eth_sendPrivateTransaction using the Flashbots ethers and web3.py libraries. + + + + + +```ts +const signer = Wallet.createRandom(); +const provider = new providers.JsonRpcProvider("http://localhost:8545/"); +const flashbotsProvider = await FlashbotsBundleProvider.create( + provider, + signer, +); + +const transaction = { + from: signer.address, + to: signer.address, + value: "0x42", + gasPrice: BigNumber.from(99).mul(1e9), + gasLimit: BigNumber.from(21000), +}; + +const res = await flashbotsProvider.sendPrivateTransaction( + { + transaction, + signer, + }, + { + 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 included on-chain."); +} else if (waitRes === FlashbotsTransactionResolution.TransactionDropped) { + 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, +}) +``` + + + + +## JSON-RPC + +Detailed JSON-RPC structure for the method are below: + +```typescript +{ + jsonrpc: "2.0", + id: string | number, + method: "eth_sendPrivateTransaction", + 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, // Sends transactions to all registered block builders, sets MEV-Share revenue share to 50% + privacy?: { // MEV-Share options; optional + hints?: Array< // data about tx to share w/ searchers on mev-share + "contract_address" | + "function_selector" | + "calldata" | + "logs" | + "hash" + >, + builders?: Array< // MEV-Share builders to exclusively receive bundles; optional + "default" | + "flashbots" + >, + }, + validity?: { + refund?: Array<{address, percent}> + } + } + }] +} +``` + +example request: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendPrivateTransaction", + "params": [ + { + "tx": "0x123abc...", + "maxBlockNumber": "0xcd23a0", + "preferences": { + "fast": true, + "privacy": { + "hints": ["calldata", "transaction_hash"], + "builders": ["default"] + }, + "validity": { + "refund": [{ "address": "0xadd123", "percent": 50 }] + } + } + } + ] +} +``` + +example response: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": "0x45df1bc3de765927b053ec029fc9d15d6321945b23cac0614eb0b5e61f3a2f2a" // tx hash +} +``` + +#### Privacy options + +By default, transactions are sent to the Flashbots MEV-Share Node with the default [Stable](/flashbots-protect/mev-refunds#stable-configuration) configuration. The `privacy` parameter allows you to customize privacy settings: + +| Parameter | Type | Description | +| ---------- | ------------ | -------------------------------------------------------------------- | +| `hint` | String array | Indicates the type of data from the transaction shared on mev-share. | +| `builders` | String array | Builders that are sent the transaction. | + +**`hint`** + + + +**`builders`** + +Flashbots currently supports sending orderflow to the following block builders. This is subject to change over time. + + + +#### `validity` + +Validity is used to specify the address and percentage to pay any refund from the backrun of a `eth_sendPrivateTranasction` transaction. + +By default, the refund is paid to the signer of the transaction and 90% of the backrun value is sent to the signer's address. + +If multiple refund addresses are specified, then the backrun value is split between them according to the percentage specified. +For example, if refund is `[{address: addr1, percent: 10}, {address: addr1, percent: 20}]` then 10% of the backrun value is sent to `addr1` and 20% is sent to `addr2` +and 70% of the backrun value is left to the builder. + +| Parameter | Type | Description | +| ------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------- | +| `refund` | Array of objects | Each entry in the array specifies address that should receive refund from backrun and percent of the backrun value. | +| `refund[].address` | Address | Address that should receive refund. | +| `refund[].percent` | Number | Percentage of the total backrun value that this address should receive. | + +## Additional methods + +### eth_sendPrivateRawTransaction + +`eth_sendPrivateRawTransaction` behaves like [eth_sendPrivateTransaction](#) but its format +is similar to that of [`eth_sendRawTransaction`](https://docs.alchemy.com/reference/eth-sendrawtransaction) + +This method has the following JSON-RPC format: + +```typescript +{ + jsonrpc: "2.0", + id: string | number, + method: "eth_sendPrivateRawTransaction", + params: [ + tx, // String, raw signed transaction + preferences? // Optional, see eth_sendPrivateTransaction + ] +} +``` + +example request: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_sendPrivateRawTransaction", + "params": ["0x123abc..."] +} +``` + +example response: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": "0x45df1bc3de765927b053ec029fc9d15d6321945b23cac0614eb0b5e61f3a2f2a" // tx hash +} +``` + +| Parameter | Type | Description | +| ----------- | ------ | --------------------------------------------------------------------------------- | +| `params[0]` | String | Raw signed transaction | +| `params[1]` | Object | Optional private tx preferences, see `preferences` in eth_sendPrivateTransaction. | + +### eth_cancelPrivateTransaction + +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 +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_cancelPrivateTransaction", + "params": [{ + txHash, // String, transaction hash of private tx to be cancelled + }] +} +``` + +example request: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "eth_cancelPrivateTransaction", + "params": [ + { + "txHash": "0x45df1bc3de765927b053ec029fc9d15d6321945b23cac0614eb0b5e61f3a2f2a" + } + ] +} +``` + +example response: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": true // true if tx successfully cancelled, false if not +} +``` diff --git a/docs/flashbots-protect/additional-documentation/status-api.md b/docs/flashbots-protect/additional-documentation/status-api.md new file mode 100644 index 00000000..fff1195a --- /dev/null +++ b/docs/flashbots-protect/additional-documentation/status-api.md @@ -0,0 +1,90 @@ +--- +title: Transaction Status API +--- + +Transactions that you submit to Flashbots Protect won't be observable in the public mempool. However, you can use our status API to check the status of your transactions. The URL for doing so is: `https://protect.flashbots.net/tx/YOUR_TX_HASH_HERE`, and you can also use Etherscan as you normally would for transactions. They will show the status of your transaction from the status API as well. + +The Transaction Status API is also available on test networks. Below is a table of URLs for accessing the API across different networks: + +| Network | URL | +| -------- | -------------------------------------------------- | +| Mainnet | `https://protect.flashbots.net/tx/` | +| Sepolia | `https://protect-sepolia.flashbots.net/tx/` | + + + +In turn you will receive a JSON response that looks like the following: + +```json +{ + "status": "PENDING", + "hash": "YOUR_TX_HASH", + "maxBlockNumber": 13543898, + "transaction": { + "from": "", + "to": "", + "gasLimit": "", + "maxFeePerGas": "", + "maxPriorityFeePerGas": "", + "nonce": "", + "value": "" + }, + "fastMode": true, // for backwards compatibility; may be removed in a future version + "seenInMempool": false, + "simError": "", + "revertReason": "", + "isRevert": false +} +``` + +Below is a table of status codes that can be returned: + +| Status Code | Description | +| ----------- | ---------------------------------------------------------------------------------- | +| `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 + +The `transaction` fields are disclosed only for transactions with an `INCLUDED` status to maintain privacy for trades that are pending, failed, or cancelled. These fields will remain empty for transactions with `PENDING`, `FAILED`, `UNKNOWN`, or `CANCELLED` statuses. Protect fast mode transactions are an exception to this rule as TEE searchers will receive all fields (without signature) for all transactions, including reverted or failed transactions, with a 5 minute delay for troubleshooting and debugging purposes. + +For instance, once a transaction is included, the JSON response will be populated with data for all fields: + +```json +{ + "status": "INCLUDED", + "hash": "YOUR_TX_HASH", + "maxBlockNumber": 13543898, + "transaction": { + "from": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", + "to": "0xac03bb73b6a9e108530aff4df5077c2b3d481e5a", + "gasLimit": "21000", + "maxFeePerGas": "300", + "maxPriorityFeePerGas": "10", + "nonce": "41", + "value": "10000000000" + }, + "fastMode": true, // for backwards compatibility; may be removed in a future version + "seenInMempool": false, + "isRevert": false +} +``` + +While your transaction is `PENDING` or `FAILED` we will try to respond with the latest seen simulation error and revert reason if exists. + +Below is the table of currently supported `simError` values. + +| Sim error | Description | +|------------------------------|---------------------------------------------------------------------------------------------| +| `SimErrorMaxFeePerGasTooLow` | Consensus incompatible tx that wasn't caught on rpc | +| `SimErrorInsufficientFunds` | Insufficient ETH balance to pay for gas | +| `SimErrorNonceTooLow` | Nonce too low | +| `SimErrorNonceTooHigh` | Nonce too high | +| `SimErrorInvalidChainId` | Consensus incompatible tx that wasn't caught on rpc | +| `SimErrorExecutionReverted` | Execution reverted (slippage tolerance exceeded). Check revertReason field for more details | +| `SimErrorOutOfGas` | Ran out of gas during execution (gas limit too low) | + +`revertReason` field is a valid utf-8 part of the simulation result. Example: `TRANSFER_FROM_FAILED`, `UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT` diff --git a/docs/flashbots-protect/cancellations.md b/docs/flashbots-protect/cancellations.md new file mode 100644 index 00000000..d62ad707 --- /dev/null +++ b/docs/flashbots-protect/cancellations.md @@ -0,0 +1,16 @@ +--- +title: Cancellations +--- + +Transactions submitted to Flashbots Protect are directed to the Flashbots MEV-Share Node. Here, they may remain in a pending state for a duration of up to 6 minutes. + +Flashbots Protect provides the functionality to cancel pending transactions. To do so, a cancellation transaction must be submitted to Flashbots Protect. This cancellation transaction should adhere to the following criteria: + +- It must be submitted from the **same address** as the original transaction that is intended to be cancelled. +- It should have the **same nonce** as the original transaction. +- The **from and to addresses** should both be set to the **from address** of the original transaction. +- The **data field** of the cancellation transaction should be left empty. + +## No cost to cancel + +The cancellation transaction serves solely for authentication purposes, verifying that you have control over the account that initiated the transaction you wish to cancel. Since this transaction is not included on-chain, it incurs no cost. diff --git a/docs/flashbots-protect/gas-fee-refunds.md b/docs/flashbots-protect/gas-fee-refunds.md new file mode 100644 index 00000000..bd943c5c --- /dev/null +++ b/docs/flashbots-protect/gas-fee-refunds.md @@ -0,0 +1,51 @@ +--- +title: Gas Fee Refunds +--- + +## Introduction + +Flashbots Protect users are automatically eligible to receive gas fee refunds, if a transaction can be landed onchain for a lower price. This applies to both the RPC and the private transaction API. + +Gas fee refunds do not change how transactions are executed and users do not need to make any changes to be eligible for them. Gas fee refunds are calculated separately, and applied in addition to, MEV refunds from [MEV-Share](/flashbots-protect/mev-refunds). + +## Where do refunds come from + +Users and orderflow providers (like wallets) often pay high priority fees to land transactions on chain. Many of these transactions could be executed just as quickly for a fraction of the gas cost. + +It can be difficult to estimate gas correctly when sending a transaction. Flashbots Protect sends all transactions to [BuilderNet](https://buildernet.org/), which calculates the optimal fee on your behalf and refunds transactions that overpay. + +Gas fee refunds include both priority fees (more common in user transactions) and coinbase transfers (less common). + +## Which transactions receive refunds + +Flashbots Protect provides refunds for transactions in blocks landed by BuilderNet. Whether a transaction receives a refund depends on a few factors that vary from block to block: +* How much network congestion and competition there was +* Whether BuilderNet made a profit and how much +* How much the specific transaction contributed to the value of the block +* If the transaction was sent directly to Flashbots Protect, or shared with other RPCs and block builders + +Note that transactions seen in the public mempool are excluded and do not receive refunds. + +## How to maximize both refunds and speed + +Transactions which are sent directly to the Flashbots RPC or API, and not multiplexed _by the user_ to other RPCs or block builders, are likely to receive higher refunds. This is because they increase the profit of BuilderNet which is used to provide refunds. + +BuilderNet does not land 100% of blocks. In order to improve inclusion speed, users can ask Flashbots to share their transactions with other block builders in cases where BuilderNet does not win a block. Flashbots will automatically share with all specified builders on the user's behalf. + +There are two ways to share with other builders: +* Use [fast mode](/flashbots-protect/quick-start#faster-transactions) to share with all registered builders +* Choose [specific builders](/flashbots-protect/settings-guide#builders) to share transactions with + +## Who receives refunds + +For the RPC: The refund recipient is the address specified in the first [refund parameter](/flashbots-protect/settings-guide#refunds) on an RPC request, if one is provided. Otherwise, refunds are sent to the transaction originator (`tx.origin`) by default. + +For the private transaction API: The refund recipient is the signer used on the `eth_sendPrivateTransaction` request. + +## How to track refunds + +Refunds are tracked from a start date of July 8, 2024. Refunds are sent to recipients in batches, the first batch originated from the Flashbots builder address `0xdf99A0839818B3f120EBAC9B73f82B617Dc6A555` while newer batches originate from [`refunds.buildernet.eth`](https://etherscan.io/address/0x62a29205f7ff00f4233d9779c210150787638e7f). The recipient can track the status of their refunds using the [`flashbots_getFeeRefundTotalsByRecipient`](/flashbots-auction/advanced/rpc-endpoint#flashbots_getfeerefundtotalsbyrecipient) RPC method. + +## Distributed refunds + +The on-chain transactions corresponding to distributed refunds can be viewed with this Dune query: [https://dune.com/queries/4398421](https://dune.com/queries/4398421) diff --git a/docs/flashbots-protect/large-transactions.md b/docs/flashbots-protect/large-transactions.md new file mode 100644 index 00000000..a1db1980 --- /dev/null +++ b/docs/flashbots-protect/large-transactions.md @@ -0,0 +1,7 @@ +--- +title: Large Transaction Allowlist +--- + +Some projects may need to post larger transactions (measured in bytes) than the transaction pool allows. Flashbots bundles are not subject to the transaction pool size constraints. However, at the RPC level only transactions to certain contracts are allowed to be over 128kb. + +The list of contracts supporting large transactions can be seen in the [RPC endpoint's allowlist](https://github.com/flashbots/rpc-endpoint/blob/main/server/whitelist.go#L21). To add your contract to this list please make a PR to the RPC endpoint appending your contract address to the allowlist and share a description of your use case in the body of the PR. diff --git a/docs/flashbots-protect/mev-refunds.mdx b/docs/flashbots-protect/mev-refunds.mdx new file mode 100644 index 00000000..1a910a0d --- /dev/null +++ b/docs/flashbots-protect/mev-refunds.mdx @@ -0,0 +1,50 @@ +--- +title: MEV Refunds +--- + +import ProtectButton from '@site/src/components/ProtectButton'; + +## Introduction + +Flashbots Protect users are automatically eligible to receive MEV refunds from [MEV-Share](/flashbots-mev-share/introduction). If your transaction (eg. a large DEX swap) generates MEV, MEV-Share can help you reclaim a significant portion of this value. The remainder is split with searchers and validators to facilitate transaction inclusion. + +By default, all Protect transactions use the [default](/flashbots-protect/settings-guide#default) privacy setting which is continuously optimized by Flashbots to balance efficient execution and protection against harmful MEV. Advanced users can customize their settings when configuring their RPC or by manually editing the query parameters their Protect RPC request. + + + +## Common privacy settings + +You can customize how much information is shared about your transactions in MEV-Share. Each piece of information is called a "hint". Sharing more hints can increase refunds, while sharing fewer hints can increase privacy. Below are some common hint choices for different levels of privacy. See the complete [settings page](/flashbots-protect/settings-guide) for a full list of all settings you can apply to your RPC request. + +### Default + +To use the default privacy settings, you don't need to specify any query parameters. + +```url +https://rpc.flashbots.net +``` + +Currently, this configuration shares the following information: + +- The `hash` of all transactions +- `default_logs` Partial logs (the pool id and the fact that a swap was made) for curve, balancer, and uniswapV2/V3/V4-style trades + +### Max Privacy + +To use Protect with full privacy, set _only_ the `hash` hint in your Protect RPC URL: + +```url +https://rpc.flashbots.net?hint=hash +``` + +This configuration ensures that all identifiable transaction data sent to the MEV-Share Node is concealed from searchers. However, it's important to note that this could make it more challenging for searchers to spot MEV opportunities, leading to a very likely decrease in your MEV refund. + +### Max Refund + +To use Protect with the maximum refund, set _all_ hints in your Protect RPC URL: + +```url +https://rpc.flashbots.net?hint=calldata&hint=contract_address&hint=function_selector&hint=logs +``` + +This configuration provides searchers with comprehensive details about your transaction, giving them a better chance to identify more MEV opportunities and return MEV refunds. diff --git a/docs/flashbots-protect/nonce-management.mdx b/docs/flashbots-protect/nonce-management.mdx new file mode 100644 index 00000000..f7face46 --- /dev/null +++ b/docs/flashbots-protect/nonce-management.mdx @@ -0,0 +1,85 @@ +--- +title: Nonce Management +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Normally, a wallet can call `eth_getTransactionCount` to get the next nonce to use for a transaction. +However, since transactions sent to Flashbots Protect are potentially sensitive, even exposing the incremented nonce can leak information about the user's activity. + +As such, transactions sent to Flashbots Protect are only included in the `eth_getTransactionCount` results when querying the `"pending"` nonce, and only if the request is signed by the user's private key. + +This is done by sending a JSON-RPC request to the Flashbots Protect RPC endpoint with the following parameters: + +```json +{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [ + "0xYOUR_ADDRESS", + "pending" + ], + "id": 1 +} +``` + +The request is then signed and the signature is included in the `X-Flashbots-Signature` header. Without such a signature, the returned nonce will only include transactions sent to the public mempool. + +### Authentication + +To authenticate your request, 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: :" --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_ADDRESS","pending"],"id":1}' https://rpc.flashbots.net +``` + +The private key of the address your want to query must be used to sign the payload. + +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: + + + + +```ts +import {Wallet, utils} from 'ethers'; + +const privateKey = '0x1234'; +const wallet = new Wallet(privateKey); +const body = + '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_ADDRESS","pending"],"id":1}'; +const signature = wallet.address + ':' + wallet.signMessage(utils.id(body)); +``` + + + + +```py +from web3 import Web3 +from eth_account import Account, messages + +body = '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_ADDRESS","pending"],"id":1}' +message = messages.encode_defunct(text=Web3.keccak(text=body).hex()) +signature = Account.from_key(private_key).address + ':' + Account.sign_message(message, private_key).signature.hex() +``` + + + + +```go +body := `{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_ADDRESS","pending"],"id":1}` +hashedBody := crypto.Keccak256Hash([]byte(body)).Hex() +sig, err := crypto.Sign(accounts.TextHash([]byte(hashedBody)), privKey) +signature := crypto.PubkeyToAddress(privKey.PublicKey).Hex() + ":" + hexutil.Encode(sig) +``` + + + + diff --git a/docs/flashbots-protect/overview.md b/docs/flashbots-protect/overview.md deleted file mode 100644 index 5c77bc5a..00000000 --- a/docs/flashbots-protect/overview.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: overview ---- - -Flashbots Protect makes it easy for everyday users and developers to use Flashbots for frontrunning protection. We abstract away the complexity of submitting bundles to the Flashbots Auction and make integrating as simple as adding a URL to your MetaMask. - -Flashbots Protect RPC is an RPC endpoint that users can add to their wallets which sends their transactions to Flashbots. Learn more [in our quick start guide](/flashbots-protect/rpc/quick-start). - -At a high level these are some of the major benefits of integrating Flashbots Protect: -- **Frontrunning protection:** transactions will not be seen by hungry sandwich bots in the public mempool. -- **No failed transactions:** transactions will only be mined if it doesn't include any reverts, so users don't pay for failed transactions. Note: transactions could be included in uncled blocks, 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. -- **Etherscan integration:** users can see the status of their transactions on Etherscan. - -We intend to release more features on top of Flashbots Protect in the future, offering even more powerful functionality. - -## Flashbots Protect with fast mode -If you want to have your transactions included as soon as possible, but without all the benefits above, then check out [fast mode](/flashbots-protect/rpc/fast-mode). - -## Community integrations -The mistX team has developed a web SDK for integrating Flashbots that compliments the RPC endpoint. If you are a dApp that wants to offer easy support for Flashbots from your website, we recommend using the [mistX SDK](https://mistx.stoplight.io/docs/mistx). diff --git a/docs/flashbots-protect/overview.mdx b/docs/flashbots-protect/overview.mdx new file mode 100644 index 00000000..a04126b9 --- /dev/null +++ b/docs/flashbots-protect/overview.mdx @@ -0,0 +1,32 @@ +--- +title: MEV Protection Overview +--- + + + MEV Protection - Block MEV With Flashbots Protect RPC + + + +import ProtectButton from '@site/src/components/ProtectButton'; + +Flashbots Protect is a cheaper and safer way to transact on Ethereum. It protects your transactions from frontrunning and gives you refunds on gas fees and MEV. + +Key benefits: +- **Frontrunning protection:** Transactions are sent to a private Flashbots mempool where they will be hidden from frontrunning and sandwich bots. +- **Refunds**: If your transaction creates MEV, you can earn an [MEV refund](/flashbots-protect/mev-refunds). If your transaction pays high priority fees, you can earn [gas fee refunds](/flashbots-protect/gas-fee-refunds). +- **No failed transactions:** Transactions are only included in the block if they do not revert. Users do not pay fees for failed transactions. +- **Configurable:** You can customize your privacy, speed, and refund settings. + +Use Flashbots Protect by clicking the button below or by sending `eth_sendRawTransaction` API requests to `rpc.flashbots.net/fast`. + + + +
+
+ +We want to thank MiningDAO, mistX, and Nethermind for significant code contributions, testing, and being early adopters of Flashbots Protect. + +**Privacy notice: Flashbots Protect RPC does not track** user information (i.e. IP, location, etc.). No user information is stored or logged. diff --git a/docs/flashbots-protect/quick-start.mdx b/docs/flashbots-protect/quick-start.mdx new file mode 100644 index 00000000..1f754922 --- /dev/null +++ b/docs/flashbots-protect/quick-start.mdx @@ -0,0 +1,82 @@ +--- +title: Quick Start +--- + +import ProtectButton from '@site/src/components/ProtectButton'; + +### Key Considerations + +Flashbots Protect has the following key benefits: + +- **Frontrunning protection:** Transactions are hidden from the public mempool away from front-running and sandwich bots. +- **Refunds**: If your transaction creates MEV, you can earn an [MEV refund](/flashbots-protect/mev-refunds). If your transaction pays high priority fees, you can earn [gas fee refunds](/flashbots-protect/gas-fee-refunds). +- **No failed transactions:** Transactions are only included in the block if they do not revert. Users do not pay fees for failed transactions. +- **Configurable:** You can customize your privacy, speed, and refund settings. + +### Faster Transactions + +Use Protect in fast mode to land your transactions faster on chain. Click the "fast" option when [configuring your Protect RPC](/flashbots-protect/quick-start#using-flashbots-protect) or manually set your RPC to `rpc.flashbots.net/fast`. + +Fast mode details: + +1. **Shared with all builders:** Transactions are multiplexed, or shared, with all [registered builders](https://github.com/flashbots/dowg/blob/main/builder-registrations.json) within one block after they are received. Multiplexing increases the probability that the transaction will be sent to the builder building the winning block. +2. **Larger validator payment:** With the default RPC, 10% of the MEV-Share refund is paid to validators. In fast mode, validators receive a higher percentage of the MEV-Share refund increasing the probability that the transaction will be included in the winning block. +3. **Shared with TEE searchers:** Full transaction information is also shared with searchers in TEEs (secure enviroments), leading to better MEV refunds while preserving frontrunning protection. + +**Note**: When you send your transaction to a builder, you trust them not to frontrun your transaction or disclose it to third-party MEV searchers. + +### Customer Support + +Wallets and applications can receive customer support for transactions tagged with their `originId`. To opt into customer support, update your RPC URL to `rpc.flashbots.net/fast?originId=[your-wallet-name]`. + +:::warning Do Not Switch RPCs Before Transaction Confirmation + +If you submit a transaction through Flashbots Protect via the MetaMask wallet, do not switch RPCs before transaction confirmation. MetaMask may resend the transaction to the public mempool exposing your transaction to potential MEV attacks if RPCs are switched before transaction confirmation. + +::: + +### 0 Priority Fees + +Flashbots Protect does not accept transactions with a priority fee of 0. They will be dropped and a standard error message will be returned. + +## Using Flashbots Protect + +There are three ways to use Flashbots Protect: + +1. Add the Flashbots Protect RPC to your wallet. +2. Send transactions to the RPC URL using [eth_sendRawTransaction](https://docs.alchemy.com/reference/eth-sendrawtransaction). +3. Send transactions to Flashbots using [eth_sendPrivateTransaction](/flashbots-protect/additional-documentation/eth-sendPrivateTransaction). + +The easiest way to use Flashbots Protect is to add the Flashbots Protect RPC to your wallet. Use the button below to create a custom Protect RPC or follow the manual instructions. **Note that you can configure the builders you send to and your MEV-Share hints as well**. + + + +## Adding Flashbots Protect RPC Manually + +You can also add Flashbots Protect RPC manually in MetaMask by following these steps: + +1. Expand the Network drop-down menu by clicking on your current network at the top of your MetaMask. By default you are connected to “Ethereum mainnet.” +2. Click “Add network” +3. Click “Add a network manually” and fill in the following information: + +- **Network Name:** Flashbots Protect +- **New RPC URL:** [https://rpc.flashbots.net/fast](https://rpc.flashbots.net/fast) or the URL provided above based on your configuration +- **Chain ID:** 1 +- **Currency Symbol:** ETH +- **Block Explorer URL:** [https://etherscan.io/](https://etherscan.io/) + +4. Click “Save.” +5. Click “Switch to Flashbots Protect” + +![mm_rpc](/img/mm_rpc.png) + +Below is the list of Flashbots Protect RPCs we currently support across Ethereum mainnet and testnets: + +| Network | URL | +| ------- | ------------------------------------ | +| Mainnet | `https://rpc.flashbots.net/fast` | +| Sepolia | `https://rpc-sepolia.flashbots.net/` | + +## Stuck transactions + +Please see our [stuck transactions guide](/flashbots-protect/stuck_transactions) for help with dealing with transactions that are "stuck" as pending. diff --git a/docs/flashbots-protect/ratelimiting.mdx b/docs/flashbots-protect/ratelimiting.mdx new file mode 100644 index 00000000..673facb9 --- /dev/null +++ b/docs/flashbots-protect/ratelimiting.mdx @@ -0,0 +1,28 @@ +--- +title: Rate Limits +--- + +In order to protect our services from abuse we have rate limits on the number of requests that can be made. Currently, the rate limits are set as follows. + +## `rpc.flashbots.net` - Flashbots Protect RPC + +| Method | Limit | +|--------------------------------------------|-------------------| +| `eth_sendRawTransaction` | None | +| `eth_call` | 200 / IP / 5 min | +| `eth_getTransactionReceipt` | 200 / IP / 5 min | +| `eth_getTransactionByBlockNumberAndIndex` | 200 / IP / 5 min | +| `eth_getBalance` | 200 / IP / 5 min | +| All others | 600 / IP / 5 min | + +Note that you are not required to read JSON RPC requests to send transactions to Flashbots Protect RPC. + +Relay rate limits for advanced user bundles sent to `relay.flashbots.net` [can be found here](../flashbots-mev-share/searchers/ratelimiting). + +## Rate limiting exceptions + +If you are a wallet or application integrating with protect and you require a higher rate limit please reach out to [Shea Ketsdever](https://twitter.com/SheaKetsdever). + +## Batch request support + +Flashbots Protect RPC is not supporting batch JSON-RPC requests. diff --git a/docs/flashbots-protect/rpc/cancellations.md b/docs/flashbots-protect/rpc/cancellations.md deleted file mode 100644 index c0744daa..00000000 --- a/docs/flashbots-protect/rpc/cancellations.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -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. - -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. - -## 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. diff --git a/docs/flashbots-protect/rpc/fast-mode.md b/docs/flashbots-protect/rpc/fast-mode.md deleted file mode 100644 index a8776f76..00000000 --- a/docs/flashbots-protect/rpc/fast-mode.md +++ /dev/null @@ -1,35 +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. diff --git a/docs/flashbots-protect/rpc/quick-start.md b/docs/flashbots-protect/rpc/quick-start.md deleted file mode 100644 index 24ac54d5..00000000 --- a/docs/flashbots-protect/rpc/quick-start.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: quick start ---- -**Please note that Flashbots Protect RPC is currently in public beta. Your transactions may occasionally time out and not be mined!** - -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. - -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. - -## Key considerations -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. -- **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. - -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*. - -## How to use Flashbots Protect RPC in MetaMask - -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`. -4. Scroll to the bottom and click “Save” - -![first metamask onboarding image](/img/flashbotsRPC-metamask1.png) -![second metamask onboarding image](/img/flashbotsRPC-metamask2.png) - -## How to use Flashbots Protect RPC in Metamask (Goerli Test Network) - -Follow these steps to add Flashbots Protect RPC endpoint for Goerli: - -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-goerli.flashbots.net` with a chainID of `5` and currency of `ETH`. -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". -4. Scroll down and click Reset Account. - -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 deleted file mode 100644 index 6ff5ab23..00000000 --- a/docs/flashbots-protect/rpc/ratelimiting.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -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 you are not required to read JSON RPC requests to send transactions to Flashbots Protect RPC. - -## Rate limiting exceptions - -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/releases.md b/docs/flashbots-protect/rpc/releases.md deleted file mode 100644 index a0cd1dab..00000000 --- a/docs/flashbots-protect/rpc/releases.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: release notes ---- - -## Initial Release -- Initial release on 10/6/2021 - -## 0.2.0 -- Upstreamed Protect API into a service that is more tightly coupled to the Flashbots Relay. As part of this migration cancellations are temporarily not supported. -- Released [status API](/flashbots-protect/rpc/status-api) that can be used to check the status of transactions. -- Spun off Protect API, webSDK, and gas fees calculator into standalone services. - -## 0.4.0 -- Refactored RPC and introduced persisent state, which is now stored in a database. This will improve UX when upgrading the RPC or during any potential downtime. -- Introduced the ability to [cancel the further submission of transactions](/flashbots-protect/rpc/cancellations) sent via Flashbots Protect RPC. diff --git a/docs/flashbots-protect/rpc/status-api.md b/docs/flashbots-protect/rpc/status-api.md deleted file mode 100644 index dfecf3b9..00000000 --- a/docs/flashbots-protect/rpc/status-api.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: private transaction status API ---- - -Transactions that you submit to Flashbots Protect won't be observable in the public mempool. However, you can use our status API to check the status of your transactions. The URL for doing so is: `https://protect.flashbots.net/tx/YOUR_TX_HASH_HERE`, and you can also use Etherscan as you normally would for transactions. They will show the status of your transaction from the status API as well. - -In turn you will receive a JSON response that looks like the following: - -```json -{ - "status": "PENDING", - "hash": "YOUR_TX_HASH", - "maxBlockNumber": 13543898, - "transaction": { - "from": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", - "to": "0xac03bb73b6a9e108530aff4df5077c2b3d481e5a", - "gasLimit": "21000", - "maxFeePerGas": "300", - "maxPriorityFeePerGas": "10", - "nonce": "41", - "value": "10000000000" - }, - "fastMode": false, - "seenInMempool": false, - "simError": "MaxFeePerGasTooLow" -} -``` - -## Potential statuses -* `PENDING` - The transaction was received and is currently being submitted to miners -* `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 deleted file mode 100644 index 09bebaab..00000000 --- a/docs/flashbots-protect/rpc/uncle-bandits.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -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. - -In order to protect against uncle bandits, users looking for frontrunning protection should include a check on the parent hash in their transaction: - -``` -require(blockhash(block.number - 1) == expectedParentHash, "block was uncled"); -``` - -Note that this check needs to be done in the smart contract that you are interacting with, and is not widely supported at this time. diff --git a/docs/flashbots-protect/settings-guide.md b/docs/flashbots-protect/settings-guide.md new file mode 100644 index 00000000..a5179c10 --- /dev/null +++ b/docs/flashbots-protect/settings-guide.md @@ -0,0 +1,154 @@ +--- +title: Settings Guide +--- + +import HintsTable from '../specs/mev-share/HintsTable'; +import Builders from '../specs/mev-share/_builders.mdx'; + +The Protect RPC uses query parameters and URL paths to convey your preferences. These parameters indicate which builders to share your transaction with, how potential refunds should be distributed, when to send transactions to the mempool, and other features. + +### Default + +```url +https://rpc.flashbots.net +``` + +By default, Flashbots Protect uses the following settings: +- Transactions are only forwarded to the Flashbots block builder +- Transactions are retried for 25 blocks and dropped if they do not land on chain within this time +- The `hash` and `default_logs` [hints](/flashbots-protect/settings-guide#hints) are shared with MEV-Share searchers +- 90% of MEV refunds are sent to `tx.origin` (the remaining 10% is sent to the validator) +- 100% of gas fee refunds are sent to `tx.origin` +- 0 priority fee transactions are not included on chain +- Reverted transactions are not included on chain + +This may change as the configuration is tuned to maximize benefits. + +### Fast + +Speed up your transactions by using fast mode. + +```url +https://rpc.flashbots.net/fast +``` + +Compared with the default configuration: +- Transactions are shared with all [registered builders](https://github.com/flashbots/dowg/blob/main/builder-registrations.json) +- Validators receive a higher percentage of the MEV-Share refund increasing the probability that the transaction will be included in the winning block. +- Full transaction information (without signatures) is shared with searchers inside TEEs to increase MEV refunds while preserving frontrunning protection. Searchers not in TEEs will receive only the hints specified. TEE searchers will be able to see full transaction information (even for failed or reverted transactions) after a 5-minute delay for troubleshooting and debugging purposes. + +### Hints + +Change what transaction data is visible to MEV-Share searchers with the `hint` query parameter. The [default](/flashbots-protect/settings-guide#default) hint configuration will be used if no hints are provided. If you specify one or more hints, any hint that is _not_ included will be disabled. If fast mode is used, searchers not in TEEs will only receive the hints specified while TEE searchers will receive all hints regardless of specification. + + + +Here is an example: + +```url +https://rpc.flashbots.net?hint=contract_address&hint=logs +``` + +This configuration shares the contract address and logs with searchers. It does not share the calldata or function selector. + +### Builders + +Designate which builders will receive your transaction with the `builder` query parameter. This parameter can be repeated multiple times to include different builders. The builders listed below are currently supported. + +Note that all transactions are shared with the Flashbots block builder, even if it is not explicitly specified. + + + +It's important to understand that while adding more builders can increase your transaction inclusion rate, it also requires you to place trust in those builders. Here's an example of how to utilize the `builder` parameter: + +```url +https://rpc.flashbots.net?builder=ABC&builder=XYZ +``` + +This configuration sends your transaction to ABC block builder, XYZ block builder, and the Flashbots block builder. + +### Refunds + +Tailor your refund settings using the `refund` query parameter. This determines how MEV and gas fee refunds will be distributed across different addresses. If not specified, the transaction originator (tx.origin) will receive all refunds. + +The refund parameter contains two colon-separated values: an address for the refund and the percentage of the payment that should be refunded to that address. + +Here is an example of a refund parameter that sends 10% of refunds to the address `recipientAddress`: + +```URL +https://rpc.flashbots.net?refund=recipientAddress:10 +``` + +#### MEV Refund Recipients + +MEV refunds can be split across multiple recipients. To distribute the payment across multiple addresses, append a new refund parameter for each address. + +The sum of all refund percentages must be less than 100. The remaining percentage, inferred from 100 - total refund percentages, is the payment to the validator. + +**Note**: Keeping a larger percentage of the refund may result in longer block inclusion times as it reduces the payment to the validator. + +#### Gas Fee Refund Recipients + +Gas fee refunds can only be sent to a single recipient. If multiple addresses are specified, the first refund address listed will receive 100% of the gas fee refund. There is no additional payment split with the validator. + +### Mempool Configuration + +Send certain transactions to the public mempool to improve the likelihood of inclusion by including the `useMempool` query parameter. If either of the following conditions are true, Flashbots will send all pending transactions with this parameter to the public mempool: +1. The Ethereum validator responsible for proposing the next block does not run [MEV-Boost](/flashbots-mev-boost/introduction). Approximately 10% of Ethereum blocks do not include any private transactions. Sending your transaction to the public mempool will give you access to those blocks at the expense of privacy and MEV refunds. +2. The transaction has not been included for 25 blocks: Some transactions pay very low priority fees are unlikely to land within 25 blocks. Send them to the public mempool to allow them to wait for lower gas prices. + +To enable this feature, add the `useMempool` parameter to your Protect RPC URL: + +```url +https://rpc.flashbots.net?useMempool=true +``` + +For analytics or other purposes, you can also specify a custom mempool URL by adding the `mempoolRpc` parameter: + +```url +https://rpc.flashbots.net?useMempool=true&mempoolRpc=https://your-custom-node-url +``` + +Note: If this setting is enabled, all cancellations will be immediately forwarded to the public mempool, regardless of if the transaction itself has been made public. + +### Reverted Transactions + +Allow reverted transactions by including the `canRevert` query parameter in your request. By default, Flashbots Protect does not land reverted transactions on chain to save users gas fees. You can override this feature to receive faster feedback about failing transactions. + +```url +https://rpc.flashbots.net?canRevert=true +``` + +### Block range + +By default we try to land transactions in the next 25 blocks. You can change this range by including the `blockRange` query parameter in your request. + +```url +https://rpc.flashbots.net?blockRange=10 +``` + +### Bundle Mode + +Use the Protect PRC in bundle mode to interactively construct a bundle of transactions that you want to be land together. This setting is typically used for whitehat rescues and you can find the complete documentation in the [Flashbots API docs](https://docs.flashbots.net/flashbots-protect/additional-documentation/bundle-cache). + +Bundle mode has a few differences from the regular Protect experience: +- Protect will not immediately attempt to land transactions sent in bundle mode. Instead, new transactions will be queued and kept in a pending state. +- To send all pending transactions as a bundle, you must make a separate API request to Flashbots. +- Querying the balance of an address in bundle mode will return a fake balance of 100 ETH. + +### Custom Read RPC + +Use a custom RPC endpoint for **read** requests by including the `url` query parameter in your request. **Write** requests (eg. `eth_sendRawTransaction`) will still be sent to the Protect RPC. This feature is recommended for wallets and applications with large volumes of read requests. + +```url +https://rpc.flashbots.net?url=http://RPC-ENDPOINT.COM +``` + +### Auction timeout + +If `auctionTimeout=T`, where `T` is the time in milliseconds, is specified, and a transaction arrives within `T` milliseconds of the end of the current slot, it will be scheduled for the next slot. +This ensures the transaction is processed at the beginning of the next slot, giving searchers the full slot duration to submit their bundles and backruns. + +``` +https://rpc.flashbots.net?auctionTimeout=3000 +``` diff --git a/docs/flashbots-protect/stuck_transactions.md b/docs/flashbots-protect/stuck_transactions.md new file mode 100644 index 00000000..e4f160b8 --- /dev/null +++ b/docs/flashbots-protect/stuck_transactions.md @@ -0,0 +1,14 @@ +--- +title: Fixing Stuck Transactions +--- + +If your transaction is stuck in a "pending" state or you have an extremely high nonce, you should clear your activity and nonce data in your MetaMask. This will cause Metamask to update the nonce and transaction history from the network. + +**Note**: Your funds and keys are safe during this process. + +To reset your MetaMask account, follow these steps: + +1. Click the account icon on the top-right corner of MetaMask. +2. Click "Settings". +3. Click "Advanced". +4. Scroll down and click “Clear activity tab data”. diff --git a/docs/guide-send-tx-bundle.mdx b/docs/guide-send-tx-bundle.mdx new file mode 100644 index 00000000..550d113d --- /dev/null +++ b/docs/guide-send-tx-bundle.mdx @@ -0,0 +1,37 @@ +--- +title: Sending Tx and Bundles +--- + +Flashbots provides a variety of methods for submitting transactions and bundles. This guide is designed to help you understand these options and select the one that best fits your needs. + +## Understanding Relay and RPC Endpoints + +Flashbots offers two primary JSON-RPC endpoints on Ethereum Mainnet: `rpc.flashbots.net` and `relay.flashbots.net`. + +### `rpc.flashbots.net` - For Retail Users +- **Purpose**: Designed specifically for retail users as a drop-in RPC replacement in their wallet. +- **Features**: Provides MEV protection and MEV refunds for eligible transactions. Support all the regular [Ethereum JSON RPC methods](https://docs.infura.io/networks/ethereum/json-rpc-methods/) but not [Flashbots specific JSON RPC +methods](flashbots-auction/advanced/rpc-endpoint). +- **Note**: Transactions are submitted through `eth_sendRawTransaction` to fit wallet RPC interface. Underneath, the endpoint uses `relay.flashbots.net` to submit transactions. + +### `relay.flashbots.net` - For Advanced Users +- **Purpose**: Designed for advanced users, including searchers, applications, and Telegram bots. It accepts both transactions and bundles. +- **Features**: Support all [Flashbots specific JSON RPC methods](flashbots-auction/advanced/rpc-endpoint). Does not support regular [Ethereum JSON RPC methods](https://docs.infura.io/networks/ethereum/json-rpc-methods/). +- **Recommendation**: Ideal for activities beyond simple transaction submissions via wallets. + +## Choosing the Right JSON-RPC Method + +With `relay.flashbots.net` identified as the go-to for advanced operations, the choice of JSON-RPC methods is as follows: + +- **For Single Transactions**: Use `eth_sendPrivateTransaction`. +- **For Bundles of Transactions**: + - **Use**: `mev_sendBundle` for more flexibility and power, like leveraging the [new bundle format](flashbots-mev-share/searchers/understanding-bundles) and [MEV-Share](flashbots-mev-share/introduction). + - **Use**: `eth_sendBundle` if you want something simple and quick! The OG way of sending bundles. + - Both bundle APIs support [multiplexing to multiple builders](flashbots-auction/advanced/multiplexing). + +## Rate Limits + +In order to protect our services from abuse we have rate limits on the number of requests that can be made. + +- [RPC rate limits for retail user transactions sent to](flashbots-protect/ratelimiting) `rpc.flashbots.net` +- [Relay rate limits for advanced user bundles sent to](flashbots-mev-share/searchers/ratelimiting) `relay.flashbots.net` diff --git a/docs/joining-flashbots.mdx b/docs/joining-flashbots.mdx index b6110129..515abc90 100644 --- a/docs/joining-flashbots.mdx +++ b/docs/joining-flashbots.mdx @@ -1,11 +1,11 @@ --- -title: join flashbots +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. +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. -* [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 +* [Open job positions](https://www.flashbots.net/jobs) - 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 diff --git a/docs/new-to-mev.mdx b/docs/new-to-mev.mdx index a11167de..4213b2b0 100644 --- a/docs/new-to-mev.mdx +++ b/docs/new-to-mev.mdx @@ -1,5 +1,5 @@ --- -title: new to mev? +title: New to MEV? --- ### Here's where to get started diff --git a/docs/policies/privacy.mdx b/docs/policies/privacy.mdx index e681a6b4..ee904d75 100644 --- a/docs/policies/privacy.mdx +++ b/docs/policies/privacy.mdx @@ -1,5 +1,5 @@ --- -title: data privacy notice +title: Data Privacy Notice --- ## Flashbots Ltd. diff --git a/docs/policies/prohibited-use-policy.mdx b/docs/policies/prohibited-use-policy.mdx new file mode 100644 index 00000000..b7315b28 --- /dev/null +++ b/docs/policies/prohibited-use-policy.mdx @@ -0,0 +1,16 @@ +--- +title: Prohibited Use Policy +--- + +## Flashbots Ltd. +*Updated July 6, 2023* + +Users of the Flashbots Services may not use the Flashbots Services or Flashbots webpages or social media pages managed by FLASHBOTS (the “Flashbots Sites”) to engage in the following activities: + +Unlawful Activity: Activity which would violate, or assist in violation of, any law, statute, ordinance, regulation, or sanctions programs administered in the countries where Flashbots Services are used, including but not limited to the U.S. Department of Treasury's Office of Foreign Assets Control ("OFAC") and the United Kingdom’s Office of Financial Sanctions Implementation (“OFSI”), or which would involve proceeds of any unlawful activity; publishing, distributing or disseminating any unlawful material or information; misrepresentation; hacks; transaction manipulation (including, e.g., frontrunning a transaction, time bandit attacks, or similar activities); theft; deceit; or unlawful or unregistered sales or offerings of securities. + +Abusive Activity: Actions which impose an unreasonable or disproportionately large load on Flashbots Services infrastructure, or detrimentally interfere with, intercept, or expropriate any system, data, or information; transmit or upload any material to the Flashbots Sites that contains viruses, trojan horses, worms, or any other harmful or deleterious programs; attempt to gain unauthorized access to Flashbots Services, Flashbots Sites, computer systems or networks connected to FLASHBOTS; use information of another party to access or use the Flashbots Services; or transfer your access or rights to any Flashbots Service to a third party, unless by operation of law or with the express permission of FLASHBOTS. + +Abuse Other Users: Interfere with another individual’s or entity’s access to or use of any Flashbots Services; defame, discriminate, abuse, extort, harass, stalk, threaten or otherwise violate or infringe the legal rights (such as, but not limited to, rights of privacy, publicity and intellectual property) of others; harvest or otherwise collect information from the Flashbots Sites about others, including without limitation email addresses, without proper consent; or use Flashbots Services or Flashbots Sites in connection with surveys, contests, pyramid schemes, chain letters, junk email, spamming, or any duplicative or unsolicited messages (commercial or otherwise). + +Fraud: Activity which operates to defraud FLASHBOTS, Flashbots Services users, or any other person; provide any false, inaccurate, or misleading information to FLASHBOTS. diff --git a/docs/policies/terms-of-service.mdx b/docs/policies/terms-of-service.mdx index ae428e79..f6dc398a 100644 --- a/docs/policies/terms-of-service.mdx +++ b/docs/policies/terms-of-service.mdx @@ -1,149 +1,162 @@ --- -title: terms of service +title: Terms of Service --- ## Flashbots Ltd. -*Updated December 10, 2021* +*Updated July 6, 2023* ### ACCEPTANCE OF TERMS -BY ACCESSING THE FLASHBOTS SERVICE, YOU AGREE TO BOTH THE FLASHBOTS LTD. (“**FLASHBOTS**”) TERMS OF SERVICE AND [THE PRIVACY POLICY](https://docs.flashbots.net/policies/privacy#contact) related to Your use of the Flashbots Service as defined below. +BY ACCESSING ANY SERVICES PROVIDED BY FLASHBOTS LTD. (**“FLASHBOTS”**) OR FLASHBOTS SITES, AS DEFINED BELOW, YOU AGREE TO THESE TERMS OF SERVICE, [THE FLASHBOTS POLICIES](/policies/terms-of-service#flashbots-policies-appendix), AND THE [PRIVACY POLICY](/policies/privacy#contact) AS GOVERNING TO YOUR USE OF THE FLASHBOTS SERVICES AND FLASHBOTS SITES. IF YOU ARE ENTERING INTO OR ACCEPTING THESE TERMS ON BEHALF OF A LEGAL ENTITY, YOU REPRESENT AND WARRANT THAT YOU HAVE THE RIGHT, AUTHORITY AND CAPACITY TO BIND SUCH ENTITY AND ITS AFFILIATES TO THESE TERMS, IN WHICH CASE, REFERENCES TO “YOU" SHALL REFER TO SUCH ENTITY AND ITS AFFILIATES. IF YOU DO NOT HAVE SUCH AUTHORITY, OR IF YOU DO NOT AGREE TO BE BOUND BY ALL OF THE PROVISIONS OF THESE TERMS, DO NOT ACCESS OR USE FLASHBOTS SERVICES. +THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS. -FLASHBOTS provides free-to-use software to Ethereum Network node operators, miners, transactors, and other participants (“**MEV Geth**”) and operates a service, the “**Relay**”, which connects persons seeking to transact on the Ethereum Network to block producers on the same, along with certain other related services and online websites (collectively, such services the “**Flashbots Services**”). The Flashbots Services are subject to the following terms of service (“**Terms of Service**” or “**ToS**”). FLASHBOTS reserves the right to update these ToS at any time without notice to You. +FLASHBOTS provides certain software, as set forth in [FLASHBOTS’ Github repository](https://github.com/flashbots), as well as other related software that FLASHBOTS may provide from time to time, (each program, a “**Software Program**” and collectively, the “**Software Programs**”) to Ethereum Network node operators, wallet and application providers, block builders, block searchers, and other participants (the “**Users**”). -FLASHBOTS shall have the right at any time to change or discontinue any aspect or feature of the Flashbots Service, including, but not limited to, content, access, or use. +The Software Programs are provided under a separate open-source license, which means that anyone can use, copy, modify, or distribute them. As such, FLASHBOTS, its affiliates, and any of their respective officers, members, owners, employees, or agents (such parties, in their individual and collective capacities, the “Flashbots Parties”) are not responsible for the operation of the Software Programs and make no guarantees regarding their security, functionality, or availability. In the event of a conflict between these Terms of Service and any separate license, the separate license will prevail with respect to the subject thereof. + +FLASHBOTS also provides certain content, including research and product information, functionality and features, as further described on [FLASHBOTS’ website](/), as well as FLASHBOTS related websites and other social media pages (the “Flashbots Sites”) and such other related services that FLASHBOTS may provide from time to time, including without limitation security, configuration, and other technical support services (each, a “Flashbots Service” and collectively, the “**Flashbots Services**”). +The Flashbots Services are subject to the following terms of service (“**Terms of Service**” or “**ToS**”). FLASHBOTS reserves the right to update these ToS at any time without notice to You. If You do not agree with the terms of the updated ToS, Your sole and exclusive remedy is to terminate Your use of Flashbots Services. + +FLASHBOTS shall have the right at any time to change or discontinue any aspect or feature of the Flashbots Services, including, but not limited to, content, access, or use. ### ELIGIBILITY -You represent and warrant that You are at least 18 years of age or the age of majority in Your state or jurisdiction of residence, whichever is greater, that You are capable of entering into a legally binding agreement and that You reside in a jurisdiction where Your use of the Flashbots Service is lawful. Your right to use the Flashbots Services is conditioned upon Your acceptance and compliance with these ToS. If You do not agree to be bound by the terms and conditions set forth in these ToS, You are not authorized to use the Flashbots Service and You agree to immediately discontinue any access to or use of the Flashbots Service. +You represent and warrant that You are at least 18 years of age or the age of majority in Your state or jurisdiction of residence, whichever is greater; that You are capable of entering into a legally binding agreement; and that You reside in a jurisdiction where Your use of the Flashbots Services is lawful. Your right to use the Flashbots Services is conditioned upon Your acceptance and compliance with these ToS. If You do not agree to be bound by the terms and conditions set forth in these ToS, You are not authorized to use the Flashbots Services and You agree to immediately discontinue any access to or use of the Flashbots Services. -In addition, in order to participate in the Relay, you may need to download, install, and run MEV Geth and, in certain situations discussed at greater length below, undertake certain personal and account verification steps prior to using the Relay. +In addition, You represent to FLASHBOTS that You, Your digital currency addresses, and Your financial institutions, or any party that owns or controls You, Your digital currency addresses or Your financial institutions, are (1) not subject to sanctions or otherwise designated on any list of prohibited or restricted parties, including but not limited to the lists maintained by the U.S. Government (i.e., the Specially Designated Nationals List and Foreign Sanctions Evaders List of the U.S. Department of Treasury and the Entity List of the U.S. Department of Commerce), the ,the United Kingdom, or other applicable government authority and (2) not located in or attempting to use Flashbots Services from any country subject to a comprehensive sanctions program implemented by the United States or the United Kingdom. ### SCOPE OF USE -These Terms of Service cover all use of the Flashbots Service, regardless of how the Flashbots Service is accessed, and regardless of which device is used for access. +These Terms of Service cover all use of the Flashbots Services, regardless of how any Flashbots Service is accessed, and regardless of which device is used for access. -### ELECTRONIC INFORMED CONSENT +### ONBOARDING -FLASHBOTS may, from time to time, ask You to accept these ToS, along with other online agreements and disclosures. By providing Your acceptance, You will be providing Your electronic informed consent that will affirm: +Prior to using any Flashbots Service, You may be required to complete onboarding steps, such as personal verification. In addition, FLASHBOTS reserves the right to require additional documentation and procedures to verify Your identity and/or control of any associated digital wallets. -- You understand and intend that these Terms of Service comprise a legally binding agreement and are equivalent to a signed, written contract; and -- You will use the Flashbots Service in a manner consistent with applicable laws and regulations, and in accordance with the terms and conditions of these Terms of Service and any other applicable rules, guidelines or other conditions that govern the use of a particular service or site. +### AVAILABILITY -### ACCOUNT CREATION & ONBOARDING +FLASHBOTS does not represent that any of the Flashbots Services will be available without interruption or for any particular duration, and the Flashbots Parties shall not be responsible for any losses, damages, costs, expenses, lost opportunities, or other harm suffered by You in connection with interruption or termination of any Flashbots Service. YOU SHOULD READ THE LIMITATION OF LIABILITY HEREIN, WHICH INCLUDES LIMITATIONS ON THE FLASHBOTS’ PARTIES AND OTHER THIRD PARTIES’ POTENTIAL LIABILITY FOR ANY SUCH SERVICE INTERRUPTIONS. -Prior to joining the Relay as a miner, you may be required to complete the miner onboarding steps. In addition, FLASHBOTS reserves the right to require additional KYC/CDD documentation and procedures to verify your identity and/or control of any associated digital wallets. +### ACKNOWLEDGMENT OF RISK -### AVAILABILITY +You acknowledge that the underlying blockchain technologies involved in using any Flashbots Service are novel, technically complex, and involve inherent risks, with or without the use of any Software Program. You bear all risk of loss from Your use of any Flashbots Service. The Flashbots Parties shall have no liability for fluctuations in the value of any cryptocurrency, transaction, or any bundle of transactions, whether requested or provided. -FLASHBOTS does not represent that the Relay or any other aspect of the Flashbots Services will be available without interruption or for any particular duration, and shall not be responsible for any losses, damages, costs, expenses, lost opportunities, or other harm suffered by You in connection with interruption or termination of the Flashbots Services. YOU SHOULD READ THE LIMITATION OF LIABILITY HEREIN, WHICH INCLUDES LIMITATIONS ON FLASHBOTS POTENTIAL LIABILITY FOR ANY SUCH SERVICE INTERRUPTIONS. +You acknowledge that although FLASHBOTS is constantly improving its security measures against security breaches that might result in the loss or corruption of data, the Flashbots Parties and FLASHBOTS’ third-party partners shall not be responsible for the operation of any Flashbots Service or Software Program and shall not be liable to You or any other Users for any damage caused by such loss or corruption of data. You understand that the Software Program and other protocol upgrades may inadvertently contain bugs or security vulnerabilities that may result in loss of functionality and ultimately funds. -### ACKNOWLEDGMENT OF RISK +You acknowledge that the Flashbots Services involve novel technological innovations. Results depend on a multiplicity of factors beyond the control of FLASHBOTS, including but not limited to network health, congestion, latency, incentives, user configuration settings, operation of third party software or hardware, wallet compatibility, protocol upgrades or forks, the activities of searchers, block builders, producers, etc. Therefore, the outcomes cannot be predicted, and no representations or warranties are made with respect to the Flashbots Services. OUTCOMES ARE NOT GUARANTEED. You agree that the Flashbots Parties are not responsible for the regulatory status or treatment in any jurisdiction of any digital assets that You may access or transact with using the Flashbots Services. + +Your participation in the Flashbots Services involves the use of sophisticated hardware and software. The Flashbots Parties will not be liable or responsible to You, nor be deemed to have defaulted or breached these Terms of Service, for any failure or delay in our performance under these Terms of Service when and to the extent such failure or delay is caused by or results from acts or circumstances beyond our reasonable control and/or from the hardware used in the Flashbots Service, including, without limitation, acts of God, cyberattack or ransomware, flood, fire, earthquake, explosion, governmental actions, war, invasion or hostilities (whether war is declared or, terrorist threats or acts, riot or other civil unrest, national emergency, revolution, insurrection, epidemic, pandemic, lockouts, strikes or other labor disputes (whether or not relating to our workforce), or restraints or delays affecting carriers or inability or delay in obtaining supplies of adequate or suitable materials, telecommunication or third party service provider breakdown, interruption or unavailability, electrical disruptions, or power outage. -You acknowledge that the underlying blockchain technologies involved in using the Flashbots Service are novel, technically complex, and involve inherent risks, with or without the use of GETH or the Flashbots Service. You bear all risk of loss from Your use of the Flashbots Service. FLASHBOTS shall have no liability for fluctuations in the value of any cryptocurrency, transaction, or any bundle of transactions, whether requested or provided. +You represent that You have the technical and financial knowledge, experience, and wherewithal to understand and undertake these risks. -You acknowledge that FLASHBOTS is constantly improving its security measures against security breaches that might result in the loss of data. In such a case, FLASHBOTS and its third-party partners responsible for the operation of the Flashbots Service or software shall not be liable to users for any damage caused. +### USE OF FLASHBOTS SERVICES -You acknowledge that the Flashbots Services involve novel technological innovations aimed at facilitating more efficient access to blockchains. Results depend on a multiplicity of factors beyond the control of FLASHBOTS, including but not limited to luck, network difficulty, latency, reject rate, fees/tips, the activities of searchers and block producers, etc. Therefore, the outcomes cannot be predicted, and no representations or warranties are made with respect to the Flashbots Services. OUTCOMES ARE NOT GUARANTEED. +You agree to use the Flashbots Services for lawful purposes only, and solely in a manner consistent with the intent of FLASHBOTS as described in these Terms of Service including without limitation, the Flashbots Policies, as updated from time to time. -Your participation in the Flashbots Service involves the use of sophisticated hardware and software. FLASHBOTS will not be liable or responsible to You, nor be deemed to have defaulted or breached these Terms of Service, for any failure or delay in our performance under these Terms of Service when and to the extent such failure or delay is caused by or results from acts or circumstances beyond our reasonable control and/or from the hardware used in the Flashbots Service, including, without limitation, acts of God, flood, fire, earthquake, explosion, governmental actions, war, invasion or hostilities (whether war is declared or not), terrorist threats or acts, riot or other civil unrest, national emergency, revolution, insurrection, epidemic, pandemic, lockouts, strikes or other labor disputes (whether or not relating to our workforce), or restraints or delays affecting carriers or inability or delay in obtaining supplies of adequate or suitable materials, materials or telecommunication breakdown, or power outage. +You agree that You shall not upload, or otherwise make available, files that contain images, photographs, software, or other material protected by intellectual property laws, including, by way of example, and not as limitation, copyright or trademark laws (or by rights of privacy or publicity) unless You own or control the rights thereto or have received all necessary consent to do the same, use any material or information, including images or photographs, which are made available through the Flashbots Service in any manner that infringes any copyright, trademark, patent, trade secret, or other proprietary right of any party, upload files that contain viruses, Trojan horses, worms, time bombs, cancelbots, corrupted files, or any other similar software or programs that may damage the operation of another’s computer or damage the property of another, falsify or delete any copyright management information such as author attributions, watermarks, legal or other proper notices or proprietary designations or labels of the origin or source of software or other material contained in a file that is uploaded, violate any code of conduct or other guidelines that may be applicable, harvest or otherwise collect information about others, including personal information or personal data. You shall be solely liable for any damage resulting from any unlawful, wrongful, deceitful or other act, or from infringement of copyrights, proprietary rights, or any other harm resulting from such an act. The foregoing provisions of this section are for the benefit of the Flashbots Parties,(including but not limited to FLASHBOTS’s third-party service and content providers) and licensors, and each shall have the right to assert and enforce such provisions directly or on its own behalf. -By accepting these Terms and using the Flashbots Service, You represent that you have the technical and financial knowledge, experience, and wherewithal to understand and undertake these risks. +Always use caution when giving out any personally identifiable information in any service. The Flashbots Parties do not control or endorse the third-party content, messages, or information found in the Flashbots Service. The Flashbots Parties disclaim any liability with regards to the Flashbots Service, and any actions resulting from Your participation in the Flashbots Service. -### USE OF THE FLASHBOTS SERVICE +FLASHBOTS reserves the right to not admit You or other Users to any Flashbots Service, or otherwise restrict access to any Flashbots Service, without any reason or cause. In addition, excessive application program interface (“API”) requests may result in the temporary or permanent suspension of Your access to a Flashbots Service. -You agree to use the Flashbots Service for lawful purposes only, and solely in a manner consistent with the intent of FLASHBOTS as described in these Terms of Service. +You agree that the Flashbots Parties have no responsibility for other Users’ use of the Flashbots Services and shall not be responsible to You to the extent that any security, configuration or technical support services that it may provide to other Users in connection with the Flashbots Services impacts Your use of the Flashbots Services. -You agree that You will not: +In the event any or all of the Flashbots Services are permanently or temporarily terminated, FLASHBOTS shall re-start services at its sole discretion as to timing and as to approach; in such event no resumption of service is promised or warranted. -- use the Flashbots Services for any unlawful or improper purpose specifically including without limitation misrepresentation, hacks, transaction manipulation (including, e.g., frontrunning a transaction, time bandit attacks, or similar activities), theft, deceit, unlawful or unregistered sales or offerings of securities, or otherwise use the Flashbots Services in connection with the violation of any applicable laws, rules or regulations; -- use any electronic communication feature, including third-party platforms such as Telegram and Discord Channels managed by FLASHBOTS, of the Flashbots Service for any purpose that is unlawful, tortious, abusive, discriminatory, intrusive on another's privacy, harassing, libelous, defamatory, embarrassing, obscene, threatening, or hateful; -- use the Flashbots Service in connection with surveys, contests, pyramid schemes, chain letters, junk email, spamming, or any duplicative or unsolicited messages (commercial or otherwise), defame, abuse, harass, stalk, threaten or otherwise violate the legal rights (such as without limitation rights of privacy and publicity) of others, publish, post, distribute or disseminate any inappropriate, profane, discriminatory, defamatory, obscene, indecent or unlawful topic, name, material or information; -- upload, or otherwise make available, files that contain images, photographs, software, or other material protected by intellectual property laws, including, by way of example, and not as limitation, copyright or trademark laws (or by rights of privacy or publicity) unless You own or control the rights thereto or have received all necessary consent to do the same, use any material or information, including images or photographs, which are made available through the Flashbots Service in any manner that infringes any copyright, trademark, patent, trade secret, or other proprietary right of any party, upload files that contain viruses, Trojan horses, worms, time bombs, cancelbots, corrupted files, or any other similar software or programs that may damage the operation of another’s computer or damage the property of another, advertise or offer to sell or buy any goods or services for any business purpose, falsify or delete any copyright management information such as author attributions, watermarks, legal or other proper notices or proprietary designations or labels of the origin or source of software or other material contained in a file that is uploaded, violate any code of conduct or other guidelines that may be applicable, harvest or otherwise collect information about others, including personal information or personal data such as by exemplar email addresses, violate any applicable laws or regulations, and/or create a false identity for the purpose of misleading others; +### YOUR RESPONSIBILITIES -You shall be solely liable for any damage resulting from any unlawful, wrongful, deceitful or other act, or from infringement of copyrights, proprietary rights, or any other harm resulting from such an act. The foregoing provisions of this section are for the benefit of FLASHBOTS, its subsidiaries, affiliates, and agents (which term includes but is not limited to FLASHBOTS’s third-party service and content providers) and licensors, and each shall have the right to assert and enforce such provisions directly or on its own behalf. +Use: You are responsible for all activities that occur with respect to Your use of the Flashbots Services, regardless of whether the activities are authorized by You or undertaken by You, Your employees or a third party (including but not limited to Your contractors, agents and other users), and (b) The Flashbots Parties are not responsible for unauthorized access to the Flashbots Services, including any access that occurred as a result of fraud, phishing, or other criminal activity perpetrated against You by third parties. -Always use caution when giving out any personally identifiable information in any service. FLASHBOTS does not control or endorse the third-party content, messages, or information found in the Flashbots Service. FLASHBOTS disclaims any liability with regard to the Flashbots Service, and any actions resulting from Your participation in the Flashbots Service. +Security, Configuration and Backup: You are solely responsible for properly configuring and using the Flashbots Services and otherwise taking appropriate action to secure, protect, and backup Your data and Your customers’ data, as applicable, in a manner that will provide appropriate security and protection. -FLASHBOTS reserves the right to terminate Your access to the Flashbots Service at any time, without notice, for any reason whatsoever, including without limitation violation of these ToS or the FLASHBOTS community best practices, and You agree that FLASHBOTS will not be liable to You or to any third party for any such termination, suspension, or modification of Your access to the Flashbots Services. +If You cannot or do not want to take such actions to ensure security and protection, then You should not use the Flashbots Services. Your obligations under this Agreement include ensuring any available software updates or upgrades relating to any Flashbots Service You are using are promptly installed or implemented and managing Your secure access to Your use of the Flashbots Services. -We reserve the right to not admit You or other users to the Relay, or otherwise restrict access to the Flashbots Service, without any reason or cause. In the event the Flashbots Service is permanently or temporarily terminated, FLASHBOTS shall re-start services at its sole discretion as to timing and as to approach; in such event no resumption of service is promised or warranted. +API Authentication: To the extent we provide You with API authentication generated by a Flashbots Service or similar credentials, such API authentication and similar credentials are for Your use only and You will not sell, transfer, or sublicense them to any other entity or person, except that You may disclose Your private key to Your agents and subcontractors performing work on Your behalf. ### LICENSE GRANT FROM FLASHBOTS -FLASHBOTS hereby grants You a single, revocable, non-exclusive, non-transferable, and limited license, personal to You, to access and use the Flashbots Service. This license grant is conditioned on Your acceptance and adherence to these Terms of Service. +FLASHBOTS hereby grants You a single, revocable, non-exclusive, non-transferable, and limited license, personal to You, to access and use the Flashbots Services and no other rights under this Terms of Use, including related intellectual property rights. This license grant is conditioned on Your acceptance and adherence to these Terms of Service. ### LICENSE GRANT TO FLASHBOTS -Unless otherwise agreed upon by You and FLASHBOTS, any communications or material of any kind that You e-mail, post, or otherwise transmit through the Flashbots Service, including transaction data, transaction bundles, text communications, comments, or suggestions (Your “Communications”) will be treated as proprietary and confidential, to the extent not ultimately published to a public blockchain or other public record by virtue of the operation of such networks. You hereby grant FLASHBOTS a limited, non-exclusive license to use, adapt, or reproduce Your Communications for purely internal purposes, such as improvement of the Service, so long as such activity does not result in public disclosure of Your Communication. +Unless otherwise agreed upon by You and FLASHBOTS, Your transaction, transaction bundle, or blocks of transactions (Your “Protected Data”) will be treated as proprietary and confidential to the extent not published to a public blockchain or other public record by virtue of the operation of such networks. You hereby grant FLASHBOTS a limited, non-exclusive license to use, adapt, or reproduce Your Protected Data for purely internal purposes, such as improvement of the Flashbots Service; as part of an anonymized, aggregated data set; to derive and publish system performance metrics and logs; or otherwise consistent with the purposes for which such information was disclosed to FLASHBOTS. + ### TAXES & FEES -Currently there is no fee for use of Flashbots Services; however, FLASHBOTS reserves the right to charge a fee in connection with Your use of the Flashbots Service. In the event FLASHBOTS chooses to charge a fee, it will be published in advance on GitHub and other websites, including the FLASHBOTS official Discord channel. Flashbots does not collect or deduct any taxes, levies, duties, or similar governmental assessments of any nature, assessable by any jurisdiction whatsoever (collectively, "Taxes"). You are responsible for determining whether any Taxes may apply to your use of the Flashbots Service, or any activity you undertake in connection with such use, and it is Your responsibility to report and remit the relevant Taxes to the appropriate taxing authorities. You agree that FLASHBOTS is not responsible for determining whether any Taxes apply, or the amount of any Taxes that may apply, to the Flashbots Service. +FLASHBOTS does not charge any fee for the use of Flashbots Services; however, FLASHBOTS reserves the right to charge a fee in connection with Your use of the Flashbots Service. In the event FLASHBOTS chooses to charge a fee, it will be published in advance on GitHub and other Flashbots Sites including the FLASHBOTS official Discord channel. Flashbots does not collect or deduct any taxes, levies, duties, or similar governmental assessments of any nature, accessible by any jurisdiction whatsoever (collectively, "Taxes"). You are responsible for determining whether any Taxes may apply to Your use of the Flashbots Service, or any activity You undertake in connection with such use, and it is Your responsibility to report and remit the relevant Taxes to the appropriate taxing authorities. You agree that the Flashbots Parties are not responsible for determining whether any Taxes apply, or the amount of any Taxes that may apply, to the Flashbots Service. ### NO INVESTMENT ADVICE OR RECOMMENDATIONS -Nothing contained in the Flashbots Service or any other content on the FLASHBOTS website constitutes a solicitation, recommendation, endorsement, or offer by FLASHBOTS to buy or sell any securities or other financial instruments. You understand that FLASHBOTS is not the source of the pricing or other information that may be available on the Flashbots platform and does not warrant its accuracy. +Nothing contained in the Flashbots Services or any other content on the Flashbots Sites constitutes a solicitation, recommendation, endorsement, or offer by FLASHBOTS to buy or sell any digital asset or other financial instruments.. -You alone assume the sole responsibility of evaluating the merits and risks associated with the use of the Flashbots Service or any related service before making any decisions based on information we provide to You, such as hashrates. In exchange for using the Flashbots Service, You agree not to hold FLASHBOTS, its employees or agents (including, without limitation, independent contractors or other service providers) liable for any possible claim for damages arising from any decision You make based on information made available to You through any of the Flashbots Services. +You alone assume the sole responsibility of evaluating the merits and risks associated with the use of the Flashbots Services or any related service before making any decisions based on information we provide to You, such as information made available though application program interfaces (APIs). In exchange for using the Flashbots Service, You agree not to hold the Flashbots Parties (including, without limitation, third party service and content providers and licensors liable for any possible claim for damages arising from any decision You make based on information made available to You through any of the Flashbots Services. ### CERTAIN INFORMATION MADE AVAILABLE BY FLASHBOTS -We may make available to You certain public data and other information (including, without limitation, information derived from public blockchain records), including information that we obtain from our agents, including but not limited to partners, vendors, infrastructure providers and KYC providers. FLASHBOTS makes this information available to You as a service for Your convenience; FLASHBOTS neither endorses nor approves any such information. FLASHBOTS neither (1) guarantees the accuracy, timeliness, or completeness of any such information, nor (2) warrants any results from Your use or reliance on such information. You agree that You use any such information at Your own risk. - -You agree that neither FLASHBOTS nor its agents (including, without limitation, independent contractors or other service providers) will be liable to You in any way for the termination, interruption, delay, or inaccuracy of any such information we provide to you. You agree that You will neither redistribute nor facilitate the redistribution of any such information, nor will You provide access to such information to anyone who is not authorized by FLASHBOTS to receive such information. +FLASHBOTS may make available to You certain public data and other information (including, without limitation, information derived from public blockchain records, system logs, and other operational metrics), including information that we obtain from our agents, including but not limited to partners, vendors, and infrastructure providers. FLASHBOTS makes this information available to You as a service for Your convenience; the Flashbots Parties neither endorse nor approve any such information. The Flashbots Parties neither (1) guarantee the accuracy, timeliness, or completeness of any such information, nor (2) warrant any results from Your use or reliance on such information. You agree that You use any such information at Your own risk. ### DISCLAIMER -YOU EXPRESSLY AGREE THAT USE OF THE FLASHBOTS SERVICE IS AT YOUR SOLE RISK. NEITHER FLASHBOTS, ITS AFFILIATES NOR ANY OF THEIR RESPECTIVE OFFICERS, MEMBERS, OWNERS, EMPLOYEES, OR LICENSORS, WILL BE LIABLE FOR ANY USE OR MISUSE OF THE FLASHBOTS SERVICE, WHETHER THAT USE IS BY FLASHBOTS, YOU, OR A THIRD PARTY. NEITHER FLASHBOTS, ITS AFFILIATES, NOR ANY OF THEIR RESPECTIVE EMPLOYEES, AGENTS, OR LICENSORS, WARRANT THAT THE FLASHBOTS SERVICE WILL BE UNINTERRUPTED OR ERROR FREE; NOR DO THEY MAKE ANY WARRANTY AS TO THE RESULTS THAT MAY BE OBTAINED FROM USE OF THE FLASHBOTS SERVICE, OR AS TO THE ACCURACY, RELIABILITY OR CONTENT OF ANY INFORMATION, SERVICE, MATERIALS, OR MERCHANDISE PROVIDED THROUGH THE FLASHBOTS SERVICE. THE SERVICES ARE PROVIDED ON AN “AS IS” BASIS WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF TITLE, IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE, OTHER THAN THOSE WARRANTIES THAT ARE BOTH (I) IMPLIED BY LAW AND (II) INCAPABLE OF EXCLUSION, RESTRICTION OR MODIFICATION, UNDER LAWS APPLICABLE TO THESE TERMS OF SERVICE. +YOU EXPRESSLY AGREE THAT USE OF THE FLASHBOTS SERVICES IS AT YOUR SOLE RISK. NEITHER THE FLASHBOTS PARTIES NOR ITS LICENSORS WILL BE LIABLE FOR ANY USE OR MISUSE OF THE FLASHBOTS SERVICES, WHETHER THAT USE IS BY THE FLASHBOTS PARTIES, YOU, OR A THIRD PARTY. NEITHER THE FLASHBOTS PARTIES NOR ITS LICENSORS WARRANT THAT THE FLASHBOTS SERVICES WILL BE UNINTERRUPTED OR ERROR FREE; NOR DO THEY MAKE ANY WARRANTY AS TO THE RESULTS THAT MAY BE OBTAINED FROM USE OF THE FLASHBOTS SERVICES, OR AS TO THE ACCURACY, RELIABILITY OR CONTENT OF ANY INFORMATION, SERVICE, MATERIALS, OR MERCHANDISE PROVIDED THROUGH THE FLASHBOTS SERVICES. THE FLASHBOTS SERVICES ARE PROVIDED ON AN “AS IS” BASIS WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF TITLE, IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE, OTHER THAN THOSE WARRANTIES THAT ARE BOTH (I) IMPLIED BY LAW AND (II) INCAPABLE OF EXCLUSION, RESTRICTION OR MODIFICATION, UNDER LAWS APPLICABLE TO THESE TERMS OF SERVICE. -WITHOUT LIMITING THE FOREGOING, THIS DISCLAIMER OF LIABILITY APPLIES TO ANY DAMAGES OR INJURY CAUSED BY ANY FAILURE OF PERFORMANCE, ERROR, OMISSION, INTERRUPTION, DELETION, DEFECT, DELAY IN OPERATION OR TRANSMISSION, COMPUTER VIRUS, COMMUNICATION LINE FAILURE, THEFT OR DESTRUCTION, OR UNAUTHORIZED ACCESS TO, ALTERATION OF, OR USE OF, THE FLASHBOTS SERVICE AND ANY MATERIALS OR CONTENT FOUND THEREIN, WHETHER FOR BREACH OF CONTRACT, TORTIOUS BEHAVIOR, NEGLIGENCE, OR UNDER ANY OTHER CAUSE OF ACTION. +WITHOUT LIMITING THE FOREGOING, THIS DISCLAIMER OF LIABILITY APPLIES TO ANY DAMAGES OR INJURY CAUSED BY ANY FAILURE OF PERFORMANCE, ERROR, OMISSION, INTERRUPTION, DELETION, DEFECT, DELAY IN OPERATION OR TRANSMISSION, COMPUTER VIRUS, COMMUNICATION LINE FAILURE, THEFT OR DESTRUCTION, OR UNAUTHORIZED ACCESS TO, ALTERATION OF, OR USE OF, THE FLASHBOTS SERVICES AND ANY MATERIALS OR CONTENT FOUND THEREIN, WHETHER FOR BREACH OF CONTRACT, TORTIOUS BEHAVIOR, NEGLIGENCE, OR UNDER ANY OTHER CAUSE OF ACTION. -YOU ACKNOWLEDGE THAT FLASHBOTS IS NOT LIABLE FOR THE DEFAMATORY, OFFENSIVE, OR ILLEGAL CONDUCT OF OTHER USERS, AND THAT YOU ALONE ARE ASSUMING THE RISK OF INJURY FROM THE FOREGOING, TO THE FULLEST EXTENT OF THE LAW. IN NO EVENT WILL FLASHBOTS, ITS AFFILIATES, ANY OF THEIR RESPECTIVE OFFICERS, MEMBERS, OWNERS, EMPLOYEES, AGENTS, LICENSORS OR ANY OTHER PERSON OR ENTITY INVOLVED IN CREATING, PRODUCING OR PROVIDING THE FLASHBOTS SERVICE OR THE SOFTWARE, BE LIABLE FOR ANY DAMAGES, INCLUDING, WITHOUT LIMITATION, DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR PUNITIVE DAMAGES ARISING OUT OF THE USE OF OR INABILITY TO USE THE FLASHBOTS SERVICE. IN ADDITION TO THE TERMS SET FORTH ABOVE, NEITHER FLASHBOTS NOR ITS AFFILIATES, AGENTS, INFORMATION PROVIDERS, OR CONTENT PARTNERS, SHALL BE LIABLE REGARDLESS OF THE CAUSE OR DURATION, FOR ANY ERRORS, INACCURACIES, OMISSIONS, OR OTHER DEFECTS IN, OR UNTIMELINESS OR UNAUTHENTICITY OF, THE INFORMATION CONTAINED WITHIN THE FLASHBOTS SERVICE, OR FOR ANY DELAY OR INTERRUPTION IN THE TRANSMISSION THEREOF TO YOU, OR FOR ANY CLAIMS OR LOSSES ARISING THEREFROM OR OCCASIONED THEREBY. FLASHBOTS SHALL NOT BE LIABLE FOR ANY THIRD-PARTY CLAIMS OR LOSSES OF ANY NATURE, INCLUDING, BUT NOT LIMITED TO, LOST PROFITS, PUNITIVE OR CONSEQUENTIAL DAMAGES. +YOU ACKNOWLEDGE THAT FLASHBOTS PARTIES ARE NOT LIABLE FOR THE DEFAMATORY, OFFENSIVE, OR ILLEGAL CONDUCT OF OTHER USERS, AND THAT YOU ALONE ARE ASSUMING THE RISK OF INJURY FROM THE FOREGOING, TO THE FULLEST EXTENT OF THE LAW. IN NO EVENT WILL THE FLASHBOTS PARTIES, , ITS LICENSORS OR ANY OTHER PERSON OR ENTITY INVOLVED IN CREATING, PRODUCING OR PROVIDING THE FLASHBOTS SERVICES OR THE SOFTWARE PROGRAMS, BE LIABLE FOR ANY DAMAGES, INCLUDING, WITHOUT LIMITATION, DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR PUNITIVE DAMAGES ARISING OUT OF THE USE OF OR INABILITY TO USE THE FLASHBOTS SERVICES. IN ADDITION TO THE TERMS SET FORTH ABOVE, NEITHER THE FLASHBOTS PARTIES , NOR FLASHBOTS’ INFORMATION PROVIDERS, OR CONTENT PARTNERS, SHALL BE LIABLE REGARDLESS OF THE CAUSE OR DURATION, FOR ANY ERRORS, INACCURACIES, OMISSIONS, OR OTHER DEFECTS IN, OR UNTIMELINESS OR UNAUTHENTICITY OF, THE INFORMATION CONTAINED WITHIN THE FLASHBOTS SERVICES, OR FOR ANY DELAY OR INTERRUPTION IN THE TRANSMISSION THEREOF TO YOU, OR FOR ANY CLAIMS OR LOSSES ARISING THEREFROM OR OCCASIONED THEREBY. THE FLASHBOTS PARTIES SHALL NOT BE LIABLE FOR ANY THIRD-PARTY CLAIMS OR LOSSES OF ANY NATURE, INCLUDING, BUT NOT LIMITED TO, LOST PROFITS, PUNITIVE OR CONSEQUENTIAL DAMAGES. -FLASHBOTS RESERVES THE RIGHT TO MAKE CHANGES AND CORRECTIONS TO THE FLASHBOTS SERVICE AND THESE TERMS OF SERVICE AT ANY TIME, WITHOUT NOTICE. THE INFORMATION PROVIDED THROUGH THE FLASHBOTS SERVICE IS PROVIDED “AS IS” AND “AS AVAILABLE.” FLASHBOTS DOES NOT WARRANT, AND AFFIRMATIVELY DISCLAIMS, ANY AND ALL WARRANTIES REGARDING, THE ACCURACY, COMPLETENESS OR TIMELINESS OF INFORMATION, TEXT, GRAPHICS, LINKS OR OTHER ITEMS CONTAINED IN THE FLASHBOTS SERVICE OR ON THE FLASHBOTS WEBSITE. FLASHBOTS PROVIDES NO GUARANTEE AGAINST THE POSSIBILITY OF DELETION, MIS-DELIVERY OR FAILURE TO STORE COMMUNICATIONS, PERSONALIZED SETTINGS, OR OTHER DATA. FLASHBOTS EXPRESSLY DISCLAIMS ALL LIABILITY FOR ERRORS OR OMISSIONS IN, OR THE MISUSE OR MISINTERPRETATION OF, ANY INFORMATION CONTAINED IN THE FLASHBOTS SERVICE OR THE OPERATION THEREOF. FLASHBOTS MAY CHANGE INFORMATION CONTAINED IN THE FLASHBOTS SERVICE AT ANY TIME AND MAKES NO COMMITMENT TO UPDATE THE INFORMATION CONTAINED THEREIN. YOU ASSUME THE ENTIRE RISK AS TO THE USE OF THE FLASHBOTS SERVICE. +FLASHBOTS RESERVES THE RIGHT TO MAKE CHANGES AND CORRECTIONS TO THE FLASHBOTS SERVICES, THESE TERMS OF SERVICE AND THE FLASHBOTS POLICIES AT ANY TIME, WITHOUT NOTICE. THE INFORMATION PROVIDED THROUGH THE FLASHBOTS SERVICES IS PROVIDED “AS IS” AND “AS AVAILABLE.” FLASHBOTS DOES NOT WARRANT, AND AFFIRMATIVELY DISCLAIMS, ANY AND ALL WARRANTIES REGARDING, THE ACCURACY, COMPLETENESS OR TIMELINESS OF INFORMATION, TEXT, GRAPHICS, LINKS OR OTHER ITEMS CONTAINED IN THE FLASHBOTS SERVICES. FLASHBOTS PROVIDES NO GUARANTEE AGAINST THE POSSIBILITY OF DELETION, MIS-DELIVERY OR FAILURE TO STORE COMMUNICATIONS, PERSONALIZED SETTINGS, OR OTHER DATA. FLASHBOTS EXPRESSLY DISCLAIMS ALL LIABILITY FOR ERRORS OR OMISSIONS IN, OR THE MISUSE OR MISINTERPRETATION OF, ANY INFORMATION CONTAINED IN THE FLASHBOTS SERVICES OR THE OPERATION THEREOF. FLASHBOTS MAY CHANGE INFORMATION CONTAINED IN THE FLASHBOTS SERVICES AT ANY TIME AND MAKES NO COMMITMENT TO UPDATE THE INFORMATION CONTAINED THEREIN. YOU ASSUME THE ENTIRE RISK AS TO THE USE OF THE FLASHBOTS SERVICES. -SOME STATES DO NOT ALLOW LIMITATIONS ON HOW LONG AN IMPLIED WARRANTY LASTS, SO THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU. YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM STATE TO STATE. - -ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE FLASHBOTS SERVICE IS DONE AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER OR OTHER ELECTRONIC SYSTEM OR LOSS OF DATA THAT RESULTS FROM THE DOWNLOAD OF ANY SUCH MATERIAL. NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED BY YOU THROUGH OR FROM THE FLASHBOTS SERVICE, WILL CREATE ANY WARRANTY NOT EXPRESSLY STATED IN THESE TERMS. +ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF FLASHBOTS SERVICES IS DONE AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER OR OTHER ELECTRONIC SYSTEM OR LOSS OF DATA THAT RESULTS FROM THE DOWNLOAD OF ANY SUCH MATERIAL. NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED BY YOU THROUGH OR FROM THE FLASHBOTS SERVICES, WILL CREATE ANY WARRANTY NOT EXPRESSLY STATED IN THESE TERMS. ### LIMITATION OF LIABILITY -IN NO EVENT SHALL FLASHBOTS BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER, EVEN IF YOU OR THE RELEVANT PARTY HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, RESULTING FROM LOSS FROM YOUR: (I) INABILITY TO USE, (II) USE, AND/OR (III) MISUSE OF, DATA; NOR SHALL FLASHBOTS BE LIABLE FOR ANY LOSS OF PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE FLASHBOTS SERVICE, DOCUMENTS, PROVISION OF OR FAILURE TO PROVIDE SERVICES, OR INFORMATION AVAILABLE RELATED TO THE FLASHBOTS SERVICE. APPLICABLE LAW MAY NOT ALLOW THE LIMITATION OR EXCLUSION OF LIABILITY OR INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATION OR EXCLUSION MAY NOT APPLY TO YOU. +IN NO EVENT SHALL FLASHBOTS PARTIES BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER, EVEN IF ANY OF THE FLASHBOTS PARTIES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, RESULTING FROM LOSS FROM YOUR: (I) INABILITY TO USE, (II) USE, AND/OR (III) MISUSE OF, DATA; NOR SHALL THE FLASHBOTS PARTIES BE LIABLE FOR ANY LOSS OF PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE FLASHBOTS SERVICE, DOCUMENTS, PROVISION OF OR FAILURE TO PROVIDE SERVICES, OR INFORMATION AVAILABLE RELATED TO THE FLASHBOTS SERVICE. -IN NO EVENT WILL FLASHBOTS OR ITS AGENTS, BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY TORT, CONTRACT OR ANY OTHER LIABILITY ARISING IN CONNECTION WITH THE USE OF THE FLASHBOTS SERVICE, OR RELIANCE ON ANY INFORMATION OR SERVICES PROVIDED BY FLASHBOTS. FLASHBOTS AND AGENTS WILL UNDER NO CIRCUMSTANCES BE LIABLE TO YOU AND/OR ANY THIRD PARTY, REGARDLESS OF THE FORM OF ACTION, FOR ANY LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER INTANGIBLE LOSSES, OR ANY DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES WHATSOEVER, EVEN IF FLASHBOTS AND/OR ITS AGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES RESULTING FROM: (I) THE USE OR THE INABILITY TO USE THE FLASHBOTS SERVICE; (II) THE TIMELINESS, DELETION, MISDELIVERY, OR FAILURE TO STORE ANY USER DATA, COMMUNICATIONS OR PERSONALIZATION SETTINGS; (III) THE COST OF GETTING SUBSTITUTE GOODS AND SERVICES RESULTING FROM ANY PRODUCTS, DATA, INFORMATION OR SERVICES PURCHASED OR OBTAINED OR MESSAGES RECEIVED OR TRANSACTIONS ENTERED INTO, THROUGH OR FROM THE FLASHBOTS SERVICE; (IV) UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; (V) STATEMENTS OR CONDUCT OF ANYONE ON THE FLASHBOTS SERVICE; (VI) THE USE, INABILITY TO USE, UNAUTHORIZED USE, PERFORMANCE OR NON-PERFORMANCE OF ANY THIRD PARTY, EVEN IF THE THIRD PARTY HAS BEEN ADVISED PREVIOUSLY OF THE POSSIBILITY OF SUCH DAMAGES; OR (VII) ANY OTHER MATTER RELATING TO THE FLASHBOTS SERVICE. YOU AGREE THAT YOU WILL NOT IN ANY WAY HOLD FLASHBOTS RESPONSIBLE FOR ANY SELECTION OR RETENTION OF, OR THE ACTS OR OMISSIONS OF, THIRD PARTIES IN CONNECTION WITH THE FLASHBOTS SERVICE. +IN NO EVENT WILL THE FLASHBOTS PARTIES BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY TORT, CONTRACT OR ANY OTHER LIABILITY ARISING IN CONNECTION WITH THE USE OF THE FLASHBOTS SERVICE, OR RELIANCE ON ANY INFORMATION OR SERVICES PROVIDED BY FLASHBOTS. THE FLASHBOTS PARTIES WILL UNDER NO CIRCUMSTANCES BE LIABLE TO YOU AND/OR ANY THIRD PARTY, REGARDLESS OF THE FORM OF ACTION, FOR ANY LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER INTANGIBLE LOSSES, OR ANY DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES WHATSOEVER, EVEN IF ANY OF THE FLASHBOTS PARTIES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES RESULTING FROM: (I) THE USE OR THE INABILITY TO USE THE FLASHBOTS SERVICE; (II) THE TIMELINESS, DELETION, MISDELIVERY, OR FAILURE TO STORE ANY USER DATA, COMMUNICATIONS OR PERSONALIZATION SETTINGS; (III) THE COST OF GETTING SUBSTITUTE SERVICES RESULTING FROM ANY PRODUCTS, DATA, INFORMATION OR SERVICES PURCHASED OR OBTAINED OR MESSAGES RECEIVED OR TRANSACTIONS ENTERED INTO, THROUGH OR FROM THE FLASHBOTS SERVICE; (IV) UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; (V) STATEMENTS OR CONDUCT OF ANYONE ON THE FLASHBOTS SERVICE; (VI) THE USE, INABILITY TO USE, UNAUTHORIZED USE, PERFORMANCE OR NON-PERFORMANCE OF ANY THIRD PARTY, EVEN IF THE THIRD PARTY HAS BEEN ADVISED PREVIOUSLY OF THE POSSIBILITY OF SUCH DAMAGES; OR (VII) ANY OTHER MATTER RELATING TO THE FLASHBOTS SERVICE. YOU AGREE THAT YOU WILL NOT IN ANY WAY HOLD THE FLASHBOTS PARTIES RESPONSIBLE FOR ANY SELECTION OR RETENTION OF, OR THE ACTS OR OMISSIONS OF, THIRD PARTIES IN CONNECTION WITH THE FLASHBOTS SERVICE. -Because some states and jurisdictions prohibit the limitation of liability for consequential or incidental damages, in such jurisdictions the limitation of liability only with respect to consequential or incidental damages may not apply to You, and the respective liability of FLASHBOTS and its agents, employees, distributors and agents is limited to the greatest extent allowable under applicable law in those states. +Because some jurisdictions may prohibit limitations of liability for consequential or incidental damages, in such jurisdictions the limitation of liability only with respect to consequential or incidental damages may not apply to You, and the respective liability of the Flashbots Parties shall be limited to the greatest extent allowable under applicable law in those states. -In the event that a court or arbitration panel, as the case may be, should hold that the limitations of liabilities or remedies available as set forth in this Agreement, or any portions thereof, are unenforceable for any reason, or that any of Your remedies under these Terms of Service fail, then You expressly agree that under no circumstances will the total, aggregate liability of FLASHBOTS and its agents, employees, distributors, agents or affiliates, to You or any party claiming by or through You for any cause whatsoever, exceed $100 (U.S.), regardless of the form of action and whether in contract, statute, tort or otherwise. +In the event that a court or arbitration panel, as the case may be, should hold that the limitations of liabilities or remedies available as set forth in this Agreement, or any portions thereof, are unenforceable for any reason, or that any of Your remedies under these Terms of Service fail, then You expressly agree that under no circumstances will the total, aggregate liability of the Flashbots Parties to You or any party claiming by or through You for any cause whatsoever, exceed $100 (U.S.), regardless of the form of action and whether in contract, statute, tort or otherwise. ### LINKS TO THIRD-PARTY SITES -LINKS FOUND IN THE FLASHBOTS SERVICES MAY LET YOU LEAVE THE FLASHBOTS SERVICES TO ENTER OTHER SITES. YOU ACKNOWLEDGE THAT SUCH LINKED SITES ARE NOT UNDER THE CONTROL OF FLASHBOTS, AND FLASHBOTS IS NOT RESPONSIBLE FOR THE CONTENTS OF ANY LINKED SITE OR ANY LINK CONTAINED IN A LINKED SITE, OR ANY CHANGES OR UPDATES TO SUCH SITES. FLASHBOTS IS NOT RESPONSIBLE FOR WEBCASTING OR ANY OTHER FORM OF TRANSMISSION RECEIVED FROM ANY LINKED SITE. FLASHBOTS IS PROVIDING THESE LINKS TO YOU ONLY AS A CONVENIENCE, AND THE INCLUSION OF ANY LINK DOES NOT IMPLY ENDORSEMENT OF THE SITE BY FLASHBOTS. ONCE YOU TRANSFER TO ANOTHER SITE, YOU ARE SUBJECT TO THEIR TERMS OF USE, PRIVACY POLICY AND COOKIE POLICY, IF ANY. +Links found in the Flashbots Services or Flashbots Sites may let you leave the Flashbots Services to enter other sites. You acknowledge that such linked sites are not under the control of FLASHBOTS, and the Flashbots Parties are not responsible for the contents of any linked site or any link contained in a linked site, or any changes or updates to such sites. The Flashbots Parties are not responsible for any form of transmission received from any linked site. FLASHBOTS is providing these links to you only as a convenience, and the inclusion of any link does not imply endorsement of the site by FLASHBOTS. Once you transfer to another site, you are subject to their terms of use, privacy policy and cookie policy, if any. ### INDEMNIFICATION -You agree to defend, indemnify and hold harmless FLASHBOTS, its affiliates and their respective owners, members, directors, officers, employees and agents from and against all Federal, State, and International, claims, demands, losses, costs, and/or expenses, including attorneys’ fees, arising out of the use of the Flashbots Service by You. +You agree to defend, indemnify and hold harmless the Flashbots Parties from and against all federal, state, and international claims, demands, losses, costs, and/or expenses, including attorneys’ fees, arising out of the use of the Flashbots Services by You. By way of clarification and not limitation, you acknowledge that this indemnification applies to each of the Flashbots Parties. ### TERMINATION -FLASHBOTS shall have the right to immediately terminate Your access to the Relay in the event of any conduct by You that FLASHBOTS, in its sole discretion, considers to be unacceptable, or in the event of any breach by You of these Terms of Service. +FLASHBOTS reserves the right to terminate Your access to the Flashbots Services at any time, without notice, for any reason whatsoever, including without limitation, violation of these ToS or the FLASHBOTS POLICIES, or conduct that FLASHBOTS, in its sole discretion, considers to be unacceptable. + +You agree that the Flashbots Parties will not be liable to You or to any third party for any such termination or any suspension, or modification of Your access to the Flashbots Services. + +These Terms of Service shall survive the termination of Your access to the Flashbots Services to the full extent necessary for their enforcement and for the protection of the party in whose favor they operate. + +### TRADEMARKS -### TRADEMARK NOTICE +You will not use any trademarks, service marks, service or trade names, logos, and other designations of Flashbots Parties that we may make available to You or on the Flashbots Sites unless You first obtain our written consent. -The term FLASHBOTS and Flashbots, along with any associated logos, are trademarks of FLASHBOTS and its subsidiaries, all rights reserved. All other trademarks appearing on the Flashbots Website or within the Flashbots Service are the property of their respective owners. +### NOTICE -### PRIVACY POLICY +To You: FLASHBOTS may provide any notice to You under this ToS using commercially reasonable means, including: (i) posting a notice on the Flashbots Sites; (ii) sending a direct message to Your email address or social media account; (iii) posting the notice in the interface of the applicable Flashbots Service, if applicable; or (iv) using public communication channels. Notices we provide by posting on the Flashbots Sites or using public communication channels will be effective upon posting, and notices we provide by direct message will be effective when we send the message. It is Your responsibility to keep Your email and social media contact information current to the extent You use them to communicate with FLASHBOTS. You will be deemed to have received any direct message then associated with Your use of Flashbots Services or Flashbots Sites, whether or not You actually receive the direct message. -To access the Flashbots Service, You agree to our privacy and data security practices when you create an account to access the Flashbots Service and when you accept these Terms of Service. Our privacy and data security practices can be found by visiting our [privacy policy](https://docs.flashbots.net/policies/privacy#contact). +To Us: To give FLASHBOTS notice under these ToS, You must contact FLASHBOTS by email at legal@flashbots.net. For support inquiries, You may contact FLASHBOTS by info@flashbots.net. ### CHOICE OF LAW -These Terms of Service are governed by and construed in accordance with the laws of the Cayman Islands, excluding that body of laws pertaining to conflict of laws. If any provision of these Terms of Service is determined by a court of law to be illegal or unenforceable, such provision will be enforced to the maximum extent possible and the other provisions will remain effective and enforceable. +These Terms of Service and any access or use of the Flashbots Services are governed by and construed in accordance with the laws of the Cayman Islands, excluding that body of laws pertaining to conflict of laws. If any provision of these Terms of Service is determined by a competent court of law to be illegal or unenforceable, such provision will be enforced to the maximum extent possible and the other provisions will remain effective and enforceable. ### DISPUTE RESOLUTION -Except to the extent applicable law provides otherwise, these Terms of Service and any access to or use of the Flashbots Service will be governed by the laws of the Cayman Islands, without regard to the conflict of laws rules thereof. All disputes of any nature related to these Terms of Service shall be determined by final and binding arbitration in the Cayman Islands before a single arbitrator. The parties shall agree on the rules and procedures to be followed in the arbitration. Unless otherwise agreed in writing between the parties, the arbitration shall be administered by JAMS pursuant to its Streamlined Arbitration Rules and Procedures, and the arbitrator shall apply the laws applicable in the Cayman Islands (without regard to the conflict of laws rules thereof). Judgment on the arbitral award may be entered in any court having jurisdiction thereof. The foregoing arbitration provisions shall not preclude either party from seeking an injunction or other provisional remedies in aid of arbitration from a court of appropriate jurisdiction. The arbitrator shall, in the arbitral award, allocate all or part of the costs of the arbitration, including the fees of the arbitrator and reasonable attorneys’ fees of the prevailing party, for payment by the non-prevailing party, and shall determine the prevailing party for this purpose. The parties further agree that (i) any claims brought by either party must be brought in such party’s individual capacity and not as a plaintiff or class member in any purported class or representative proceeding, and (ii) the arbitrator may not (x) consolidate more than one person’s claims, (y) otherwise preside over any form of a representative or class proceeding or (z) award class-wide relief. BY AGREEING TO THESE TERMS OF SERVICE YOU WAIVE ANY RIGHT TO TRIAL BY JURY. +THIS SECTION MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS. BY AGREEING TO THESE TERMS OF SERVICE YOU WAIVE ANY RIGHT TO TRIAL BY JURY AND A WAIVER OF CLASS ACTIONS. + +Any dispute, controversy or claim arising out of or relating to these Terms of Service, including the formation, interpretation, breach or termination thereof, including whether the claims asserted are arbitrable, will be referred to and finally determined by arbitration in accordance with the JAMS International Arbitration Rules. The Tribunal will consist of one arbitrator. The place of arbitration will be London, United Kingdom. The language to be used in the arbitral proceedings will be English. Judgment upon the award rendered by the arbitrator(s) may be entered in any court having jurisdiction thereof. Unless otherwise agreed in writing between the parties, the arbitration shall be administered by the JAMS in accordance with JAMS International Arbitration Rules, The arbitrator shall apply the laws applicable in the Cayman Islands (without regard to the conflict of laws rules thereof). Judgment on the arbitral award may be entered in any court having jurisdiction thereof. The foregoing arbitration provisions shall not preclude either party from seeking an injunction or other provisional remedies in aid of arbitration from a court of appropriate jurisdiction. The arbitrator shall, in the arbitral award, allocate all or part of the costs of the arbitration, including the fees of the arbitrator and reasonable attorneys’ fees of the prevailing party, for payment by the non-prevailing party, and shall determine the prevailing party for this purpose. The parties further agree that (i) any claims brought by either party must be brought in such party’s individual capacity and not as a plaintiff or class member in any purported class or representative proceeding, and (ii) the arbitrator may not (x) consolidate more than one person’s claims, (y) otherwise preside over any form of a representative or class proceeding or (z) award class-wide relief. + +YOU AGREE THAT YOU MAY BRING CLAIMS AGAINST THE FLASHBOTS PARTIES ONLY ON AN INDIVIDUAL BASIS, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING. YOU AND THE FLASHBOTS PARTIES EXPRESSLY WAIVES ANY RIGHT TO FILE A CLASS ACTION OR SEEK RELIEF ON A CLASS BASIS. + +--- -### CONTACT +### FLASHBOTS POLICIES APPENDIX -If you have questions about these Terms of Service, You can contact us by email at legal@flashbots.net +[Prohibited Use Policy](/policies/prohibited-use-policy) \ No newline at end of file diff --git a/docs/sidebars.js b/docs/sidebars.js index 59102431..fdf0d28a 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -1,143 +1,164 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ module.exports = { docs: [ { - "welcome": [ - 'welcome', 'new-to-mev', 'code-of-conduct' + "Welcome": [ + 'welcome', 'new-to-mev', 'code-of-conduct', 'guide-send-tx-bundle' ], }, { - 'flashbots auction': [ + 'Flashbots Builders': [ 'flashbots-auction/overview', + 'flashbots-auction/quick-start', { - "for searchers": [ - 'flashbots-auction/searchers/quick-start', - 'flashbots-auction/searchers/faq', - { - "advanced concepts": [ - 'flashbots-auction/searchers/advanced/understanding-bundles', - 'flashbots-auction/searchers/advanced/coinbase-payment', - 'flashbots-auction/searchers/advanced/bundle-pricing', - 'flashbots-auction/searchers/advanced/rpc-endpoint', - 'flashbots-auction/searchers/advanced/reputation', - 'flashbots-auction/searchers/advanced/goerli-testnet', - 'flashbots-auction/searchers/advanced/eip1559', - 'flashbots-auction/searchers/advanced/troubleshooting', - 'flashbots-auction/searchers/advanced/private-transaction' - ], - "example searchers": [ - 'flashbots-auction/searchers/example-searchers/simple-arbitrage-bot', - 'flashbots-auction/searchers/example-searchers/searcher-sponsored-tx', - 'flashbots-auction/searchers/example-searchers/searcher-minter', - 'flashbots-auction/searchers/example-searchers/synthetix-searcher', - - - ], - "libraries": [ - 'flashbots-auction/searchers/libraries/golang', - 'flashbots-auction/searchers/libraries/ethers-js-provider', - 'flashbots-auction/searchers/libraries/web3py-provider', - ] - }, - 'flashbots-auction/other-resources' + "Example Searchers": [ + 'flashbots-auction/example-searchers/simple-arbitrage-bot', + 'flashbots-auction/example-searchers/searcher-sponsored-tx', + 'flashbots-auction/example-searchers/searcher-minter', + 'flashbots-auction/example-searchers/synthetix-searcher', ], - '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', - ] - }, - ], - }, + "Libraries": [ + 'flashbots-auction/libraries/bundle-relay', + 'flashbots-auction/libraries/mev-share-clients', + 'flashbots-auction/libraries/golang', + 'flashbots-auction/libraries/ethers-js-provider', + 'flashbots-auction/libraries/web3py-provider', + 'flashbots-auction/libraries/alchemyprovider', + 'flashbots-auction/libraries/rust-provider', ], - 'releases': [ - 'flashbots-auction/releases/alpha-v0.6', - 'flashbots-auction/releases/alpha-v0.5', - 'flashbots-auction/releases/alpha-v0.4', - 'flashbots-auction/releases/alpha-v0.3', - 'flashbots-auction/releases/alpha-v0.2', - 'flashbots-auction/releases/upgrade-process', - + "Advanced Concepts": [ + 'flashbots-auction/advanced/understanding-bundles', + 'flashbots-auction/advanced/multiplexing', + 'flashbots-auction/advanced/gas-fee-refunds', + 'flashbots-auction/advanced/coinbase-payment', + 'flashbots-auction/advanced/bundle-pricing', + 'flashbots-auction/advanced/reputation', + 'flashbots-auction/advanced/testnets', + 'flashbots-auction/advanced/eip1559', + 'flashbots-auction/advanced/troubleshooting', + 'flashbots-auction/advanced/bundle-cancellations', + 'flashbots-auction/advanced/co-locate', ], }, + 'flashbots-auction/faq', + 'flashbots-auction/other-resources', ] }, { - "flashbots data": [ + "Flashbots Protect": [ + 'flashbots-protect/overview', + 'flashbots-protect/quick-start', + 'flashbots-protect/mev-refunds', + 'flashbots-protect/gas-fee-refunds', + 'flashbots-protect/settings-guide', + 'flashbots-protect/cancellations', + 'flashbots-protect/nonce-management', + 'flashbots-protect/stuck_transactions', + 'flashbots-protect/large-transactions', + 'flashbots-protect/ratelimiting', { - 'mev-inspect': [ - 'flashbots-data/mev-inspect-py/overview', - 'flashbots-data/mev-inspect-py/install', - 'flashbots-data/mev-inspect-py/quick-start', - 'flashbots-data/mev-inspect-py/inspecting', - 'flashbots-data/mev-inspect-py/exploring', - { - "data": [ - 'flashbots-data/mev-inspect-py/data/classified_traces', - 'flashbots-data/mev-inspect-py/data/transfers', - 'flashbots-data/mev-inspect-py/data/swaps', - 'flashbots-data/mev-inspect-py/data/arbitrages', - 'flashbots-data/mev-inspect-py/data/miner_payments', - ], - }, + 'Additional Documentation': [ + 'flashbots-protect/additional-documentation/eth-sendPrivateTransaction', + ], + } + ], + }, + { + "MEV-Boost": [ + 'flashbots-mev-boost/introduction', + { + 'Architecture Overview': [ + 'flashbots-mev-boost/architecture-overview/specifications', + 'flashbots-mev-boost/architecture-overview/block-proposal', + 'flashbots-mev-boost/architecture-overview/risks' + ] + }, + + 'flashbots-mev-boost/block-builders', + 'flashbots-mev-boost/block-proposers', + 'flashbots-mev-boost/relay', + { + 'Getting Started':[ + 'flashbots-mev-boost/getting-started/system-requirements', + 'flashbots-mev-boost/getting-started/installation', + 'flashbots-mev-boost/getting-started/usage', ] }, - 'flashbots-data/blockapi', - 'flashbots-data/mev-explore', - 'flashbots-data/dashboard', + '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 protect": [ - 'flashbots-protect/overview', + "MEV-Share": [ + 'flashbots-mev-share/introduction', + 'flashbots-mev-share/for-users', + 'flashbots-mev-share/orderflow-providers', { - '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', - 'flashbots-protect/rpc/ratelimiting', - 'flashbots-protect/rpc/cancellations', - 'flashbots-protect/rpc/releases', + 'For Searchers': [ + 'flashbots-mev-share/searchers/getting-started', + 'flashbots-mev-share/searchers/event-stream', + 'flashbots-mev-share/searchers/understanding-bundles', + 'flashbots-mev-share/searchers/sending-bundles', + 'flashbots-mev-share/searchers/debugging', + 'flashbots-mev-share/searchers/ratelimiting', + { + 'Tutorials': [ + { + 'Limit Order Bot': [ + 'flashbots-mev-share/searchers/tutorials/limit-order/introduction', + 'flashbots-mev-share/searchers/tutorials/limit-order/setup', + 'flashbots-mev-share/searchers/tutorials/limit-order/using-events', + 'flashbots-mev-share/searchers/tutorials/limit-order/sending-bundles', + 'flashbots-mev-share/searchers/tutorials/limit-order/debugging', + 'flashbots-mev-share/searchers/tutorials/limit-order/more-resources' + ], + 'Flash Loan Arbitrage Bot': [ + 'flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/introduction', + 'flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/simple-blind-arbitrage', + 'flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/flash-loan-basics', + 'flashbots-mev-share/searchers/tutorials/flash-loan-arbitrage/bot', + ] + } + ] + } + ], + 'Release Notes': [ + 'flashbots-mev-share/release-notes/2023-03', + 'flashbots-mev-share/release-notes/2023-06', + 'flashbots-mev-share/release-notes/2023-07', + 'flashbots-mev-share/release-notes/2023-09' ] } - ], + ] }, { - "community": [ + "Community": [ 'community-tools', 'whitehat', ], }, { - "contribute": [ + "Contribute": [ 'joining-flashbots', 'contribution-guide', 'cheatsheet', ], }, + { + type: 'link', + label: 'Forum', + href: 'https://collective.flashbots.net/', + }, { type: 'link', label: 'Discord', - href: 'https://discord.gg/7hvTycdNcK', + href: 'https://discord.gg/flashbots', }, { type: 'link', @@ -149,6 +170,11 @@ module.exports = { href: 'https://status.flashbots.net/', label: 'Status', }, - 'policies/privacy','policies/terms-of-service', + 'policies/privacy','policies/terms-of-service', 'policies/prohibited-use-policy', 'brand-assets', ], + api: [ + "flashbots-auction/advanced/rpc-endpoint", + "flashbots-protect/additional-documentation/status-api", + "flashbots-protect/additional-documentation/bundle-cache", + ] }; diff --git a/docs/specs/README.md b/docs/specs/README.md new file mode 100644 index 00000000..396b8e9a --- /dev/null +++ b/docs/specs/README.md @@ -0,0 +1,17 @@ +# specs + +Commonly used bits of information ("specs") live here so that they can be reused. + +To use a spec in an mdx file: + +```mdx +import SomeSpec from "../relative/path/to/_file.mdx" + +## We include the specification again + +You may recall that this specification has been mentioned in many places, and due to its DRYness, has always accurately reflected the truth: + + +``` + +> :information_source: Note that the spec file is prefixed with an underscore. This lets Docusaurus know that it's a spec, and allows us to use it in our markdown files like a React component. diff --git a/docs/specs/contracts/abi/_flashLoanArb.mdx b/docs/specs/contracts/abi/_flashLoanArb.mdx new file mode 100644 index 00000000..5f91038b --- /dev/null +++ b/docs/specs/contracts/abi/_flashLoanArb.mdx @@ -0,0 +1,3 @@ +```json title="abi/blindBackrunFlashLoan.json" +{ "abi": [ { "inputs": [ { "internalType": "address", "name": "_wethAddress", "type": "address" } ], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "inputs": [], "name": "WETH_ADDRESS", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address payable", "name": "_to", "type": "address" }, { "internalType": "uint256", "name": "_value", "type": "uint256" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "name": "call", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "firstPairAddress", "type": "address" }, { "internalType": "address", "name": "secondPairAddress", "type": "address" }, { "internalType": "uint256", "name": "percentageToPayToCoinbase", "type": "uint256" }, { "internalType": "address", "name": "recipient", "type": "address" } ], "name": "executeArbitrage", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ], "internalType": "struct IPairReserves.PairReserves", "name": "firstPairData", "type": "tuple" }, { "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ], "internalType": "struct IPairReserves.PairReserves", "name": "secondPairData", "type": "tuple" } ], "name": "getAmountIn", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ], "internalType": "struct IPairReserves.PairReserves", "name": "firstPairData", "type": "tuple" }, { "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ], "internalType": "struct IPairReserves.PairReserves", "name": "secondPairData", "type": "tuple" } ], "name": "getDenominator", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ], "internalType": "struct IPairReserves.PairReserves", "name": "firstPairData", "type": "tuple" }, { "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ], "internalType": "struct IPairReserves.PairReserves", "name": "secondPairData", "type": "tuple" } ], "name": "getNumerator", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "contract IERC20[]", "name": "tokens", "type": "address[]" }, { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" }, { "internalType": "bytes", "name": "userData", "type": "bytes" } ], "name": "makeFlashLoan", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "contract IERC20[]", "name": "tokens", "type": "address[]" }, { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" }, { "internalType": "uint256[]", "name": "feeAmounts", "type": "uint256[]" }, { "internalType": "bytes", "name": "userData", "type": "bytes" } ], "name": "receiveFlashLoan", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "withdrawETHToOwner", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "withdrawWETHToOwner", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "stateMutability": "payable", "type": "receive" } ], "bytecode": { "object": "0x60a06040526103e560015534801561001657600080fd5b50604051611a56380380611a56833981016040819052610035916100a1565b8061003f33610051565b6001600160a01b0316608052506100d1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156100b357600080fd5b81516001600160a01b03811681146100ca57600080fd5b9392505050565b60805161192b61012b600039600081816101370152818161039101528181610457015281816106d8015281816107d50152818161087101528181610b5401528181610be601528181610d380152610fd5015261192b6000f3fe6080604052600436106100c45760003560e01c806377432b8c1161007f578063ea3e506c11610059578063ea3e506c14610219578063eb6b21161461022e578063f04f27071461024e578063f2fde38b1461026e57600080fd5b806377432b8c146101c65780638da5cb5b146101db578063c9a69562146101f957600080fd5b8062bb7d67146100d0578062fb430414610103578063040141e5146101255780631fa7d39b146101715780636dbf2fa014610191578063715018a6146101b157600080fd5b366100cb57005b600080fd5b3480156100dc57600080fd5b506100f06100eb366004611290565b61028e565b6040519081526020015b60405180910390f35b34801561010f57600080fd5b5061012361011e3660046112db565b610379565b005b34801561013157600080fd5b506101597f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100fa565b34801561017d57600080fd5b506100f061018c366004611290565b610922565b34801561019d57600080fd5b506101236101ac36600461139e565b6109b6565b3480156101bd57600080fd5b50610123610a69565b3480156101d257600080fd5b50610123610a7d565b3480156101e757600080fd5b506000546001600160a01b0316610159565b34801561020557600080fd5b506101236102143660046114ea565b610ab8565b34801561022557600080fd5b50610123610b34565b34801561023a57600080fd5b506100f0610249366004611290565b610c5b565b34801561025a57600080fd5b50610123610269366004611568565b610c94565b34801561027a57600080fd5b50610123610289366004611615565b610e33565b606082015160009015156001036103175760006102e484600001516102de85602001516102de87600001516102d88a602001516102d8600154600154610eac90919063ffffffff16565b90610eac565b90610ebf565b9050600061030d85600001516102d886602001516102d86103e861030788610ecb565b90610f17565b9250610373915050565b600061035084602001516102de85600001516102de87602001516102d88a600001516102d8600154600154610eac90919063ffffffff16565b9050600061030d85602001516102d886600001516102d86103e861030788610ecb565b92915050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156103e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104049190611632565b90508484600061041383610f23565b9050600061042083610f23565b9050600061042e8383610c5b565b60405163a9059cbb60e01b81526001600160a01b038c81166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af11580156104a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c6919061164b565b506000808460600151151560011515036105cf576104ed83866000015187602001516110cd565b915061050282856020015186600001516110cd565b9050866001600160a01b031663022c0d9f6000848e6040518463ffffffff1660e01b815260040161053593929190611668565b600060405180830381600087803b15801561054f57600080fd5b505af1158015610563573d6000803e3d6000fd5b505060405163022c0d9f60e01b81526001600160a01b038916925063022c0d9f91506105989084906000903090600401611668565b600060405180830381600087803b1580156105b257600080fd5b505af11580156105c6573d6000803e3d6000fd5b505050506106c0565b6105e283866020015187600001516110cd565b91506105f782856000015186602001516110cd565b9050866001600160a01b031663022c0d9f8360008e6040518463ffffffff1660e01b815260040161062a93929190611668565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b505060405163022c0d9f60e01b81526001600160a01b038916925063022c0d9f915061068d9060009085903090600401611668565b600060405180830381600087803b1580156106a757600080fd5b505af11580156106bb573d6000803e3d6000fd5b505050505b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074b9190611632565b90508881116107945760405162461bcd60e51b815260206004820152601060248201526f105c989a5d1c9859d94819985a5b195960821b60448201526064015b60405180910390fd5b60006107a0828b610f17565b905060006107bc60646102de8f85610eac90919063ffffffff16565b604051632e1a7d4d60e01b8152600481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561082157600080fd5b505af1158015610835573d6000803e3d6000fd5b505060405141925083156108fc02915083906000818181858888f19350505050158015610866573d6000803e3d6000fd5b506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663a9059cbb8d6108a18585610f17565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af11580156108ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610910919061164b565b50505050505050505050505050505050565b6060820151600090151560010361098557600061097c61095785602001516102d8600154600154610eac90919063ffffffff16565b6109766103e86102d88760200151600154610eac90919063ffffffff16565b90611115565b91506103739050565b825160015460009161097c916109a091906102d89080610eac565b8451600154610976916103e8916102d891610eac565b6109be611121565b6000836001600160a01b031683836040516109d991906116ba565b60006040518083038185875af1925050503d8060008114610a16576040519150601f19603f3d011682016040523d82523d6000602084013e610a1b565b606091505b5050905080610a635760405162461bcd60e51b8152602060048201526014602482015273115e1d195c9b985b0818d85b1b0819985a5b195960621b604482015260640161078b565b50505050565b610a71611121565b610a7b600061117b565b565b610a85611121565b6040514790339082156108fc029083906000818181858888f19350505050158015610ab4573d6000803e3d6000fd5b5050565b610ac0611121565b604051632e1c224f60e11b815273ba12222222228d8ba445958a75a0704d566bf2c890635c38449e90610afd903090879087908790600401611702565b600060405180830381600087803b158015610b1757600080fd5b505af1158015610b2b573d6000803e3d6000fd5b50505050505050565b610b3c611121565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610ba3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc79190611632565b60405163a9059cbb60e01b8152336004820152602481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610c37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab4919061164b565b600080610c68848461028e565b90506000610c768585610922565b90506000610c8a826102de856103e8610eac565b9695505050505050565b3373ba12222222228d8ba445958a75a0704d566bf2c814610d0b5760405162461bcd60e51b815260206004820152602b60248201527f466c6173684c6f616e526563697069656e743a2063616c6c6572206973206e6f60448201526a1d081d1a19481d985d5b1d60aa1b606482015260840161078b565b600080600083806020019051810190610d24919061179e565b925092509250610d3682848330610379565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb73ba12222222228d8ba445958a75a0704d566bf2c887600081518110610d8d57610d8d6117e1565b602002602001015189600081518110610da857610da86117e1565b6020026020010151610dba919061180d565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e29919061164b565b5050505050505050565b610e3b611121565b6001600160a01b038116610ea05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161078b565b610ea98161117b565b50565b6000610eb88284611820565b9392505050565b6000610eb88284611837565b600081600003610edd57506000919050565b6000610eef60026102de856001611115565b9050825b80821015610eb8575080610f1060026102de836109768882610ebf565b9150610ef3565b6000610eb88284611859565b610f5060405180608001604052806000815260200160008152602001600081526020016000151581525090565b600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb59190611888565b506001600160701b031691506001600160701b03169150600080600090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561103b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105f91906118d8565b6001600160a01b03160361108e57611083846102de85670de0b6b3a7640000610eac565b9150600190506110a7565b6110a4836102de86670de0b6b3a7640000610eac565b91505b604080516080810182529485526020850193909352918301521515606082015292915050565b6000806110dc856103e5610eac565b905060006110ea8285610eac565b905060006110fe83610976886103e8610eac565b905061110a8183611837565b979650505050505050565b6000610eb8828461180d565b6000546001600160a01b03163314610a7b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161078b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561120a5761120a6111cb565b604052919050565b8015158114610ea957600080fd5b60006080828403121561123257600080fd5b6040516080810181811067ffffffffffffffff82111715611255576112556111cb565b8060405250809150823581526020830135602082015260408301356040820152606083013561128381611212565b6060919091015292915050565b60008061010083850312156112a457600080fd5b6112ae8484611220565b91506112bd8460808501611220565b90509250929050565b6001600160a01b0381168114610ea957600080fd5b600080600080608085870312156112f157600080fd5b84356112fc816112c6565b9350602085013561130c816112c6565b9250604085013591506060850135611323816112c6565b939692955090935050565b600082601f83011261133f57600080fd5b813567ffffffffffffffff811115611359576113596111cb565b61136c601f8201601f19166020016111e1565b81815284602083860101111561138157600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000606084860312156113b357600080fd5b83356113be816112c6565b925060208401359150604084013567ffffffffffffffff8111156113e157600080fd5b6113ed8682870161132e565b9150509250925092565b600067ffffffffffffffff821115611411576114116111cb565b5060051b60200190565b600082601f83011261142c57600080fd5b8135602061144161143c836113f7565b6111e1565b82815260059290921b8401810191818101908684111561146057600080fd5b8286015b84811015611484578035611477816112c6565b8352918301918301611464565b509695505050505050565b600082601f8301126114a057600080fd5b813560206114b061143c836113f7565b82815260059290921b840181019181810190868411156114cf57600080fd5b8286015b8481101561148457803583529183019183016114d3565b6000806000606084860312156114ff57600080fd5b833567ffffffffffffffff8082111561151757600080fd5b6115238783880161141b565b9450602086013591508082111561153957600080fd5b6115458783880161148f565b9350604086013591508082111561155b57600080fd5b506113ed8682870161132e565b6000806000806080858703121561157e57600080fd5b843567ffffffffffffffff8082111561159657600080fd5b6115a28883890161141b565b955060208701359150808211156115b857600080fd5b6115c48883890161148f565b945060408701359150808211156115da57600080fd5b6115e68883890161148f565b935060608701359150808211156115fc57600080fd5b506116098782880161132e565b91505092959194509250565b60006020828403121561162757600080fd5b8135610eb8816112c6565b60006020828403121561164457600080fd5b5051919050565b60006020828403121561165d57600080fd5b8151610eb881611212565b92835260208301919091526001600160a01b0316604082015260806060820181905260009082015260a00190565b60005b838110156116b1578181015183820152602001611699565b50506000910152565b600082516116cc818460208701611696565b9190910192915050565b600081518084526116ee816020860160208601611696565b601f01601f19169290920160200192915050565b6001600160a01b0385811682526080602080840182905286519184018290526000928782019290919060a0860190855b81811015611750578551851683529483019491830191600101611732565b5050858103604087015287518082529082019350915080870160005b838110156117885781518552938201939082019060010161176c565b50505050828103606084015261110a81856116d6565b6000806000606084860312156117b357600080fd5b83516117be816112c6565b60208501519093506117cf816112c6565b80925050604084015190509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610373576103736117f7565b8082028115828204841417610373576103736117f7565b60008261185457634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610373576103736117f7565b80516001600160701b038116811461188357600080fd5b919050565b60008060006060848603121561189d57600080fd5b6118a68461186c565b92506118b46020850161186c565b9150604084015163ffffffff811681146118cd57600080fd5b809150509250925092565b6000602082840312156118ea57600080fd5b8151610eb8816112c656fea2646970667358221220676487a1d86f39c43717d6d35a54a941fb253b31450166709b652d8163b2b26464736f6c63430008130033", "sourceMap": "1103:1241:26:-:0;;;941:3:23;918:26;;1267:63:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1314:12;936:32:0;719:10:4;936:18:0;:32::i;:::-;-1:-1:-1;;;;;1039:27:23;;;-1:-1:-1;1103:1241:26;;2426:187:0;2499:16;2518:6;;-1:-1:-1;;;;;2534:17:0;;;-1:-1:-1;;;;;;2534:17:0;;;;;;2566:40;;2518:6;;;;;;;2566:40;;2499:16;2566:40;2489:124;2426:187;:::o;14:290:28:-;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:28;;214:42;;204:70;;270:1;267;260:12;204:70;293:5;14:290;-1:-1:-1;;;14:290:28:o;:::-;1103:1241:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", "linkReferences": {} }, "deployedBytecode": { "object": "0x6080604052600436106100c45760003560e01c806377432b8c1161007f578063ea3e506c11610059578063ea3e506c14610219578063eb6b21161461022e578063f04f27071461024e578063f2fde38b1461026e57600080fd5b806377432b8c146101c65780638da5cb5b146101db578063c9a69562146101f957600080fd5b8062bb7d67146100d0578062fb430414610103578063040141e5146101255780631fa7d39b146101715780636dbf2fa014610191578063715018a6146101b157600080fd5b366100cb57005b600080fd5b3480156100dc57600080fd5b506100f06100eb366004611290565b61028e565b6040519081526020015b60405180910390f35b34801561010f57600080fd5b5061012361011e3660046112db565b610379565b005b34801561013157600080fd5b506101597f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100fa565b34801561017d57600080fd5b506100f061018c366004611290565b610922565b34801561019d57600080fd5b506101236101ac36600461139e565b6109b6565b3480156101bd57600080fd5b50610123610a69565b3480156101d257600080fd5b50610123610a7d565b3480156101e757600080fd5b506000546001600160a01b0316610159565b34801561020557600080fd5b506101236102143660046114ea565b610ab8565b34801561022557600080fd5b50610123610b34565b34801561023a57600080fd5b506100f0610249366004611290565b610c5b565b34801561025a57600080fd5b50610123610269366004611568565b610c94565b34801561027a57600080fd5b50610123610289366004611615565b610e33565b606082015160009015156001036103175760006102e484600001516102de85602001516102de87600001516102d88a602001516102d8600154600154610eac90919063ffffffff16565b90610eac565b90610ebf565b9050600061030d85600001516102d886602001516102d86103e861030788610ecb565b90610f17565b9250610373915050565b600061035084602001516102de85600001516102de87602001516102d88a600001516102d8600154600154610eac90919063ffffffff16565b9050600061030d85602001516102d886600001516102d86103e861030788610ecb565b92915050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156103e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104049190611632565b90508484600061041383610f23565b9050600061042083610f23565b9050600061042e8383610c5b565b60405163a9059cbb60e01b81526001600160a01b038c81166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af11580156104a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c6919061164b565b506000808460600151151560011515036105cf576104ed83866000015187602001516110cd565b915061050282856020015186600001516110cd565b9050866001600160a01b031663022c0d9f6000848e6040518463ffffffff1660e01b815260040161053593929190611668565b600060405180830381600087803b15801561054f57600080fd5b505af1158015610563573d6000803e3d6000fd5b505060405163022c0d9f60e01b81526001600160a01b038916925063022c0d9f91506105989084906000903090600401611668565b600060405180830381600087803b1580156105b257600080fd5b505af11580156105c6573d6000803e3d6000fd5b505050506106c0565b6105e283866020015187600001516110cd565b91506105f782856000015186602001516110cd565b9050866001600160a01b031663022c0d9f8360008e6040518463ffffffff1660e01b815260040161062a93929190611668565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b505060405163022c0d9f60e01b81526001600160a01b038916925063022c0d9f915061068d9060009085903090600401611668565b600060405180830381600087803b1580156106a757600080fd5b505af11580156106bb573d6000803e3d6000fd5b505050505b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074b9190611632565b90508881116107945760405162461bcd60e51b815260206004820152601060248201526f105c989a5d1c9859d94819985a5b195960821b60448201526064015b60405180910390fd5b60006107a0828b610f17565b905060006107bc60646102de8f85610eac90919063ffffffff16565b604051632e1a7d4d60e01b8152600481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561082157600080fd5b505af1158015610835573d6000803e3d6000fd5b505060405141925083156108fc02915083906000818181858888f19350505050158015610866573d6000803e3d6000fd5b506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663a9059cbb8d6108a18585610f17565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af11580156108ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610910919061164b565b50505050505050505050505050505050565b6060820151600090151560010361098557600061097c61095785602001516102d8600154600154610eac90919063ffffffff16565b6109766103e86102d88760200151600154610eac90919063ffffffff16565b90611115565b91506103739050565b825160015460009161097c916109a091906102d89080610eac565b8451600154610976916103e8916102d891610eac565b6109be611121565b6000836001600160a01b031683836040516109d991906116ba565b60006040518083038185875af1925050503d8060008114610a16576040519150601f19603f3d011682016040523d82523d6000602084013e610a1b565b606091505b5050905080610a635760405162461bcd60e51b8152602060048201526014602482015273115e1d195c9b985b0818d85b1b0819985a5b195960621b604482015260640161078b565b50505050565b610a71611121565b610a7b600061117b565b565b610a85611121565b6040514790339082156108fc029083906000818181858888f19350505050158015610ab4573d6000803e3d6000fd5b5050565b610ac0611121565b604051632e1c224f60e11b815273ba12222222228d8ba445958a75a0704d566bf2c890635c38449e90610afd903090879087908790600401611702565b600060405180830381600087803b158015610b1757600080fd5b505af1158015610b2b573d6000803e3d6000fd5b50505050505050565b610b3c611121565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610ba3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc79190611632565b60405163a9059cbb60e01b8152336004820152602481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610c37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab4919061164b565b600080610c68848461028e565b90506000610c768585610922565b90506000610c8a826102de856103e8610eac565b9695505050505050565b3373ba12222222228d8ba445958a75a0704d566bf2c814610d0b5760405162461bcd60e51b815260206004820152602b60248201527f466c6173684c6f616e526563697069656e743a2063616c6c6572206973206e6f60448201526a1d081d1a19481d985d5b1d60aa1b606482015260840161078b565b600080600083806020019051810190610d24919061179e565b925092509250610d3682848330610379565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb73ba12222222228d8ba445958a75a0704d566bf2c887600081518110610d8d57610d8d6117e1565b602002602001015189600081518110610da857610da86117e1565b6020026020010151610dba919061180d565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e29919061164b565b5050505050505050565b610e3b611121565b6001600160a01b038116610ea05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161078b565b610ea98161117b565b50565b6000610eb88284611820565b9392505050565b6000610eb88284611837565b600081600003610edd57506000919050565b6000610eef60026102de856001611115565b9050825b80821015610eb8575080610f1060026102de836109768882610ebf565b9150610ef3565b6000610eb88284611859565b610f5060405180608001604052806000815260200160008152602001600081526020016000151581525090565b600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb59190611888565b506001600160701b031691506001600160701b03169150600080600090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561103b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105f91906118d8565b6001600160a01b03160361108e57611083846102de85670de0b6b3a7640000610eac565b9150600190506110a7565b6110a4836102de86670de0b6b3a7640000610eac565b91505b604080516080810182529485526020850193909352918301521515606082015292915050565b6000806110dc856103e5610eac565b905060006110ea8285610eac565b905060006110fe83610976886103e8610eac565b905061110a8183611837565b979650505050505050565b6000610eb8828461180d565b6000546001600160a01b03163314610a7b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161078b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561120a5761120a6111cb565b604052919050565b8015158114610ea957600080fd5b60006080828403121561123257600080fd5b6040516080810181811067ffffffffffffffff82111715611255576112556111cb565b8060405250809150823581526020830135602082015260408301356040820152606083013561128381611212565b6060919091015292915050565b60008061010083850312156112a457600080fd5b6112ae8484611220565b91506112bd8460808501611220565b90509250929050565b6001600160a01b0381168114610ea957600080fd5b600080600080608085870312156112f157600080fd5b84356112fc816112c6565b9350602085013561130c816112c6565b9250604085013591506060850135611323816112c6565b939692955090935050565b600082601f83011261133f57600080fd5b813567ffffffffffffffff811115611359576113596111cb565b61136c601f8201601f19166020016111e1565b81815284602083860101111561138157600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000606084860312156113b357600080fd5b83356113be816112c6565b925060208401359150604084013567ffffffffffffffff8111156113e157600080fd5b6113ed8682870161132e565b9150509250925092565b600067ffffffffffffffff821115611411576114116111cb565b5060051b60200190565b600082601f83011261142c57600080fd5b8135602061144161143c836113f7565b6111e1565b82815260059290921b8401810191818101908684111561146057600080fd5b8286015b84811015611484578035611477816112c6565b8352918301918301611464565b509695505050505050565b600082601f8301126114a057600080fd5b813560206114b061143c836113f7565b82815260059290921b840181019181810190868411156114cf57600080fd5b8286015b8481101561148457803583529183019183016114d3565b6000806000606084860312156114ff57600080fd5b833567ffffffffffffffff8082111561151757600080fd5b6115238783880161141b565b9450602086013591508082111561153957600080fd5b6115458783880161148f565b9350604086013591508082111561155b57600080fd5b506113ed8682870161132e565b6000806000806080858703121561157e57600080fd5b843567ffffffffffffffff8082111561159657600080fd5b6115a28883890161141b565b955060208701359150808211156115b857600080fd5b6115c48883890161148f565b945060408701359150808211156115da57600080fd5b6115e68883890161148f565b935060608701359150808211156115fc57600080fd5b506116098782880161132e565b91505092959194509250565b60006020828403121561162757600080fd5b8135610eb8816112c6565b60006020828403121561164457600080fd5b5051919050565b60006020828403121561165d57600080fd5b8151610eb881611212565b92835260208301919091526001600160a01b0316604082015260806060820181905260009082015260a00190565b60005b838110156116b1578181015183820152602001611699565b50506000910152565b600082516116cc818460208701611696565b9190910192915050565b600081518084526116ee816020860160208601611696565b601f01601f19169290920160200192915050565b6001600160a01b0385811682526080602080840182905286519184018290526000928782019290919060a0860190855b81811015611750578551851683529483019491830191600101611732565b5050858103604087015287518082529082019350915080870160005b838110156117885781518552938201939082019060010161176c565b50505050828103606084015261110a81856116d6565b6000806000606084860312156117b357600080fd5b83516117be816112c6565b60208501519093506117cf816112c6565b80925050604084015190509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610373576103736117f7565b8082028115828204841417610373576103736117f7565b60008261185457634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610373576103736117f7565b80516001600160701b038116811461188357600080fd5b919050565b60008060006060848603121561189d57600080fd5b6118a68461186c565b92506118b46020850161186c565b9150604084015163ffffffff811681146118cd57600080fd5b809150509250925092565b6000602082840312156118ea57600080fd5b8151610eb8816112c656fea2646970667358221220676487a1d86f39c43717d6d35a54a941fb253b31450166709b652d8163b2b26464736f6c63430008130033", "sourceMap": "1103:1241:26:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4524:1133:23;;;;;;;;;;-1:-1:-1;4524:1133:23;;;;;:::i;:::-;;:::i;:::-;;;1750:25:28;;;1738:2;1723:18;4524:1133:23;;;;;;;;1424:2330;;;;;;;;;;-1:-1:-1;1424:2330:23;;;;;:::i;:::-;;:::i;:::-;;951:37;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2689:32:28;;;2671:51;;2659:2;2644:18;951:37:23;2525:203:28;5663:687:23;;;;;;;;;;-1:-1:-1;5663:687:23;;;;;:::i;:::-;;:::i;9330:236::-;;;;;;;;;;-1:-1:-1;9330:236:23;;;;;:::i;:::-;;:::i;1824:101:0:-;;;;;;;;;;;;;:::i;8794:152:23:-;;;;;;;;;;;;;:::i;1201:85:0:-;;;;;;;;;;-1:-1:-1;1247:7:0;1273:6;-1:-1:-1;;;;;1273:6:0;1201:85;;1336:210:26;;;;;;;;;;-1:-1:-1;1336:210:26;;;;;:::i;:::-;;:::i;8459:190:23:-;;;;;;;;;;;;;:::i;4097:421::-;;;;;;;;;;-1:-1:-1;4097:421:23;;;;;:::i;:::-;;:::i;1552:790:26:-;;;;;;;;;;-1:-1:-1;1552:790:26;;;;;:::i;:::-;;:::i;2074:198:0:-;;;;;;;;;;-1:-1:-1;2074:198:0;;;;;:::i;:::-;;:::i;4524:1133:23:-;4711:24;;;;4688:7;;4711:32;;4739:4;4711:32;4707:944;;4759:12;4774:229;4980:13;:22;;;4774:184;4934:14;:23;;;4774:138;4888:14;:23;;;4774:92;4843:13;:22;;;4774:47;4808:12;;4774;;:33;;:47;;;;:::i;:::-;:68;;:92::i;:138::-;:159;;:184::i;:229::-;4759:244;;5018:17;5038:115;5130:13;:22;;;5038:70;5084:14;:23;;;5039:22;5057:3;5039:13;5044:7;5039:4;:13::i;:::-;:17;;:22::i;5038:115::-;5018:135;-1:-1:-1;5168:16:23;;-1:-1:-1;;5168:16:23;4707:944;5215:12;5230:229;5436:13;:22;;;5230:184;5390:14;:23;;;5230:138;5344:14;:23;;;5230:92;5299:13;:22;;;5230:47;5264:12;;5230;;:33;;:47;;;;:::i;:229::-;5215:244;;5474:17;5494:115;5586:13;:22;;;5494:70;5540:14;:23;;;5495:22;5513:3;5495:13;5500:7;5495:4;:13::i;4707:944::-;4524:1133;;;;:::o;1424:2330::-;1633:45;;-1:-1:-1;;;1633:45:23;;1672:4;1633:45;;;2671:51:28;1609:21:23;;1640:12;-1:-1:-1;;;;;1633:30:23;;;;2644:18:28;;1633:45:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1609:69;-1:-1:-1;1730:16:23;1800:17;1688:24;1879:44;1730:16;1879:11;:44::i;:::-;1829:94;;1933:48;1984:45;2009:10;1984:11;:45::i;:::-;1933:96;;2040:16;2059:42;2071:13;2086:14;2059:11;:42::i;:::-;2111:57;;-1:-1:-1;;;2111:57:23;;-1:-1:-1;;;;;7933:32:28;;;2111:57:23;;;7915:51:28;7982:18;;;7975:34;;;2040:61:23;;-1:-1:-1;2118:12:23;2111:29;;;;;;7888:18:28;;2111:57:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;2179:26;2215:22;2251:13;:24;;;:32;;2279:4;2251:32;;;2247:1034;;2320:132;2350:8;2376:13;:22;;;2416:13;:22;;;2320:12;:132::i;:::-;2299:153;;2483:144;2513:18;2549:14;:23;;;2590:14;:23;;;2483:12;:144::i;:::-;2466:161;;2642:9;-1:-1:-1;;;;;2642:14:23;;2657:1;2660:18;2680:17;2642:60;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2716:53:23;;-1:-1:-1;;;2716:53:23;;-1:-1:-1;;;;;2716:15:23;;;-1:-1:-1;2716:15:23;;-1:-1:-1;2716:53:23;;2732:14;;2748:1;;2759:4;;2716:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2247:1034;;;2821:132;2851:8;2877:13;:22;;;2917:13;:22;;;2821:12;:132::i;:::-;2800:153;;2984:144;3014:18;3050:14;:23;;;3091:14;:23;;;2984:12;:144::i;:::-;2967:161;;3143:9;-1:-1:-1;;;;;3143:14:23;;3158:18;3178:1;3181:17;3143:60;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3217:53:23;;-1:-1:-1;;;3217:53:23;;-1:-1:-1;;;;;3217:15:23;;;-1:-1:-1;3217:15:23;;-1:-1:-1;3217:53:23;;3233:1;;3236:14;;3260:4;;3217:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2247:1034;3314:45;;-1:-1:-1;;;3314:45:23;;3353:4;3314:45;;;2671:51:28;3291:20:23;;3321:12;-1:-1:-1;;;;;3314:30:23;;;;2644:18:28;;3314:45:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3291:68;;3392:13;3377:12;:28;3369:57;;;;-1:-1:-1;;;3369:57:23;;9548:2:28;3369:57:23;;;9530:21:28;9587:2;9567:18;;;9560:30;-1:-1:-1;;;9606:18:28;;;9599:46;9662:18;;3369:57:23;;;;;;;;;3436:11;3450:31;:12;3467:13;3450:16;:31::i;:::-;3436:45;;3491:21;3515:46;3557:3;3515:37;3526:25;3515:6;:10;;:37;;;;:::i;:46::-;3571;;-1:-1:-1;;;3571:46:23;;;;;1750:25:28;;;3491:70:23;;-1:-1:-1;3577:12:23;-1:-1:-1;;;;;3571:28:23;;;;1723:18:28;;3571:46:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3627:41:23;;:14;;-1:-1:-1;3627:41:23;;;;;-1:-1:-1;3651:16:23;;3627:41;;;;3651:16;3627:14;:41;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;3684:12:23;3678:28;;3707:9;3718:28;:6;3729:16;3718:10;:28::i;:::-;3678:69;;-1:-1:-1;;;;;;3678:69:23;;;;;;;-1:-1:-1;;;;;7933:32:28;;;3678:69:23;;;7915:51:28;7982:18;;;7975:34;7888:18;;3678:69:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;1599:2155;;;;;;;;;;;1424:2330;;;;:::o;5663:687::-;5852:24;;;;5829:7;;5852:32;;5880:4;5852:32;5848:496;;5900:19;5922:147;6010:58;6045:13;:22;;;6010:30;6027:12;;6010;;:16;;:30;;;;:::i;:58::-;5940:51;5986:4;5940:41;5957:14;:23;;;5940:12;;:16;;:41;;;;:::i;:51::-;5922:87;;:147::i;:::-;5900:169;-1:-1:-1;6083:18:23;;-1:-1:-1;6083:18:23;5848:496;6277:22;;6259:12;;6132:19;;6154:147;;6242:58;;6277:22;6242:30;;6259:12;6242:16;:30::i;:58::-;6189:23;;6172:12;;:51;;6218:4;;6172:41;;:16;:41::i;9330:236::-;1094:13:0;:11;:13::i;:::-;9461:12:23::1;9479:3;-1:-1:-1::0;;;;;9479:8:23::1;9495:6;9503:5;9479:30;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9460:49;;;9527:7;9519:40;;;::::0;-1:-1:-1;;;9519:40:23;;10440:2:28;9519:40:23::1;::::0;::::1;10422:21:28::0;10479:2;10459:18;;;10452:30;-1:-1:-1;;;10498:18:28;;;10491:50;10558:18;;9519:40:23::1;10238:344:28::0;9519:40:23::1;9450:116;9330:236:::0;;;:::o;1824:101:0:-;1094:13;:11;:13::i;:::-;1888:30:::1;1915:1;1888:18;:30::i;:::-;1824:101::o:0;8794:152:23:-;1094:13:0;:11;:13::i;:::-;8902:37:23::1;::::0;8871:21:::1;::::0;8910:10:::1;::::0;8902:37;::::1;;;::::0;8871:21;;8853:15:::1;8902:37:::0;8853:15;8902:37;8871:21;8910:10;8902:37;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;8843:103;8794:152::o:0;1336:210:26:-;1094:13:0;:11;:13::i;:::-;1491:48:26::1;::::0;-1:-1:-1;;;1491:48:26;;1217:42:::1;::::0;1491:15:::1;::::0;:48:::1;::::0;1507:4:::1;::::0;1513:6;;1521:7;;1530:8;;1491:48:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;1336:210:::0;;;:::o;8459:190:23:-;1094:13:0;:11;:13::i;:::-;8537:45:23::1;::::0;-1:-1:-1;;;8537:45:23;;8576:4:::1;8537:45;::::0;::::1;2671:51:28::0;8519:15:23::1;::::0;8544:12:::1;-1:-1:-1::0;;;;;8537:30:23::1;::::0;::::1;::::0;2644:18:28;;8537:45:23::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8592:50;::::0;-1:-1:-1;;;8592:50:23;;8622:10:::1;8592:50;::::0;::::1;7915:51:28::0;7982:18;;;7975:34;;;8519:63:23;;-1:-1:-1;8599:12:23::1;-1:-1:-1::0;;;;;8592:29:23::1;::::0;::::1;::::0;7888:18:28;;8592:50:23::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;4097:421::-:0;4260:7;4279:17;4299:43;4312:13;4327:14;4299:12;:43::i;:::-;4279:63;;4352:19;4374:45;4389:13;4404:14;4374;:45::i;:::-;4352:67;-1:-1:-1;4430:16:23;4449:36;4352:67;4449:19;:9;4463:4;4449:13;:19::i;:36::-;4430:55;4097:421;-1:-1:-1;;;;;;4097:421:23:o;1552:790:26:-;1758:10;1217:42;1758:28;1737:118;;;;-1:-1:-1;;;1737:118:26;;12517:2:28;1737:118:26;;;12499:21:28;12556:2;12536:18;;;12529:30;12595:34;12575:18;;;12568:62;-1:-1:-1;;;12646:18:28;;;12639:41;12697:19;;1737:118:26;12315:407:28;1737:118:26;1880:24;1918:25;1957:33;2014:8;2003:49;;;;;;;;;;;;:::i;:::-;1866:186;;;;;;2063:153;2093:17;2124:16;2154:25;2201:4;2063:16;:153::i;:::-;2233:12;-1:-1:-1;;;;;2227:28:26;;1217:42;2311:10;2322:1;2311:13;;;;;;;;:::i;:::-;;;;;;;2297:7;2305:1;2297:10;;;;;;;;:::i;:::-;;;;;;;:28;;;;:::i;:::-;2227:108;;-1:-1:-1;;;;;;2227:108:26;;;;;;;-1:-1:-1;;;;;7933:32:28;;;2227:108:26;;;7915:51:28;7982:18;;;7975:34;7888:18;;2227:108:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;1727:615;;;1552:790;;;;:::o;2074:198:0:-;1094:13;:11;:13::i;:::-;-1:-1:-1;;;;;2162:22:0;::::1;2154:73;;;::::0;-1:-1:-1;;;2154:73:0;;13790:2:28;2154:73:0::1;::::0;::::1;13772:21:28::0;13829:2;13809:18;;;13802:30;13868:34;13848:18;;;13841:62;-1:-1:-1;;;13919:18:28;;;13912:36;13965:19;;2154:73:0::1;13588:402:28::0;2154:73:0::1;2237:28;2256:8;2237:18;:28::i;:::-;2074:198:::0;:::o;3465:96:5:-;3523:7;3549:5;3553:1;3549;:5;:::i;:::-;3542:12;3465:96;-1:-1:-1;;;3465:96:5:o;3850:::-;3908:7;3934:5;3938:1;3934;:5;:::i;7359:268:23:-;7406:7;7429:1;7434;7429:6;7425:20;;-1:-1:-1;7444:1:23;;7359:268;-1:-1:-1;7359:268:23:o;7425:20::-;7455:9;7467:15;7480:1;7467:8;:1;7473;7467:5;:8::i;:15::-;7455:27;-1:-1:-1;7504:1:23;7515:88;7526:1;7522;:5;7515:88;;;-1:-1:-1;7547:1:23;7566:26;7590:1;7567:17;7547:1;7568:8;:1;7547;7568:5;:8::i;7566:26::-;7562:30;;7515:88;;3122:96:5;3180:7;3206:5;3210:1;3206;:5;:::i;6621:552:23:-;6699:33;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6699:33:23;6745:16;6763;6785:4;-1:-1:-1;;;;;6785:16:23;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6744:59;-1:-1:-1;;;;;6744:59:23;;;-1:-1:-1;;;;;6744:59:23;;;6813:13;6837:15;6855:5;6837:23;;6891:12;-1:-1:-1;;;;;6874:29:23;:4;-1:-1:-1;;;;;6874:11:23;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;6874:29:23;;6870:202;;6927:32;6950:8;6927:18;:8;6940:4;6927:12;:18::i;:32::-;6919:40;;6986:4;6973:17;;6870:202;;;7029:32;7052:8;7029:18;:8;7042:4;7029:12;:18::i;:32::-;7021:40;;6870:202;7101:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6621:552;-1:-1:-1;;6621:552:23:o;7920:393::-;8042:14;;8091:17;:8;8104:3;8091:12;:17::i;:::-;8068:40;-1:-1:-1;8118:14:23;8135:31;8068:40;8155:10;8135:19;:31::i;:::-;8118:48;-1:-1:-1;8176:16:23;8195:40;8219:15;8195:19;:9;8209:4;8195:13;:19::i;:40::-;8176:59;-1:-1:-1;8257:23:23;8176:59;8257:9;:23;:::i;:::-;8245:35;7920:393;-1:-1:-1;;;;;;;7920:393:23:o;2755:96:5:-;2813:7;2839:5;2843:1;2839;:5;:::i;1359:130:0:-;1247:7;1273:6;-1:-1:-1;;;;;1273:6:0;719:10:4;1422:23:0;1414:68;;;;-1:-1:-1;;;1414:68:0;;15629:2:28;1414:68:0;;;15611:21:28;;;15648:18;;;15641:30;15707:34;15687:18;;;15680:62;15759:18;;1414:68:0;15427:356:28;2426:187:0;2499:16;2518:6;;-1:-1:-1;;;;;2534:17:0;;;-1:-1:-1;;;;;;2534:17:0;;;;;;2566:40;;2518:6;;;;;;;2566:40;;2499:16;2566:40;2489:124;2426:187;:::o;14:127:28:-;75:10;70:3;66:20;63:1;56:31;106:4;103:1;96:15;130:4;127:1;120:15;146:275;217:2;211:9;282:2;263:13;;-1:-1:-1;;259:27:28;247:40;;317:18;302:34;;338:22;;;299:62;296:88;;;364:18;;:::i;:::-;400:2;393:22;146:275;;-1:-1:-1;146:275:28:o;426:118::-;512:5;505:13;498:21;491:5;488:32;478:60;;534:1;531;524:12;549:679;608:5;656:4;644:9;639:3;635:19;631:30;628:50;;;674:1;671;664:12;628:50;707:2;701:9;749:4;741:6;737:17;820:6;808:10;805:22;784:18;772:10;769:34;766:62;763:88;;;831:18;;:::i;:::-;871:10;867:2;860:22;;900:6;891:15;;943:9;930:23;922:6;915:39;1015:2;1004:9;1000:18;987:32;982:2;974:6;970:15;963:57;1081:2;1070:9;1066:18;1053:32;1048:2;1040:6;1036:15;1029:57;1138:2;1127:9;1123:18;1110:32;1151:30;1173:7;1151:30;:::i;:::-;1209:2;1197:15;;;;1190:32;549:679;;-1:-1:-1;;549:679:28:o;1233:366::-;1363:6;1371;1424:3;1412:9;1403:7;1399:23;1395:33;1392:53;;;1441:1;1438;1431:12;1392:53;1464:50;1506:7;1495:9;1464:50;:::i;:::-;1454:60;;1533;1585:7;1579:3;1568:9;1564:19;1533:60;:::i;:::-;1523:70;;1233:366;;;;;:::o;1786:131::-;-1:-1:-1;;;;;1861:31:28;;1851:42;;1841:70;;1907:1;1904;1897:12;1922:598;2008:6;2016;2024;2032;2085:3;2073:9;2064:7;2060:23;2056:33;2053:53;;;2102:1;2099;2092:12;2053:53;2141:9;2128:23;2160:31;2185:5;2160:31;:::i;:::-;2210:5;-1:-1:-1;2267:2:28;2252:18;;2239:32;2280:33;2239:32;2280:33;:::i;:::-;2332:7;-1:-1:-1;2386:2:28;2371:18;;2358:32;;-1:-1:-1;2442:2:28;2427:18;;2414:32;2455:33;2414:32;2455:33;:::i;:::-;1922:598;;;;-1:-1:-1;1922:598:28;;-1:-1:-1;;1922:598:28:o;2733:530::-;2775:5;2828:3;2821:4;2813:6;2809:17;2805:27;2795:55;;2846:1;2843;2836:12;2795:55;2882:6;2869:20;2908:18;2904:2;2901:26;2898:52;;;2930:18;;:::i;:::-;2974:55;3017:2;2998:13;;-1:-1:-1;;2994:27:28;3023:4;2990:38;2974:55;:::i;:::-;3054:2;3045:7;3038:19;3100:3;3093:4;3088:2;3080:6;3076:15;3072:26;3069:35;3066:55;;;3117:1;3114;3107:12;3066:55;3182:2;3175:4;3167:6;3163:17;3156:4;3147:7;3143:18;3130:55;3230:1;3205:16;;;3223:4;3201:27;3194:38;;;;3209:7;2733:530;-1:-1:-1;;;2733:530:28:o;3268:531::-;3362:6;3370;3378;3431:2;3419:9;3410:7;3406:23;3402:32;3399:52;;;3447:1;3444;3437:12;3399:52;3486:9;3473:23;3505:31;3530:5;3505:31;:::i;:::-;3555:5;-1:-1:-1;3607:2:28;3592:18;;3579:32;;-1:-1:-1;3662:2:28;3647:18;;3634:32;3689:18;3678:30;;3675:50;;;3721:1;3718;3711:12;3675:50;3744:49;3785:7;3776:6;3765:9;3761:22;3744:49;:::i;:::-;3734:59;;;3268:531;;;;;:::o;3804:191::-;3872:4;3905:18;3897:6;3894:30;3891:56;;;3927:18;;:::i;:::-;-1:-1:-1;3972:1:28;3968:14;3984:4;3964:25;;3804:191::o;4000:753::-;4062:5;4115:3;4108:4;4100:6;4096:17;4092:27;4082:55;;4133:1;4130;4123:12;4082:55;4169:6;4156:20;4195:4;4219:68;4235:51;4283:2;4235:51;:::i;:::-;4219:68;:::i;:::-;4321:15;;;4407:1;4403:10;;;;4391:23;;4387:32;;;4352:12;;;;4431:15;;;4428:35;;;4459:1;4456;4449:12;4428:35;4495:2;4487:6;4483:15;4507:217;4523:6;4518:3;4515:15;4507:217;;;4603:3;4590:17;4620:31;4645:5;4620:31;:::i;:::-;4664:18;;4702:12;;;;4540;;4507:217;;;-1:-1:-1;4742:5:28;4000:753;-1:-1:-1;;;;;;4000:753:28:o;4758:670::-;4812:5;4865:3;4858:4;4850:6;4846:17;4842:27;4832:55;;4883:1;4880;4873:12;4832:55;4919:6;4906:20;4945:4;4969:68;4985:51;5033:2;4985:51;:::i;4969:68::-;5071:15;;;5157:1;5153:10;;;;5141:23;;5137:32;;;5102:12;;;;5181:15;;;5178:35;;;5209:1;5206;5199:12;5178:35;5245:2;5237:6;5233:15;5257:142;5273:6;5268:3;5265:15;5257:142;;;5339:17;;5327:30;;5377:12;;;;5290;;5257:142;;5433:815;5583:6;5591;5599;5652:2;5640:9;5631:7;5627:23;5623:32;5620:52;;;5668:1;5665;5658:12;5620:52;5708:9;5695:23;5737:18;5778:2;5770:6;5767:14;5764:34;;;5794:1;5791;5784:12;5764:34;5817:69;5878:7;5869:6;5858:9;5854:22;5817:69;:::i;:::-;5807:79;;5939:2;5928:9;5924:18;5911:32;5895:48;;5968:2;5958:8;5955:16;5952:36;;;5984:1;5981;5974:12;5952:36;6007:63;6062:7;6051:8;6040:9;6036:24;6007:63;:::i;:::-;5997:73;;6123:2;6112:9;6108:18;6095:32;6079:48;;6152:2;6142:8;6139:16;6136:36;;;6168:1;6165;6158:12;6136:36;;6191:51;6234:7;6223:8;6212:9;6208:24;6191:51;:::i;6253:1042::-;6437:6;6445;6453;6461;6514:3;6502:9;6493:7;6489:23;6485:33;6482:53;;;6531:1;6528;6521:12;6482:53;6571:9;6558:23;6600:18;6641:2;6633:6;6630:14;6627:34;;;6657:1;6654;6647:12;6627:34;6680:69;6741:7;6732:6;6721:9;6717:22;6680:69;:::i;:::-;6670:79;;6802:2;6791:9;6787:18;6774:32;6758:48;;6831:2;6821:8;6818:16;6815:36;;;6847:1;6844;6837:12;6815:36;6870:63;6925:7;6914:8;6903:9;6899:24;6870:63;:::i;:::-;6860:73;;6986:2;6975:9;6971:18;6958:32;6942:48;;7015:2;7005:8;7002:16;6999:36;;;7031:1;7028;7021:12;6999:36;7054:63;7109:7;7098:8;7087:9;7083:24;7054:63;:::i;:::-;7044:73;;7170:2;7159:9;7155:18;7142:32;7126:48;;7199:2;7189:8;7186:16;7183:36;;;7215:1;7212;7205:12;7183:36;;7238:51;7281:7;7270:8;7259:9;7255:24;7238:51;:::i;:::-;7228:61;;;6253:1042;;;;;;;:::o;7300:247::-;7359:6;7412:2;7400:9;7391:7;7387:23;7383:32;7380:52;;;7428:1;7425;7418:12;7380:52;7467:9;7454:23;7486:31;7511:5;7486:31;:::i;7552:184::-;7622:6;7675:2;7663:9;7654:7;7650:23;7646:32;7643:52;;;7691:1;7688;7681:12;7643:52;-1:-1:-1;7714:16:28;;7552:184;-1:-1:-1;7552:184:28:o;8020:245::-;8087:6;8140:2;8128:9;8119:7;8115:23;8111:32;8108:52;;;8156:1;8153;8146:12;8108:52;8188:9;8182:16;8207:28;8229:5;8207:28;:::i;8270:533::-;8545:25;;;8601:2;8586:18;;8579:34;;;;-1:-1:-1;;;;;8649:32:28;8644:2;8629:18;;8622:60;8718:3;8713:2;8698:18;;8691:31;;;-1:-1:-1;8738:19:28;;;8731:30;8669:3;8778:19;;8270:533::o;9691:250::-;9776:1;9786:113;9800:6;9797:1;9794:13;9786:113;;;9876:11;;;9870:18;9857:11;;;9850:39;9822:2;9815:10;9786:113;;;-1:-1:-1;;9933:1:28;9915:16;;9908:27;9691:250::o;9946:287::-;10075:3;10113:6;10107:13;10129:66;10188:6;10183:3;10176:4;10168:6;10164:17;10129:66;:::i;:::-;10211:16;;;;;9946:287;-1:-1:-1;;9946:287:28:o;10587:270::-;10628:3;10666:5;10660:12;10693:6;10688:3;10681:19;10709:76;10778:6;10771:4;10766:3;10762:14;10755:4;10748:5;10744:16;10709:76;:::i;:::-;10839:2;10818:15;-1:-1:-1;;10814:29:28;10805:39;;;;10846:4;10801:50;;10587:270;-1:-1:-1;;10587:270:28:o;10862:1448::-;-1:-1:-1;;;;;11311:15:28;;;11293:34;;11242:3;11346:2;11364:18;;;11357:31;;;11437:13;;11227:19;;;11459:22;;;11194:4;;11539:15;;;;11265:19;;11346:2;11273:3;11497:19;;;11194:4;11582:178;11596:6;11593:1;11590:13;11582:178;;;11661:13;;11657:22;;11645:35;;11735:15;;;;11700:12;;;;11618:1;11611:9;11582:178;;;-1:-1:-1;;11796:19:28;;;11791:2;11776:18;;11769:47;11866:13;;11888:21;;;11927:12;;;;-1:-1:-1;11866:13:28;-1:-1:-1;11964:15:28;;;11999:1;12009:189;12025:8;12020:3;12017:17;12009:189;;;12094:15;;12080:30;;12132:14;;;;12171:17;;;;12053:1;12044:11;12009:189;;;12013:3;;;;12245:9;12238:5;12234:21;12229:2;12218:9;12214:18;12207:49;12273:31;12298:5;12290:6;12273:31;:::i;12727:462::-;12831:6;12839;12847;12900:2;12888:9;12879:7;12875:23;12871:32;12868:52;;;12916:1;12913;12906:12;12868:52;12948:9;12942:16;12967:31;12992:5;12967:31;:::i;:::-;13067:2;13052:18;;13046:25;13017:5;;-1:-1:-1;13080:33:28;13046:25;13080:33;:::i;:::-;13132:7;13122:17;;;13179:2;13168:9;13164:18;13158:25;13148:35;;12727:462;;;;;:::o;13194:127::-;13255:10;13250:3;13246:20;13243:1;13236:31;13286:4;13283:1;13276:15;13310:4;13307:1;13300:15;13326:127;13387:10;13382:3;13378:20;13375:1;13368:31;13418:4;13415:1;13408:15;13442:4;13439:1;13432:15;13458:125;13523:9;;;13544:10;;;13541:36;;;13557:18;;:::i;13995:168::-;14068:9;;;14099;;14116:15;;;14110:22;;14096:37;14086:71;;14137:18;;:::i;14168:217::-;14208:1;14234;14224:132;;14278:10;14273:3;14269:20;14266:1;14259:31;14313:4;14310:1;14303:15;14341:4;14338:1;14331:15;14224:132;-1:-1:-1;14370:9:28;;14168:217::o;14390:128::-;14457:9;;;14478:11;;;14475:37;;;14492:18;;:::i;14523:188::-;14602:13;;-1:-1:-1;;;;;14644:42:28;;14634:53;;14624:81;;14701:1;14698;14691:12;14624:81;14523:188;;;:::o;14716:450::-;14803:6;14811;14819;14872:2;14860:9;14851:7;14847:23;14843:32;14840:52;;;14888:1;14885;14878:12;14840:52;14911:40;14941:9;14911:40;:::i;:::-;14901:50;;14970:49;15015:2;15004:9;15000:18;14970:49;:::i;:::-;14960:59;;15062:2;15051:9;15047:18;15041:25;15106:10;15099:5;15095:22;15088:5;15085:33;15075:61;;15132:1;15129;15122:12;15075:61;15155:5;15145:15;;;14716:450;;;;;:::o;15171:251::-;15241:6;15294:2;15282:9;15273:7;15269:23;15265:32;15262:52;;;15310:1;15307;15300:12;15262:52;15342:9;15336:16;15361:31;15386:5;15361:31;:::i", "linkReferences": {}, "immutableReferences": { "31558": [ { "start": 311, "length": 32 }, { "start": 913, "length": 32 }, { "start": 1111, "length": 32 }, { "start": 1752, "length": 32 }, { "start": 2005, "length": 32 }, { "start": 2161, "length": 32 }, { "start": 2900, "length": 32 }, { "start": 3046, "length": 32 }, { "start": 3384, "length": 32 }, { "start": 4053, "length": 32 } ] } }, "methodIdentifiers": { "WETH_ADDRESS()": "040141e5", "call(address,uint256,bytes)": "6dbf2fa0", "executeArbitrage(address,address,uint256,address)": "00fb4304", "getAmountIn((uint256,uint256,uint256,bool),(uint256,uint256,uint256,bool))": "eb6b2116", "getDenominator((uint256,uint256,uint256,bool),(uint256,uint256,uint256,bool))": "1fa7d39b", "getNumerator((uint256,uint256,uint256,bool),(uint256,uint256,uint256,bool))": "00bb7d67", "makeFlashLoan(address[],uint256[],bytes)": "c9a69562", "owner()": "8da5cb5b", "receiveFlashLoan(address[],uint256[],uint256[],bytes)": "f04f2707", "renounceOwnership()": "715018a6", "transferOwnership(address)": "f2fde38b", "withdrawETHToOwner()": "77432b8c", "withdrawWETHToOwner()": "ea3e506c" }, "rawMetadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"WETH_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"firstPairAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"secondPairAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"percentageToPayToCoinbase\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"executeArbitrage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"reserve0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reserve1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWETHZero\",\"type\":\"bool\"}],\"internalType\":\"struct IPairReserves.PairReserves\",\"name\":\"firstPairData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"reserve0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reserve1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWETHZero\",\"type\":\"bool\"}],\"internalType\":\"struct IPairReserves.PairReserves\",\"name\":\"secondPairData\",\"type\":\"tuple\"}],\"name\":\"getAmountIn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"reserve0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reserve1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWETHZero\",\"type\":\"bool\"}],\"internalType\":\"struct IPairReserves.PairReserves\",\"name\":\"firstPairData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"reserve0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reserve1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWETHZero\",\"type\":\"bool\"}],\"internalType\":\"struct IPairReserves.PairReserves\",\"name\":\"secondPairData\",\"type\":\"tuple\"}],\"name\":\"getDenominator\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"reserve0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reserve1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWETHZero\",\"type\":\"bool\"}],\"internalType\":\"struct IPairReserves.PairReserves\",\"name\":\"firstPairData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"reserve0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reserve1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWETHZero\",\"type\":\"bool\"}],\"internalType\":\"struct IPairReserves.PairReserves\",\"name\":\"secondPairData\",\"type\":\"tuple\"}],\"name\":\"getNumerator\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20[]\",\"name\":\"tokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"userData\",\"type\":\"bytes\"}],\"name\":\"makeFlashLoan\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20[]\",\"name\":\"tokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"feeAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"userData\",\"type\":\"bytes\"}],\"name\":\"receiveFlashLoan\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawETHToOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawWETHToOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"call(address,uint256,bytes)\":{\"details\":\"Only the contract owner can call this function.Reverted calls will result in a revert.\",\"params\":{\"_data\":\"The calldata to send with the call.\",\"_to\":\"The address of the contract to call.\",\"_value\":\"The amount of Ether to send with the call.\"}},\"executeArbitrage(address,address,uint256,address)\":{\"details\":\"Only the contract owner can call this function.\",\"params\":{\"firstPairAddress\":\"Address of the first Uniswap V2 pair.\",\"secondPairAddress\":\"Address of the second Uniswap V2 pair.\"}},\"getAmountIn((uint256,uint256,uint256,bool),(uint256,uint256,uint256,bool))\":{\"params\":{\"firstPairData\":\"Struct containing data about the first Uniswap V2 pair.\",\"secondPairData\":\"Struct containing data about the second Uniswap V2 pair.\"},\"returns\":{\"_0\":\"amountIn, the optimal amount to trade to arbitrage two v2 pairs.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"receiveFlashLoan(address[],uint256[],uint256[],bytes)\":{\"details\":\"When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient. At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the Vault, or else the entire flash loan will revert. `userData` is the same value passed in the `IVault.flashLoan` call.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"withdrawETHToOwner()\":{\"details\":\"Only the contract owner can call this function.\"},\"withdrawWETHToOwner()\":{\"details\":\"Only the contract owner can call this function.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"call(address,uint256,bytes)\":{\"notice\":\"Executes a call to another contract with the provided data and value.\"},\"executeArbitrage(address,address,uint256,address)\":{\"notice\":\"Executes an arbitrage transaction between two Uniswap V2 pairs.Pair addresses need to be computed off-chain.\"},\"getAmountIn((uint256,uint256,uint256,bool),(uint256,uint256,uint256,bool))\":{\"notice\":\"Calculates the required input amount for the arbitrage transaction.\"},\"withdrawETHToOwner()\":{\"notice\":\"Transfers all ETH held by the contract to the contract owner.\"},\"withdrawWETHToOwner()\":{\"notice\":\"Transfers all WETH held by the contract to the contract owner.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/blindBackrunFL.sol\":\"BlindBackrunFL\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin/=lib/openzeppelin-contracts/contracts/\"]},\"sources\":{\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0x923b9774b81c1abfb992262ae7763b6e6de77b077a7180d53c6ebb7b1c8bd648\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://53445dc0431f9b45c06f567c6091da961d4087bec0010cca5bd62100fa624a38\",\"dweb:/ipfs/QmNvBYpBv183czrAqNXr76E8M3LF93ouAJFeAcHfb59Rcx\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0x00c839ff53d07d19db2e7cfa1e5133f9ee90a8d64b0e2e57f50446a2d1a3a0e0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3dac621d015a68a5251b1e5d41dda0faf252699bf6e8bcf46a958b29964d9dd1\",\"dweb:/ipfs/QmP9axjgZv4cezAhALoTemM62sdLtMDJ9MGTxECnNwHgSJ\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92\",\"dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3\"]},\"lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol\":{\"keccak256\":\"0xa80cb30fccbba7c8ff72ac82cc898576a78d4c3031e85676840048f3fe195f5d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://22fff2b2370631317e0e4bf36eabb136e96f1db5d5993c61e13b27d7615b504f\",\"dweb:/ipfs/QmfTW395az3LUhe3Gm5BUCwkaj9Sk1fURZKvHL2XzDHYQk\"]},\"src/BlindBackrun.sol\":{\"keccak256\":\"0x94cb76a0a711d8725db99bf728521638548ae444077d4485e3a23fb87f4d87da\",\"urls\":[\"bzz-raw://bbe803026bb99cb6f926f19a5d8fa50c8ea7cee30f49fd58df906c8cc91b7aa1\",\"dweb:/ipfs/QmSynZeD4hv25hH9e5ZgFzB78WbxYjpza3gRPrrPanenAo\"]},\"src/blindBackrunFL.sol\":{\"keccak256\":\"0xd823a06388208db5cfdf08f3d6a87ca26876777317dd721037a845d4e25ffd4f\",\"urls\":[\"bzz-raw://9e07a30427d99d1a3dae21d358f49fb1f1eee7bbf217854fa4dd741d595ecd7b\",\"dweb:/ipfs/Qmd2MVgu5qRd1Yuub2rUdQg1F61MKBX6ZHUCmaGbsDxL97\"]}},\"version\":1}", "metadata": { "compiler": { "version": "0.8.19+commit.7dd6d404" }, "language": "Solidity", "output": { "abi": [ { "inputs": [ { "internalType": "address", "name": "_wethAddress", "type": "address" } ], "stateMutability": "nonpayable", "type": "constructor" }, { "inputs": [ { "internalType": "address", "name": "previousOwner", "type": "address", "indexed": true }, { "internalType": "address", "name": "newOwner", "type": "address", "indexed": true } ], "type": "event", "name": "OwnershipTransferred", "anonymous": false }, { "inputs": [], "stateMutability": "view", "type": "function", "name": "WETH_ADDRESS", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ] }, { "inputs": [ { "internalType": "address payable", "name": "_to", "type": "address" }, { "internalType": "uint256", "name": "_value", "type": "uint256" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "stateMutability": "nonpayable", "type": "function", "name": "call" }, { "inputs": [ { "internalType": "address", "name": "firstPairAddress", "type": "address" }, { "internalType": "address", "name": "secondPairAddress", "type": "address" }, { "internalType": "uint256", "name": "percentageToPayToCoinbase", "type": "uint256" }, { "internalType": "address", "name": "recipient", "type": "address" } ], "stateMutability": "nonpayable", "type": "function", "name": "executeArbitrage" }, { "inputs": [ { "internalType": "struct IPairReserves.PairReserves", "name": "firstPairData", "type": "tuple", "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ] }, { "internalType": "struct IPairReserves.PairReserves", "name": "secondPairData", "type": "tuple", "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ] } ], "stateMutability": "view", "type": "function", "name": "getAmountIn", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ] }, { "inputs": [ { "internalType": "struct IPairReserves.PairReserves", "name": "firstPairData", "type": "tuple", "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ] }, { "internalType": "struct IPairReserves.PairReserves", "name": "secondPairData", "type": "tuple", "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ] } ], "stateMutability": "view", "type": "function", "name": "getDenominator", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ] }, { "inputs": [ { "internalType": "struct IPairReserves.PairReserves", "name": "firstPairData", "type": "tuple", "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ] }, { "internalType": "struct IPairReserves.PairReserves", "name": "secondPairData", "type": "tuple", "components": [ { "internalType": "uint256", "name": "reserve0", "type": "uint256" }, { "internalType": "uint256", "name": "reserve1", "type": "uint256" }, { "internalType": "uint256", "name": "price", "type": "uint256" }, { "internalType": "bool", "name": "isWETHZero", "type": "bool" } ] } ], "stateMutability": "view", "type": "function", "name": "getNumerator", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ] }, { "inputs": [ { "internalType": "contract IERC20[]", "name": "tokens", "type": "address[]" }, { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" }, { "internalType": "bytes", "name": "userData", "type": "bytes" } ], "stateMutability": "nonpayable", "type": "function", "name": "makeFlashLoan" }, { "inputs": [], "stateMutability": "view", "type": "function", "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ] }, { "inputs": [ { "internalType": "contract IERC20[]", "name": "tokens", "type": "address[]" }, { "internalType": "uint256[]", "name": "amounts", "type": "uint256[]" }, { "internalType": "uint256[]", "name": "feeAmounts", "type": "uint256[]" }, { "internalType": "bytes", "name": "userData", "type": "bytes" } ], "stateMutability": "nonpayable", "type": "function", "name": "receiveFlashLoan" }, { "inputs": [], "stateMutability": "nonpayable", "type": "function", "name": "renounceOwnership" }, { "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "stateMutability": "nonpayable", "type": "function", "name": "transferOwnership" }, { "inputs": [], "stateMutability": "nonpayable", "type": "function", "name": "withdrawETHToOwner" }, { "inputs": [], "stateMutability": "nonpayable", "type": "function", "name": "withdrawWETHToOwner" }, { "inputs": [], "stateMutability": "payable", "type": "receive" } ], "devdoc": { "kind": "dev", "methods": { "call(address,uint256,bytes)": { "details": "Only the contract owner can call this function.Reverted calls will result in a revert.", "params": { "_data": "The calldata to send with the call.", "_to": "The address of the contract to call.", "_value": "The amount of Ether to send with the call." } }, "executeArbitrage(address,address,uint256,address)": { "details": "Only the contract owner can call this function.", "params": { "firstPairAddress": "Address of the first Uniswap V2 pair.", "secondPairAddress": "Address of the second Uniswap V2 pair." } }, "getAmountIn((uint256,uint256,uint256,bool),(uint256,uint256,uint256,bool))": { "params": { "firstPairData": "Struct containing data about the first Uniswap V2 pair.", "secondPairData": "Struct containing data about the second Uniswap V2 pair." }, "returns": { "_0": "amountIn, the optimal amount to trade to arbitrage two v2 pairs." } }, "owner()": { "details": "Returns the address of the current owner." }, "receiveFlashLoan(address[],uint256[],uint256[],bytes)": { "details": "When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient. At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the Vault, or else the entire flash loan will revert. `userData` is the same value passed in the `IVault.flashLoan` call." }, "renounceOwnership()": { "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." }, "transferOwnership(address)": { "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." }, "withdrawETHToOwner()": { "details": "Only the contract owner can call this function." }, "withdrawWETHToOwner()": { "details": "Only the contract owner can call this function." } }, "version": 1 }, "userdoc": { "kind": "user", "methods": { "call(address,uint256,bytes)": { "notice": "Executes a call to another contract with the provided data and value." }, "executeArbitrage(address,address,uint256,address)": { "notice": "Executes an arbitrage transaction between two Uniswap V2 pairs.Pair addresses need to be computed off-chain." }, "getAmountIn((uint256,uint256,uint256,bool),(uint256,uint256,uint256,bool))": { "notice": "Calculates the required input amount for the arbitrage transaction." }, "withdrawETHToOwner()": { "notice": "Transfers all ETH held by the contract to the contract owner." }, "withdrawWETHToOwner()": { "notice": "Transfers all WETH held by the contract to the contract owner." } }, "version": 1 } }, "settings": { "remappings": [ ":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/", ":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", ":forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/", ":openzeppelin-contracts/=lib/openzeppelin-contracts/", ":openzeppelin/=lib/openzeppelin-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "compilationTarget": { "src/blindBackrunFL.sol": "BlindBackrunFL" }, "libraries": {} }, "sources": { "lib/openzeppelin-contracts/contracts/access/Ownable.sol": { "keccak256": "0x923b9774b81c1abfb992262ae7763b6e6de77b077a7180d53c6ebb7b1c8bd648", "urls": [ "bzz-raw://53445dc0431f9b45c06f567c6091da961d4087bec0010cca5bd62100fa624a38", "dweb:/ipfs/QmNvBYpBv183czrAqNXr76E8M3LF93ouAJFeAcHfb59Rcx" ], "license": "MIT" }, "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": { "keccak256": "0x00c839ff53d07d19db2e7cfa1e5133f9ee90a8d64b0e2e57f50446a2d1a3a0e0", "urls": [ "bzz-raw://3dac621d015a68a5251b1e5d41dda0faf252699bf6e8bcf46a958b29964d9dd1", "dweb:/ipfs/QmP9axjgZv4cezAhALoTemM62sdLtMDJ9MGTxECnNwHgSJ" ], "license": "MIT" }, "lib/openzeppelin-contracts/contracts/utils/Context.sol": { "keccak256": "0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7", "urls": [ "bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92", "dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3" ], "license": "MIT" }, "lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol": { "keccak256": "0xa80cb30fccbba7c8ff72ac82cc898576a78d4c3031e85676840048f3fe195f5d", "urls": [ "bzz-raw://22fff2b2370631317e0e4bf36eabb136e96f1db5d5993c61e13b27d7615b504f", "dweb:/ipfs/QmfTW395az3LUhe3Gm5BUCwkaj9Sk1fURZKvHL2XzDHYQk" ], "license": "MIT" }, "src/BlindBackrun.sol": { "keccak256": "0x94cb76a0a711d8725db99bf728521638548ae444077d4485e3a23fb87f4d87da", "urls": [ "bzz-raw://bbe803026bb99cb6f926f19a5d8fa50c8ea7cee30f49fd58df906c8cc91b7aa1", "dweb:/ipfs/QmSynZeD4hv25hH9e5ZgFzB78WbxYjpza3gRPrrPanenAo" ], "license": null }, "src/blindBackrunFL.sol": { "keccak256": "0xd823a06388208db5cfdf08f3d6a87ca26876777317dd721037a845d4e25ffd4f", "urls": [ "bzz-raw://9e07a30427d99d1a3dae21d358f49fb1f1eee7bbf217854fa4dd741d595ecd7b", "dweb:/ipfs/Qmd2MVgu5qRd1Yuub2rUdQg1F61MKBX6ZHUCmaGbsDxL97" ], "license": null } }, "version": 1 }, "ast": { "absolutePath": "src/blindBackrunFL.sol", "id": 30460, "exportedSymbols": { "BlindBackrun": [ 32259 ], "BlindBackrunFL": [ 30459 ], "Context": [ 824 ], "IERC20": [ 777 ], "IFlashLoanRecipient": [ 30342 ], "IPairReserves": [ 31548 ], "IUniswapV2Pair": [ 31538 ], "IVault": [ 30325 ], "IWETH": [ 31507 ], "Ownable": [ 112 ], "SafeMath": [ 1136 ] }, "nodeType": "SourceUnit", "src": "0:2345:26", "nodes": [ { "id": 30305, "nodeType": "PragmaDirective", "src": "0:23:26", "nodes": [], "literals": [ "solidity", "^", "0.8", ".0" ] }, { "id": 30306, "nodeType": "ImportDirective", "src": "25:45:26", "nodes": [], "absolutePath": "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol", "file": "openzeppelin/token/ERC20/IERC20.sol", "nameLocation": "-1:-1:-1", "scope": 30460, "sourceUnit": 778, "symbolAliases": [], "unitAlias": "" }, { "id": 30307, "nodeType": "ImportDirective", "src": "71:41:26", "nodes": [], "absolutePath": "lib/openzeppelin-contracts/contracts/access/Ownable.sol", "file": "openzeppelin/access/Ownable.sol", "nameLocation": "-1:-1:-1", "scope": 30460, "sourceUnit": 113, "symbolAliases": [], "unitAlias": "" }, { "id": 30308, "nodeType": "ImportDirective", "src": "113:46:26", "nodes": [], "absolutePath": "lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol", "file": "openzeppelin/utils/math/SafeMath.sol", "nameLocation": "-1:-1:-1", "scope": 30460, "sourceUnit": 1137, "symbolAliases": [], "unitAlias": "" }, { "id": 30309, "nodeType": "ImportDirective", "src": "160:28:26", "nodes": [], "absolutePath": "src/BlindBackrun.sol", "file": "./BlindBackrun.sol", "nameLocation": "-1:-1:-1", "scope": 30460, "sourceUnit": 32260, "symbolAliases": [], "unitAlias": "" }, { "id": 30325, "nodeType": "ContractDefinition", "src": "190:195:26", "nodes": [ { "id": 30324, "nodeType": "FunctionDefinition", "src": "213:170:26", "nodes": [], "functionSelector": "5c38449e", "implemented": false, "kind": "function", "modifiers": [], "name": "flashLoan", "nameLocation": "222:9:26", "parameters": { "id": 30322, "nodeType": "ParameterList", "parameters": [ { "constant": false, "id": 30312, "mutability": "mutable", "name": "recipient", "nameLocation": "261:9:26", "nodeType": "VariableDeclaration", "scope": 30324, "src": "241:29:26", "stateVariable": false, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_contract$_IFlashLoanRecipient_$30342", "typeString": "contract IFlashLoanRecipient" }, "typeName": { "id": 30311, "nodeType": "UserDefinedTypeName", "pathNode": { "id": 30310, "name": "IFlashLoanRecipient", "nameLocations": [ "241:19:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 30342, "src": "241:19:26" }, "referencedDeclaration": 30342, "src": "241:19:26", "typeDescriptions": { "typeIdentifier": "t_contract$_IFlashLoanRecipient_$30342", "typeString": "contract IFlashLoanRecipient" } }, "visibility": "internal" }, { "constant": false, "id": 30316, "mutability": "mutable", "name": "tokens", "nameLocation": "296:6:26", "nodeType": "VariableDeclaration", "scope": 30324, "src": "280:22:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_memory_ptr", "typeString": "contract IERC20[]" }, "typeName": { "baseType": { "id": 30314, "nodeType": "UserDefinedTypeName", "pathNode": { "id": 30313, "name": "IERC20", "nameLocations": [ "280:6:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 777, "src": "280:6:26" }, "referencedDeclaration": 777, "src": "280:6:26", "typeDescriptions": { "typeIdentifier": "t_contract$_IERC20_$777", "typeString": "contract IERC20" } }, "id": 30315, "nodeType": "ArrayTypeName", "src": "280:8:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_storage_ptr", "typeString": "contract IERC20[]" } }, "visibility": "internal" }, { "constant": false, "id": 30319, "mutability": "mutable", "name": "amounts", "nameLocation": "329:7:26", "nodeType": "VariableDeclaration", "scope": 30324, "src": "312:24:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[]" }, "typeName": { "baseType": { "id": 30317, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "312:7:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "id": 30318, "nodeType": "ArrayTypeName", "src": "312:9:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_storage_ptr", "typeString": "uint256[]" } }, "visibility": "internal" }, { "constant": false, "id": 30321, "mutability": "mutable", "name": "userData", "nameLocation": "359:8:26", "nodeType": "VariableDeclaration", "scope": 30324, "src": "346:21:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_bytes_memory_ptr", "typeString": "bytes" }, "typeName": { "id": 30320, "name": "bytes", "nodeType": "ElementaryTypeName", "src": "346:5:26", "typeDescriptions": { "typeIdentifier": "t_bytes_storage_ptr", "typeString": "bytes" } }, "visibility": "internal" } ], "src": "231:142:26" }, "returnParameters": { "id": 30323, "nodeType": "ParameterList", "parameters": [], "src": "382:0:26" }, "scope": 30325, "stateMutability": "nonpayable", "virtual": false, "visibility": "external" } ], "abstract": false, "baseContracts": [], "canonicalName": "IVault", "contractDependencies": [], "contractKind": "interface", "fullyImplemented": false, "linearizedBaseContracts": [ 30325 ], "name": "IVault", "nameLocation": "200:6:26", "scope": 30460, "usedErrors": [] }, { "id": 30342, "nodeType": "ContractDefinition", "src": "387:714:26", "nodes": [ { "id": 30341, "nodeType": "FunctionDefinition", "src": "924:175:26", "nodes": [], "documentation": { "id": 30326, "nodeType": "StructuredDocumentation", "src": "423:496:26", "text": " @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.\n At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this\n call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the\n Vault, or else the entire flash loan will revert.\n `userData` is the same value passed in the `IVault.flashLoan` call." }, "functionSelector": "f04f2707", "implemented": false, "kind": "function", "modifiers": [], "name": "receiveFlashLoan", "nameLocation": "933:16:26", "parameters": { "id": 30339, "nodeType": "ParameterList", "parameters": [ { "constant": false, "id": 30330, "mutability": "mutable", "name": "tokens", "nameLocation": "975:6:26", "nodeType": "VariableDeclaration", "scope": 30341, "src": "959:22:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_memory_ptr", "typeString": "contract IERC20[]" }, "typeName": { "baseType": { "id": 30328, "nodeType": "UserDefinedTypeName", "pathNode": { "id": 30327, "name": "IERC20", "nameLocations": [ "959:6:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 777, "src": "959:6:26" }, "referencedDeclaration": 777, "src": "959:6:26", "typeDescriptions": { "typeIdentifier": "t_contract$_IERC20_$777", "typeString": "contract IERC20" } }, "id": 30329, "nodeType": "ArrayTypeName", "src": "959:8:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_storage_ptr", "typeString": "contract IERC20[]" } }, "visibility": "internal" }, { "constant": false, "id": 30333, "mutability": "mutable", "name": "amounts", "nameLocation": "1008:7:26", "nodeType": "VariableDeclaration", "scope": 30341, "src": "991:24:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[]" }, "typeName": { "baseType": { "id": 30331, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "991:7:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "id": 30332, "nodeType": "ArrayTypeName", "src": "991:9:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_storage_ptr", "typeString": "uint256[]" } }, "visibility": "internal" }, { "constant": false, "id": 30336, "mutability": "mutable", "name": "feeAmounts", "nameLocation": "1042:10:26", "nodeType": "VariableDeclaration", "scope": 30341, "src": "1025:27:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[]" }, "typeName": { "baseType": { "id": 30334, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "1025:7:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "id": 30335, "nodeType": "ArrayTypeName", "src": "1025:9:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_storage_ptr", "typeString": "uint256[]" } }, "visibility": "internal" }, { "constant": false, "id": 30338, "mutability": "mutable", "name": "userData", "nameLocation": "1075:8:26", "nodeType": "VariableDeclaration", "scope": 30341, "src": "1062:21:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_bytes_memory_ptr", "typeString": "bytes" }, "typeName": { "id": 30337, "name": "bytes", "nodeType": "ElementaryTypeName", "src": "1062:5:26", "typeDescriptions": { "typeIdentifier": "t_bytes_storage_ptr", "typeString": "bytes" } }, "visibility": "internal" } ], "src": "949:140:26" }, "returnParameters": { "id": 30340, "nodeType": "ParameterList", "parameters": [], "src": "1098:0:26" }, "scope": 30342, "stateMutability": "nonpayable", "virtual": false, "visibility": "external" } ], "abstract": false, "baseContracts": [], "canonicalName": "IFlashLoanRecipient", "contractDependencies": [], "contractKind": "interface", "fullyImplemented": false, "linearizedBaseContracts": [ 30342 ], "name": "IFlashLoanRecipient", "nameLocation": "397:19:26", "scope": 30460, "usedErrors": [] }, { "id": 30459, "nodeType": "ContractDefinition", "src": "1103:1241:26", "nodes": [ { "id": 30352, "nodeType": "VariableDeclaration", "src": "1170:90:26", "nodes": [], "constant": true, "mutability": "constant", "name": "vault", "nameLocation": "1194:5:26", "scope": 30459, "stateVariable": true, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_contract$_IVault_$30325", "typeString": "contract IVault" }, "typeName": { "id": 30348, "nodeType": "UserDefinedTypeName", "pathNode": { "id": 30347, "name": "IVault", "nameLocations": [ "1170:6:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 30325, "src": "1170:6:26" }, "referencedDeclaration": 30325, "src": "1170:6:26", "typeDescriptions": { "typeIdentifier": "t_contract$_IVault_$30325", "typeString": "contract IVault" } }, "value": { "arguments": [ { "hexValue": "307842413132323232323232323238643842613434353935386137356130373034643536364246324338", "id": 30350, "isConstant": false, "isLValue": false, "isPure": true, "kind": "number", "lValueRequested": false, "nodeType": "Literal", "src": "1217:42:26", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" }, "value": "0xBA12222222228d8Ba445958a75a0704d566BF2C8" } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_address", "typeString": "address" } ], "id": 30349, "name": "IVault", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30325, "src": "1210:6:26", "typeDescriptions": { "typeIdentifier": "t_type$_t_contract$_IVault_$30325_$", "typeString": "type(contract IVault)" } }, "id": 30351, "isConstant": false, "isLValue": false, "isPure": true, "kind": "typeConversion", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "1210:50:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_contract$_IVault_$30325", "typeString": "contract IVault" } }, "visibility": "private" }, { "id": 30361, "nodeType": "FunctionDefinition", "src": "1267:63:26", "nodes": [], "body": { "id": 30360, "nodeType": "Block", "src": "1328:2:26", "nodes": [], "statements": [] }, "implemented": true, "kind": "constructor", "modifiers": [ { "arguments": [ { "id": 30357, "name": "_wethAddress", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30354, "src": "1314:12:26", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } } ], "id": 30358, "kind": "baseConstructorSpecifier", "modifierName": { "id": 30356, "name": "BlindBackrun", "nameLocations": [ "1301:12:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 32259, "src": "1301:12:26" }, "nodeType": "ModifierInvocation", "src": "1301:26:26" } ], "name": "", "nameLocation": "-1:-1:-1", "parameters": { "id": 30355, "nodeType": "ParameterList", "parameters": [ { "constant": false, "id": 30354, "mutability": "mutable", "name": "_wethAddress", "nameLocation": "1287:12:26", "nodeType": "VariableDeclaration", "scope": 30361, "src": "1279:20:26", "stateVariable": false, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" }, "typeName": { "id": 30353, "name": "address", "nodeType": "ElementaryTypeName", "src": "1279:7:26", "stateMutability": "nonpayable", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } }, "visibility": "internal" } ], "src": "1278:22:26" }, "returnParameters": { "id": 30359, "nodeType": "ParameterList", "parameters": [], "src": "1328:0:26" }, "scope": 30459, "stateMutability": "nonpayable", "virtual": false, "visibility": "public" }, { "id": 30385, "nodeType": "FunctionDefinition", "src": "1336:210:26", "nodes": [], "body": { "id": 30384, "nodeType": "Block", "src": "1481:65:26", "nodes": [], "statements": [ { "expression": { "arguments": [ { "id": 30378, "name": "this", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": -28, "src": "1507:4:26", "typeDescriptions": { "typeIdentifier": "t_contract$_BlindBackrunFL_$30459", "typeString": "contract BlindBackrunFL" } }, { "id": 30379, "name": "tokens", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30365, "src": "1513:6:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_memory_ptr", "typeString": "contract IERC20[] memory" } }, { "id": 30380, "name": "amounts", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30368, "src": "1521:7:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[] memory" } }, { "id": 30381, "name": "userData", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30370, "src": "1530:8:26", "typeDescriptions": { "typeIdentifier": "t_bytes_memory_ptr", "typeString": "bytes memory" } } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_contract$_BlindBackrunFL_$30459", "typeString": "contract BlindBackrunFL" }, { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_memory_ptr", "typeString": "contract IERC20[] memory" }, { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[] memory" }, { "typeIdentifier": "t_bytes_memory_ptr", "typeString": "bytes memory" } ], "expression": { "id": 30375, "name": "vault", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30352, "src": "1491:5:26", "typeDescriptions": { "typeIdentifier": "t_contract$_IVault_$30325", "typeString": "contract IVault" } }, "id": 30377, "isConstant": false, "isLValue": false, "isPure": false, "lValueRequested": false, "memberLocation": "1497:9:26", "memberName": "flashLoan", "nodeType": "MemberAccess", "referencedDeclaration": 30324, "src": "1491:15:26", "typeDescriptions": { "typeIdentifier": "t_function_external_nonpayable$_t_contract$_IFlashLoanRecipient_$30342_$_t_array$_t_contract$_IERC20_$777_$dyn_memory_ptr_$_t_array$_t_uint256_$dyn_memory_ptr_$_t_bytes_memory_ptr_$returns$__$", "typeString": "function (contract IFlashLoanRecipient,contract IERC20[] memory,uint256[] memory,bytes memory) external" } }, "id": 30382, "isConstant": false, "isLValue": false, "isPure": false, "kind": "functionCall", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "1491:48:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_tuple$__$", "typeString": "tuple()" } }, "id": 30383, "nodeType": "ExpressionStatement", "src": "1491:48:26" } ] }, "functionSelector": "c9a69562", "implemented": true, "kind": "function", "modifiers": [ { "id": 30373, "kind": "modifierInvocation", "modifierName": { "id": 30372, "name": "onlyOwner", "nameLocations": [ "1471:9:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 31, "src": "1471:9:26" }, "nodeType": "ModifierInvocation", "src": "1471:9:26" } ], "name": "makeFlashLoan", "nameLocation": "1345:13:26", "parameters": { "id": 30371, "nodeType": "ParameterList", "parameters": [ { "constant": false, "id": 30365, "mutability": "mutable", "name": "tokens", "nameLocation": "1384:6:26", "nodeType": "VariableDeclaration", "scope": 30385, "src": "1368:22:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_memory_ptr", "typeString": "contract IERC20[]" }, "typeName": { "baseType": { "id": 30363, "nodeType": "UserDefinedTypeName", "pathNode": { "id": 30362, "name": "IERC20", "nameLocations": [ "1368:6:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 777, "src": "1368:6:26" }, "referencedDeclaration": 777, "src": "1368:6:26", "typeDescriptions": { "typeIdentifier": "t_contract$_IERC20_$777", "typeString": "contract IERC20" } }, "id": 30364, "nodeType": "ArrayTypeName", "src": "1368:8:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_storage_ptr", "typeString": "contract IERC20[]" } }, "visibility": "internal" }, { "constant": false, "id": 30368, "mutability": "mutable", "name": "amounts", "nameLocation": "1417:7:26", "nodeType": "VariableDeclaration", "scope": 30385, "src": "1400:24:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[]" }, "typeName": { "baseType": { "id": 30366, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "1400:7:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "id": 30367, "nodeType": "ArrayTypeName", "src": "1400:9:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_storage_ptr", "typeString": "uint256[]" } }, "visibility": "internal" }, { "constant": false, "id": 30370, "mutability": "mutable", "name": "userData", "nameLocation": "1447:8:26", "nodeType": "VariableDeclaration", "scope": 30385, "src": "1434:21:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_bytes_memory_ptr", "typeString": "bytes" }, "typeName": { "id": 30369, "name": "bytes", "nodeType": "ElementaryTypeName", "src": "1434:5:26", "typeDescriptions": { "typeIdentifier": "t_bytes_storage_ptr", "typeString": "bytes" } }, "visibility": "internal" } ], "src": "1358:103:26" }, "returnParameters": { "id": 30374, "nodeType": "ParameterList", "parameters": [], "src": "1481:0:26" }, "scope": 30459, "stateMutability": "nonpayable", "virtual": false, "visibility": "external" }, { "id": 30458, "nodeType": "FunctionDefinition", "src": "1552:790:26", "nodes": [], "body": { "id": 30457, "nodeType": "Block", "src": "1727:615:26", "nodes": [], "statements": [ { "expression": { "arguments": [ { "commonType": { "typeIdentifier": "t_address", "typeString": "address" }, "id": 30407, "isConstant": false, "isLValue": false, "isPure": false, "lValueRequested": false, "leftExpression": { "expression": { "id": 30401, "name": "msg", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": -15, "src": "1758:3:26", "typeDescriptions": { "typeIdentifier": "t_magic_message", "typeString": "msg" } }, "id": 30402, "isConstant": false, "isLValue": false, "isPure": false, "lValueRequested": false, "memberLocation": "1762:6:26", "memberName": "sender", "nodeType": "MemberAccess", "src": "1758:10:26", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } }, "nodeType": "BinaryOperation", "operator": "==", "rightExpression": { "arguments": [ { "id": 30405, "name": "vault", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30352, "src": "1780:5:26", "typeDescriptions": { "typeIdentifier": "t_contract$_IVault_$30325", "typeString": "contract IVault" } } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_contract$_IVault_$30325", "typeString": "contract IVault" } ], "id": 30404, "isConstant": false, "isLValue": false, "isPure": true, "lValueRequested": false, "nodeType": "ElementaryTypeNameExpression", "src": "1772:7:26", "typeDescriptions": { "typeIdentifier": "t_type$_t_address_$", "typeString": "type(address)" }, "typeName": { "id": 30403, "name": "address", "nodeType": "ElementaryTypeName", "src": "1772:7:26", "typeDescriptions": {} } }, "id": 30406, "isConstant": false, "isLValue": false, "isPure": true, "kind": "typeConversion", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "1772:14:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } }, "src": "1758:28:26", "typeDescriptions": { "typeIdentifier": "t_bool", "typeString": "bool" } }, { "hexValue": "466c6173684c6f616e526563697069656e743a2063616c6c6572206973206e6f7420746865207661756c74", "id": 30408, "isConstant": false, "isLValue": false, "isPure": true, "kind": "string", "lValueRequested": false, "nodeType": "Literal", "src": "1800:45:26", "typeDescriptions": { "typeIdentifier": "t_stringliteral_0f31b4f6d08b07b44b6c6f09cb866661e71ab79b49d3cbdc3ea1d936d7a195c5", "typeString": "literal_string \"FlashLoanRecipient: caller is not the vault\"" }, "value": "FlashLoanRecipient: caller is not the vault" } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_bool", "typeString": "bool" }, { "typeIdentifier": "t_stringliteral_0f31b4f6d08b07b44b6c6f09cb866661e71ab79b49d3cbdc3ea1d936d7a195c5", "typeString": "literal_string \"FlashLoanRecipient: caller is not the vault\"" } ], "id": 30400, "name": "require", "nodeType": "Identifier", "overloadedDeclarations": [ -18, -18 ], "referencedDeclaration": -18, "src": "1737:7:26", "typeDescriptions": { "typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$", "typeString": "function (bool,string memory) pure" } }, "id": 30409, "isConstant": false, "isLValue": false, "isPure": false, "kind": "functionCall", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "1737:118:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_tuple$__$", "typeString": "tuple()" } }, "id": 30410, "nodeType": "ExpressionStatement", "src": "1737:118:26" }, { "assignments": [ 30412, 30414, 30416 ], "declarations": [ { "constant": false, "id": 30412, "mutability": "mutable", "name": "firstPairAddress", "nameLocation": "1888:16:26", "nodeType": "VariableDeclaration", "scope": 30457, "src": "1880:24:26", "stateVariable": false, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" }, "typeName": { "id": 30411, "name": "address", "nodeType": "ElementaryTypeName", "src": "1880:7:26", "stateMutability": "nonpayable", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } }, "visibility": "internal" }, { "constant": false, "id": 30414, "mutability": "mutable", "name": "secondPairAddress", "nameLocation": "1926:17:26", "nodeType": "VariableDeclaration", "scope": 30457, "src": "1918:25:26", "stateVariable": false, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" }, "typeName": { "id": 30413, "name": "address", "nodeType": "ElementaryTypeName", "src": "1918:7:26", "stateMutability": "nonpayable", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } }, "visibility": "internal" }, { "constant": false, "id": 30416, "mutability": "mutable", "name": "percentageToPayToCoinbase", "nameLocation": "1965:25:26", "nodeType": "VariableDeclaration", "scope": 30457, "src": "1957:33:26", "stateVariable": false, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" }, "typeName": { "id": 30415, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "1957:7:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "visibility": "internal" } ], "id": 30428, "initialValue": { "arguments": [ { "id": 30419, "name": "userData", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30397, "src": "2014:8:26", "typeDescriptions": { "typeIdentifier": "t_bytes_memory_ptr", "typeString": "bytes memory" } }, { "components": [ { "id": 30421, "isConstant": false, "isLValue": false, "isPure": true, "lValueRequested": false, "nodeType": "ElementaryTypeNameExpression", "src": "2025:7:26", "typeDescriptions": { "typeIdentifier": "t_type$_t_address_$", "typeString": "type(address)" }, "typeName": { "id": 30420, "name": "address", "nodeType": "ElementaryTypeName", "src": "2025:7:26", "typeDescriptions": {} } }, { "id": 30423, "isConstant": false, "isLValue": false, "isPure": true, "lValueRequested": false, "nodeType": "ElementaryTypeNameExpression", "src": "2034:7:26", "typeDescriptions": { "typeIdentifier": "t_type$_t_address_$", "typeString": "type(address)" }, "typeName": { "id": 30422, "name": "address", "nodeType": "ElementaryTypeName", "src": "2034:7:26", "typeDescriptions": {} } }, { "id": 30425, "isConstant": false, "isLValue": false, "isPure": true, "lValueRequested": false, "nodeType": "ElementaryTypeNameExpression", "src": "2043:7:26", "typeDescriptions": { "typeIdentifier": "t_type$_t_uint256_$", "typeString": "type(uint256)" }, "typeName": { "id": 30424, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "2043:7:26", "typeDescriptions": {} } } ], "id": 30426, "isConstant": false, "isInlineArray": false, "isLValue": false, "isPure": true, "lValueRequested": false, "nodeType": "TupleExpression", "src": "2024:27:26", "typeDescriptions": { "typeIdentifier": "t_tuple$_t_type$_t_address_$_$_t_type$_t_address_$_$_t_type$_t_uint256_$_$", "typeString": "tuple(type(address),type(address),type(uint256))" } } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_bytes_memory_ptr", "typeString": "bytes memory" }, { "typeIdentifier": "t_tuple$_t_type$_t_address_$_$_t_type$_t_address_$_$_t_type$_t_uint256_$_$", "typeString": "tuple(type(address),type(address),type(uint256))" } ], "expression": { "id": 30417, "name": "abi", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": -1, "src": "2003:3:26", "typeDescriptions": { "typeIdentifier": "t_magic_abi", "typeString": "abi" } }, "id": 30418, "isConstant": false, "isLValue": false, "isPure": true, "lValueRequested": false, "memberLocation": "2007:6:26", "memberName": "decode", "nodeType": "MemberAccess", "src": "2003:10:26", "typeDescriptions": { "typeIdentifier": "t_function_abidecode_pure$__$returns$__$", "typeString": "function () pure" } }, "id": 30427, "isConstant": false, "isLValue": false, "isPure": false, "kind": "functionCall", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "2003:49:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_tuple$_t_address_payable_$_t_address_payable_$_t_uint256_$", "typeString": "tuple(address payable,address payable,uint256)" } }, "nodeType": "VariableDeclarationStatement", "src": "1866:186:26" }, { "expression": { "arguments": [ { "id": 30430, "name": "secondPairAddress", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30414, "src": "2093:17:26", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } }, { "id": 30431, "name": "firstPairAddress", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30412, "src": "2124:16:26", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } }, { "id": 30432, "name": "percentageToPayToCoinbase", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30416, "src": "2154:25:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, { "arguments": [ { "id": 30435, "name": "this", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": -28, "src": "2201:4:26", "typeDescriptions": { "typeIdentifier": "t_contract$_BlindBackrunFL_$30459", "typeString": "contract BlindBackrunFL" } } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_contract$_BlindBackrunFL_$30459", "typeString": "contract BlindBackrunFL" } ], "id": 30434, "isConstant": false, "isLValue": false, "isPure": true, "lValueRequested": false, "nodeType": "ElementaryTypeNameExpression", "src": "2193:7:26", "typeDescriptions": { "typeIdentifier": "t_type$_t_address_$", "typeString": "type(address)" }, "typeName": { "id": 30433, "name": "address", "nodeType": "ElementaryTypeName", "src": "2193:7:26", "typeDescriptions": {} } }, "id": 30436, "isConstant": false, "isLValue": false, "isPure": false, "kind": "typeConversion", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "2193:13:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_address", "typeString": "address" }, { "typeIdentifier": "t_address", "typeString": "address" }, { "typeIdentifier": "t_uint256", "typeString": "uint256" }, { "typeIdentifier": "t_address", "typeString": "address" } ], "id": 30429, "name": "executeArbitrage", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 31797, "src": "2063:16:26", "typeDescriptions": { "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_uint256_$_t_address_$returns$__$", "typeString": "function (address,address,uint256,address)" } }, "id": 30437, "isConstant": false, "isLValue": false, "isPure": false, "kind": "functionCall", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "2063:153:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_tuple$__$", "typeString": "tuple()" } }, "id": 30438, "nodeType": "ExpressionStatement", "src": "2063:153:26" }, { "expression": { "arguments": [ { "arguments": [ { "id": 30445, "name": "vault", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30352, "src": "2277:5:26", "typeDescriptions": { "typeIdentifier": "t_contract$_IVault_$30325", "typeString": "contract IVault" } } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_contract$_IVault_$30325", "typeString": "contract IVault" } ], "id": 30444, "isConstant": false, "isLValue": false, "isPure": true, "lValueRequested": false, "nodeType": "ElementaryTypeNameExpression", "src": "2269:7:26", "typeDescriptions": { "typeIdentifier": "t_type$_t_address_$", "typeString": "type(address)" }, "typeName": { "id": 30443, "name": "address", "nodeType": "ElementaryTypeName", "src": "2269:7:26", "typeDescriptions": {} } }, "id": 30446, "isConstant": false, "isLValue": false, "isPure": true, "kind": "typeConversion", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "2269:14:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } }, { "commonType": { "typeIdentifier": "t_uint256", "typeString": "uint256" }, "id": 30454, "isConstant": false, "isLValue": false, "isPure": false, "lValueRequested": false, "leftExpression": { "baseExpression": { "id": 30447, "name": "amounts", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30392, "src": "2297:7:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[] memory" } }, "id": 30449, "indexExpression": { "hexValue": "30", "id": 30448, "isConstant": false, "isLValue": false, "isPure": true, "kind": "number", "lValueRequested": false, "nodeType": "Literal", "src": "2305:1:26", "typeDescriptions": { "typeIdentifier": "t_rational_0_by_1", "typeString": "int_const 0" }, "value": "0" }, "isConstant": false, "isLValue": true, "isPure": false, "lValueRequested": false, "nodeType": "IndexAccess", "src": "2297:10:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "nodeType": "BinaryOperation", "operator": "+", "rightExpression": { "components": [ { "baseExpression": { "id": 30450, "name": "feeAmounts", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 30395, "src": "2311:10:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[] memory" } }, "id": 30452, "indexExpression": { "hexValue": "30", "id": 30451, "isConstant": false, "isLValue": false, "isPure": true, "kind": "number", "lValueRequested": false, "nodeType": "Literal", "src": "2322:1:26", "typeDescriptions": { "typeIdentifier": "t_rational_0_by_1", "typeString": "int_const 0" }, "value": "0" }, "isConstant": false, "isLValue": true, "isPure": false, "lValueRequested": false, "nodeType": "IndexAccess", "src": "2311:13:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } } ], "id": 30453, "isConstant": false, "isInlineArray": false, "isLValue": false, "isPure": false, "lValueRequested": false, "nodeType": "TupleExpression", "src": "2310:15:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "src": "2297:28:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_address", "typeString": "address" }, { "typeIdentifier": "t_uint256", "typeString": "uint256" } ], "expression": { "arguments": [ { "id": 30440, "name": "WETH_ADDRESS", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 31558, "src": "2233:12:26", "typeDescriptions": { "typeIdentifier": "t_address", "typeString": "address" } } ], "expression": { "argumentTypes": [ { "typeIdentifier": "t_address", "typeString": "address" } ], "id": 30439, "name": "IWETH", "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 31507, "src": "2227:5:26", "typeDescriptions": { "typeIdentifier": "t_type$_t_contract$_IWETH_$31507_$", "typeString": "type(contract IWETH)" } }, "id": 30441, "isConstant": false, "isLValue": false, "isPure": false, "kind": "typeConversion", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "2227:19:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_contract$_IWETH_$31507", "typeString": "contract IWETH" } }, "id": 30442, "isConstant": false, "isLValue": false, "isPure": false, "lValueRequested": false, "memberLocation": "2247:8:26", "memberName": "transfer", "nodeType": "MemberAccess", "referencedDeclaration": 744, "src": "2227:28:26", "typeDescriptions": { "typeIdentifier": "t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$", "typeString": "function (address,uint256) external returns (bool)" } }, "id": 30455, "isConstant": false, "isLValue": false, "isPure": false, "kind": "functionCall", "lValueRequested": false, "nameLocations": [], "names": [], "nodeType": "FunctionCall", "src": "2227:108:26", "tryCall": false, "typeDescriptions": { "typeIdentifier": "t_bool", "typeString": "bool" } }, "id": 30456, "nodeType": "ExpressionStatement", "src": "2227:108:26" } ] }, "baseFunctions": [ 30341 ], "functionSelector": "f04f2707", "implemented": true, "kind": "function", "modifiers": [], "name": "receiveFlashLoan", "nameLocation": "1561:16:26", "parameters": { "id": 30398, "nodeType": "ParameterList", "parameters": [ { "constant": false, "id": 30389, "mutability": "mutable", "name": "tokens", "nameLocation": "1603:6:26", "nodeType": "VariableDeclaration", "scope": 30458, "src": "1587:22:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_memory_ptr", "typeString": "contract IERC20[]" }, "typeName": { "baseType": { "id": 30387, "nodeType": "UserDefinedTypeName", "pathNode": { "id": 30386, "name": "IERC20", "nameLocations": [ "1587:6:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 777, "src": "1587:6:26" }, "referencedDeclaration": 777, "src": "1587:6:26", "typeDescriptions": { "typeIdentifier": "t_contract$_IERC20_$777", "typeString": "contract IERC20" } }, "id": 30388, "nodeType": "ArrayTypeName", "src": "1587:8:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_contract$_IERC20_$777_$dyn_storage_ptr", "typeString": "contract IERC20[]" } }, "visibility": "internal" }, { "constant": false, "id": 30392, "mutability": "mutable", "name": "amounts", "nameLocation": "1636:7:26", "nodeType": "VariableDeclaration", "scope": 30458, "src": "1619:24:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[]" }, "typeName": { "baseType": { "id": 30390, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "1619:7:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "id": 30391, "nodeType": "ArrayTypeName", "src": "1619:9:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_storage_ptr", "typeString": "uint256[]" } }, "visibility": "internal" }, { "constant": false, "id": 30395, "mutability": "mutable", "name": "feeAmounts", "nameLocation": "1670:10:26", "nodeType": "VariableDeclaration", "scope": 30458, "src": "1653:27:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_memory_ptr", "typeString": "uint256[]" }, "typeName": { "baseType": { "id": 30393, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "1653:7:26", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "id": 30394, "nodeType": "ArrayTypeName", "src": "1653:9:26", "typeDescriptions": { "typeIdentifier": "t_array$_t_uint256_$dyn_storage_ptr", "typeString": "uint256[]" } }, "visibility": "internal" }, { "constant": false, "id": 30397, "mutability": "mutable", "name": "userData", "nameLocation": "1703:8:26", "nodeType": "VariableDeclaration", "scope": 30458, "src": "1690:21:26", "stateVariable": false, "storageLocation": "memory", "typeDescriptions": { "typeIdentifier": "t_bytes_memory_ptr", "typeString": "bytes" }, "typeName": { "id": 30396, "name": "bytes", "nodeType": "ElementaryTypeName", "src": "1690:5:26", "typeDescriptions": { "typeIdentifier": "t_bytes_storage_ptr", "typeString": "bytes" } }, "visibility": "internal" } ], "src": "1577:140:26" }, "returnParameters": { "id": 30399, "nodeType": "ParameterList", "parameters": [], "src": "1727:0:26" }, "scope": 30459, "stateMutability": "nonpayable", "virtual": false, "visibility": "external" } ], "abstract": false, "baseContracts": [ { "baseName": { "id": 30343, "name": "BlindBackrun", "nameLocations": [ "1130:12:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 32259, "src": "1130:12:26" }, "id": 30344, "nodeType": "InheritanceSpecifier", "src": "1130:12:26" }, { "baseName": { "id": 30345, "name": "IFlashLoanRecipient", "nameLocations": [ "1144:19:26" ], "nodeType": "IdentifierPath", "referencedDeclaration": 30342, "src": "1144:19:26" }, "id": 30346, "nodeType": "InheritanceSpecifier", "src": "1144:19:26" } ], "canonicalName": "BlindBackrunFL", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, "linearizedBaseContracts": [ 30459, 30342, 32259, 112, 824 ], "name": "BlindBackrunFL", "nameLocation": "1112:14:26", "scope": 30460, "usedErrors": [] } ] }, "id": 26} +``` \ No newline at end of file diff --git a/docs/specs/contracts/abi/_uniswapV2Factory.mdx b/docs/specs/contracts/abi/_uniswapV2Factory.mdx new file mode 100644 index 00000000..73cb1039 --- /dev/null +++ b/docs/specs/contracts/abi/_uniswapV2Factory.mdx @@ -0,0 +1,3 @@ +```json title="abi/uniswapV2Factory.json" +[{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"name":"setFeeToSetter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}] +``` diff --git a/docs/specs/mev-share/HintsTable.jsx b/docs/specs/mev-share/HintsTable.jsx new file mode 100644 index 00000000..d5f334d1 --- /dev/null +++ b/docs/specs/mev-share/HintsTable.jsx @@ -0,0 +1,28 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import hints from "./hints.json" + +export default function HintsTable() { + return ( + + + + + + + + + {hints.map((hint, index) => ( + + + + + ))} + +
HintDescription
{hint.name}{hint.description}
+ ); +} diff --git a/docs/specs/mev-share/_builders.mdx b/docs/specs/mev-share/_builders.mdx new file mode 100644 index 00000000..10d2d3c2 --- /dev/null +++ b/docs/specs/mev-share/_builders.mdx @@ -0,0 +1,3 @@ +import BuildersTable from "@site/src/components/mev-share/buildersTable.tsx" + + diff --git a/docs/specs/mev-share/_mev_sendBundle.mdx b/docs/specs/mev-share/_mev_sendBundle.mdx new file mode 100644 index 00000000..074ff91d --- /dev/null +++ b/docs/specs/mev-share/_mev_sendBundle.mdx @@ -0,0 +1,52 @@ + + +```typescript +/* + NOTE: optional fields are marked with a ? + example: { + privacy?: { ... } // privacy is optional + } + */ +{ + jsonrpc: "2.0", + id: string | number, + method: "mev_sendBundle", + params: [{ /* MevSendBundleParams */ + version: "v0.1", + inclusion: { + block: string, // hex-encoded number + maxBlock?: string, // hex-encoded number + }, + body: Array< + { hash: string } | + { tx: string, canRevert: boolean } | + { bundle: MevSendBundleParams } + >, + validity?: { + refund?: Array<{ + bodyIdx: number, + percent: number, + }>, + refundConfig?: Array<{ + address: string, + percent: number, + }> + }, + privacy?: { + hints?: Array< + "calldata" | + "contract_address" | + "logs" | + "function_selector" | + "hash" | + "tx_hash" | + "full" + >, + builders?: Array, + }, + metadata?: { + originId?: string, + } + }] +} +``` diff --git a/docs/specs/mev-share/_mev_simBundle.mdx b/docs/specs/mev-share/_mev_simBundle.mdx new file mode 100644 index 00000000..67fc2c1e --- /dev/null +++ b/docs/specs/mev-share/_mev_simBundle.mdx @@ -0,0 +1,55 @@ + + +```typescript +{ + jsonrpc: "2.0", + id: string | number, + method: "mev_simBundle", + params: [{ /* MevSimBundleParams */ + version: "beta-1", + inclusion: { + block: string, // hex-encoded number + maxBlock?: string, // hex-encoded number + }, + body: Array< + { hash: string } | + { tx: string, canRevert: boolean } | + { bundle: MevSimBundleParams } + >, + validity: { + refund: Array<{ + bodyIdx: number, + percent: number, + }>, + refundConfig: Array<{ + address: string, + percent: number, + }> + }, + privacy?: { + hints?: Array< + "calldata" | + "contract_address" | + "logs" | + "function_selector" | + "hash" | + "tx_hash" | + "full" + >, + builders?: Array, + }, + metadata?: { + originId?: string, + }, + simOptions?: { /* SimBundleOptions */ + parentBlock?: number | string, // Block used for simulation state. Defaults to latest block. + blockNumber?: number, // default = parentBlock.number + 1 + coinbase?: string, // default = parentBlock.coinbase + timestamp?: number, // default = parentBlock.timestamp + 12 + gasLimit?: number, // default = parentBlock.gasLimit + baseFee?: bigint, // default = parentBlock.baseFeePerGas + timeout?: number, // default = 5 (defined in seconds) + } + }] +} +``` diff --git a/docs/specs/mev-share/_streamEvent.mdx b/docs/specs/mev-share/_streamEvent.mdx new file mode 100644 index 00000000..64fd4c1c --- /dev/null +++ b/docs/specs/mev-share/_streamEvent.mdx @@ -0,0 +1,46 @@ + +```typescript +{ + hash: string, + logs?: LogParams[], + txs: Array<{ + hash?: string, + callData?: string, + functionSelector?: string, + to?: string, + from?: string, + value?: string, + maxFeePerGas?: string, + maxPriorityFeePerGas?: string, + nonce?: string, + chainId?: string, + accessList?: Array<{ + address: string, + storageKeys: string[] + }>, + gas?: string, + type?: string + }> +} +``` + +| Param | Type Info | Description | +|-|-|-| +| `hash` | Hex-string | [Double-hashed](/flashbots-mev-share/searchers/event-stream#understanding-double-hash) transaction hash, or, bundle hash | +| `logs` | Array of JSON-encoded events | Event logs emitted by executing the transaction. | +| `txs` | Array of JSON objects | Transactions from the event. Will only be one if event is a transaction, otherwise event is a bundle. +| `txs.hash` | Hex-string | Transaction hash. | +| `txs.callData` | Hex-string | Calldata of the transaction. | +| `txs.functionSelector` | Hex-string | 4-byte function selector. | +| `txs.to` | Hex-string | Transaction recipient address. | +| `txs.from` | Hex-string | Transaction sender address. | +| `txs.value` | Hex-string | Value transferred in the transaction. | +| `txs.maxFeePerGas` | Hex-string | Maximum fee per gas of the transaction. GasFeeCap | +| `txs.maxPriorityFeePerGas` | Hex-string | Maximum priority fee per gas of the transaction. GasTipCap | +| `txs.nonce` | Hex-string | Nonce of the transaction. | +| `txs.chainId` | Hex-string | Chain ID of the transaction. | +| `txs.accessList` | Array of JSON objects | Access list of the transaction. | +| `txs.accessList.address` | Hex-string | Address in the access list. | +| `txs.accessList.storageKeys` | Array of hex-strings | Storage keys in the access list. | +| `txs.gas` | Hex-string | Gas limit of the transaction. | +| `txs.type` | Hex-string | Type of the transaction. | diff --git a/docs/specs/mev-share/blurbs/_builderInheritance.mdx b/docs/specs/mev-share/blurbs/_builderInheritance.mdx new file mode 100644 index 00000000..bea8904d --- /dev/null +++ b/docs/specs/mev-share/blurbs/_builderInheritance.mdx @@ -0,0 +1,3 @@ +By default, when a user specifies which builders their transactions should be sent to (by setting `builders`), those settings are inherited by bundles which use those transactions. + +Searchers can restrict these settings by specifying `builders` in the bundle's `privacy` parameters. Specifically, by setting `builders`, the bundle is sent to the **intersection** of all builders specified by each of the bundle's transactions, and the builders specified in the bundle's `builders` parameter. diff --git a/docs/specs/mev-share/blurbs/_whatsMevShareAdvanced.mdx b/docs/specs/mev-share/blurbs/_whatsMevShareAdvanced.mdx new file mode 100644 index 00000000..3bd81cac --- /dev/null +++ b/docs/specs/mev-share/blurbs/_whatsMevShareAdvanced.mdx @@ -0,0 +1,3 @@ +MEV-Share is an open-source protocol for users, wallets, and applications to internalize the MEV that their transactions create ("orderflow auction"). It allows users to selectively share data about their transactions with searchers who bid to include the transactions in bundles. Users can choose how the searcher's bid is redistributed -- between themselves, validators, or other parties. + +MEV-Share is credibly neutral, permissionless for searchers, and does not enshrine a single block builder. It aims to reduce the centralizing impact of exclusive orderflow on Ethereum while enabling wallets and other sources of order flow to participate in the MEV supply chain. diff --git a/docs/specs/mev-share/blurbs/_whatsMevShareBasic.mdx b/docs/specs/mev-share/blurbs/_whatsMevShareBasic.mdx new file mode 100644 index 00000000..ed948f49 --- /dev/null +++ b/docs/specs/mev-share/blurbs/_whatsMevShareBasic.mdx @@ -0,0 +1 @@ +[MEV-share](https://collective.flashbots.net/t/mev-share-programmably-private-orderflow-to-share-mev-with-users/1264) is a protocol that lets users, wallets, and dapps to **capture the MEV their transactions create.** diff --git a/docs/specs/mev-share/blurbs/_whatsaMEVShareNode.mdx b/docs/specs/mev-share/blurbs/_whatsaMEVShareNode.mdx new file mode 100644 index 00000000..9ba53361 --- /dev/null +++ b/docs/specs/mev-share/blurbs/_whatsaMEVShareNode.mdx @@ -0,0 +1 @@ +A MEV-Share Node is a service that matches user transactions with searcher bundles. Flashbots runs MEV-Share Nodes on Ethereum Mainnet and Goerli. Users submit their transactions to the Node, which shares select information about transactions with searchers. Searchers propose transactions for the Node to bundle with the user transactions (currently we only support backruns). The Node forwards these bundles to a block builder with a requirement that **the user is paid a refund**; a percentage of the winning searcher's bundle profit. diff --git a/docs/specs/mev-share/hints.json b/docs/specs/mev-share/hints.json new file mode 100644 index 00000000..7e41bd26 --- /dev/null +++ b/docs/specs/mev-share/hints.json @@ -0,0 +1,34 @@ +[ + { + "name": "calldata", + "description": "Share data sent to the smart contract (if applicable) by the transaction. The function selector and contract address will also be shared if the calldata is shared." + }, + { + "name": "logs", + "description": "Share logs emitted by executing the transaction." + }, + { + "name": "default_logs", + "description": "Share specific subset of logs related to defi swaps. Partial info (the pool id and the fact that a swap was made) for curve, balancer, and uniswapV2/V3-style trades" + }, + { + "name": "function_selector", + "description": "Share the 4-byte identifier of the function being called on the smart contract by the transaction. The contract address will also be shared if the function selector is shared." + }, + { + "name": "contract_address", + "description": "Share the address of the recipient of the transaction; typically a smart contract." + }, + { + "name": "hash", + "description": "Share the transaction hash (or bundle hash if sending a bundle). To use full privacy mode, share this hint and this hint alone. The hash will always be shared if other hints are shared." + }, + { + "name": "tx_hash", + "description": "Share individual tx hashes in the bundle." + }, + { + "name": "full", + "description": "Share all fields of individual txs except signature. This includes nonce, gas price, gas limit, to, from, value, data, and chainId." + } +] diff --git a/docs/specs/protect-rpc/_hints.mdx b/docs/specs/protect-rpc/_hints.mdx new file mode 100644 index 00000000..6fa9b594 --- /dev/null +++ b/docs/specs/protect-rpc/_hints.mdx @@ -0,0 +1,8 @@ +```js +hint: "calldata" | + "contract_address" | + "function_selector" | + "logs" | + "hash" | + undefined +``` diff --git a/docs/welcome.mdx b/docs/welcome.mdx index fac35d36..1eea52fb 100644 --- a/docs/welcome.mdx +++ b/docs/welcome.mdx @@ -1,21 +1,65 @@ --- slug: / -title: welcome to flashbots +title: Welcome to Flashbots +hide_title: true description: The home page of the knowledge base keywords: - flashbots - docs --- -Flashbots is a research and development organization working on mitigating the negative externalities of current Maximal Extractable Value (from now on MEV) extraction techniques and avoiding the existential risks MEV could cause to state-rich blockchains like Ethereum. +import Grid from "@site/src/components/Grid/Grid.tsx"; +import GridBlock from "@site/src/components/GridBlock/GridBlock.tsx"; -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. +# Welcome to Flashbots -Our efforts are focused on three verticals: -1. **Flashbots Auction**: a private communication channel between miners 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. +Flashbots is a research and development organization formed to mitigate the negative externalities posed by Maximal Extractable Value (MEV) to stateful blockchains, starting with Ethereum. -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. +## Get started -[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) + + + +Discover how to capture MEV opportunities on Ethereum responsibly with Flashbots. + +- [Understanding Bundles](/flashbots-auction/advanced/understanding-bundles)
+- [Guide to Sending Transactions and Bundles on Flashbots](/guide-send-tx-bundle)
+- [Multiplexing](/flashbots-auction/advanced/multiplexing)
+- [RPC Docs](/flashbots-auction/advanced/rpc-endpoint)
+- [Client Libs](/flashbots-auction/libraries/ethers-js-provider)
+- [Help & FAQs](https://collective.flashbots.net/tags/c/searchers/12/question) + +
+ + +Link your wallet to Flashbots Protect to safeguard against frontrunning, benefit from backrunning MEV through the MEV-Share protocol, and receive assistance in recovering funds from scams. + +- [Flashbots Protect](/flashbots-protect/quick-start) +- [Scam Victims Hotline](https://whitehat.flashbots.net) + + + + +Leverage MEV-Boost to access a competitive block-building market, fostering greater competition, decentralization, and censorship-resistance for Ethereum. + +- [MEV-Boost Docs](/flashbots-mev-boost/introduction)
+ +
+
+ +## About Flashbots + +Our primary focus is to enable a permissionless, transparent, and sustainable ecosystem for MEV, via a three-pronged approach: + +- **Illuminate**: bringing transparency to MEV activity, quantifying its impact, and reducing information asymmetry between participants. +- **Democratize**: democratizing access to MEV via open platforms that maximize competition and are freely available to all. +- **Distribute**: enabling sustainable distribution of any remaining MEV. + +Product & research are the semi-autonomous dual engines that propel our organization forward: + +- [Flashbots Product](/) builds core infrastructure and ecosystem tooling that redefine the block production supply chain across blockchains and protect users. +- [Flashbots Research](https://github.com/flashbots/mev-research) explores MEV market dynamics and blockchain design challenges at the intersection of economics, security, and cryptography. + +You can interact with Flashbots via our [Forum](https://collective.flashbots.net/) where we have dedicated categories for each of our efforts and welcome your contributions. Our work is open source and you can follow our progress under each [Github](https://github.com/flashbots/pm) repository of the Flashbots organization. + +[Mission](https://writings.flashbots.net/frontrunning-mev-crisis) | [Forum](https://collective.flashbots.net/) | [Writings](https://writings.flashbots.net) | [GitHub](https://github.com/flashbots/pm) | [Discord](https://discord.gg/7hvTycdNcK) | [Status](https://status.flashbots.net) diff --git a/docs/whitehat.mdx b/docs/whitehat.mdx index 8c63010b..b77c9314 100644 --- a/docs/whitehat.mdx +++ b/docs/whitehat.mdx @@ -1,8 +1,12 @@ --- -title: whitehat hotline +title: Whitehat Hotline --- -Hello! Your wallet has been compromised and you've been redirected to this page. -We're here to help. +If your wallet has been compromised by a malicious third party and you need help recovering remaining funds, we are here to help Please go to https://whitehat.flashbots.net (and only to this address) to submit a request for help. + +Ensure you only interact with [Flashbots Discord](https://discord.gg/flashbots) members with the "whitehat", "whitehat-associate", or "serv.eth" role. + +We can only attempt to rescue remaining funds, we won't be able to get back funds that have already been transferred out from the address. +Please note that the Whitehat team can only assist if remaining assets in the compromised address exceed the minimum rescue amount of $1000. diff --git a/docusaurus.config.js b/docusaurus.config.js index 5e5fb719..5a7a4048 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -1,87 +1,120 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ require('dotenv').config() -const math = require('remark-math'); -const katex = require('rehype-katex'); -const lightCodeTheme = require("prism-react-renderer/themes/github") -const darkCodeTheme = require("prism-react-renderer/themes/dracula"); +const { themes: { github: lightCodeTheme } } = require('prism-react-renderer'); +const { themes: { dracula: darkCodeTheme } } = require('prism-react-renderer'); +const tailwindcss = require('tailwindcss'); +const autoprefixer = require('autoprefixer'); -// With JSDoc @type annotations, IDEs can provide config autocompletion -/** @type {import('@docusaurus/types').DocusaurusConfig} */ -(module.exports = { - title: 'Flashbots Docs', - tagline: 'Flashbots repository of knowledge', - baseUrl: process.env.BASE_URL, - onBrokenLinks: 'throw', - onBrokenMarkdownLinks: 'warn', - favicon: 'img/favicon.ico', - organizationName: 'flashbots', - projectName: 'docs', - url: process.env.TARGET_URL, - stylesheets: [ - { - href: 'https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css', - type: 'text/css', - integrity: - 'sha384-AfEj0r4/OFrOo5t7NnNe46zW/tFgW6x/bCJG8FqQCEo3+Aro6EYUG4+cU+KJWu/X', - crossorigin: 'anonymous', - }, - ], - themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - ({ - algolia: { - apiKey: '693df7609c6aeaac03b78418095b79c4', - indexName: 'flashbots', - // Optional: see doc section below - appId: 'BH4D9OD16A', - }, - prism: { - theme: lightCodeTheme, - darkTheme: darkCodeTheme, - additionalLanguages: ['solidity'] +/** @returns {Promise} */ +module.exports = async function createConfigAsync() { + return { + title: 'Flashbots Docs', + tagline: 'Flashbots repository of knowledge', + baseUrl: process.env.BASE_URL, + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'warn', + favicon: 'img/favicon.ico', + organizationName: 'flashbots', + projectName: 'docs', + trailingSlash: false, + url: process.env.TARGET_URL, + stylesheets: [ + { + href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', + type: 'text/css', + integrity: + 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', + crossorigin: 'anonymous', }, - hideableSidebar: true, - navbar: { - title: 'Flashbots Docs', - logo: { - alt: 'Flashbots Logo', - src: 'img/logo.png', - }, - items: [ - { - href: 'https://github.com/flashbots/docs', - label: 'GitHub', - position: 'right', - }, - ], - } - - }), - presets: [ - [ - '@docusaurus/preset-classic', - /** @type {import('@docusaurus/preset-classic').Options} */ + ], + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ - docs: { - sidebarPath: require.resolve('./docs/sidebars.js'), - // Please change this to your repo. - routeBasePath: '/', - // editUrl: - // 'https://github.com/flashbots/docs/edit/main/', - remarkPlugins: [math], - rehypePlugins: [katex], + algolia: { + apiKey: process.env.ALGOLIA_SEARCH_API_KEY, + indexName: process.env.ALGOLIA_INDEX_NAME, + appId: process.env.ALGOLIA_APP_ID, + }, + prism: { + theme: lightCodeTheme, + darkTheme: darkCodeTheme, + additionalLanguages: ['solidity', 'uri', 'ini', 'rust'] }, - theme: { - customCss: require.resolve('./src/css/custom.css'), + docs: { + sidebar: { + hideable: true + } }, + navbar: { + title: 'Flashbots', + logo: { + alt: 'Flashbots Logo', + src: 'img/logo.png', + }, + items: [ + { + type: 'docSidebar', + label: 'Docs', + sidebarId: 'docs', + position: 'left', + }, + { + type: 'docSidebar', + label: 'API', + sidebarId: 'api', + position: 'left', + }, + { + href: 'https://github.com/flashbots/docs', + label: 'GitHub', + position: 'right', + }, + ], + } + }), + presets: [ + [ + '@docusaurus/preset-classic', + /** @type {import('@docusaurus/preset-classic').Options} */ + ({ + debug: true, // force debug plugin usage + docs: { + sidebarPath: require.resolve('./docs/sidebars.js'), + // Please change this to your repo. + routeBasePath: '/', + editUrl: + 'https://github.com/flashbots/flashbots-docs/edit/main/', + showLastUpdateTime: true, + remarkPlugins: [(await import('remark-math')).default], + rehypePlugins: [(await import('rehype-katex')).default], + }, + theme: { + customCss: require.resolve('./src/css/custom.css'), + }, + }), + ], ], - ], - plugins: [ - [ - "docusaurus2-dotenv", - { - systemvars: true, + plugins: [ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async function tailwindcssSupport(context, options) { + return { + name: "docusaurus-tailwindcss", + configurePostCss(postcssOptions) { + // Appends TailwindCSS and AutoPrefixer. + postcssOptions.plugins.push('tailwindcss/nesting') + postcssOptions.plugins.push(tailwindcss); + postcssOptions.plugins.push(autoprefixer); + return postcssOptions; + }, + }; }, + 'docusaurus-plugin-sass' ], - ], -}) + } +} diff --git a/package.json b/package.json index 54475cd1..0705b12f 100644 --- a/package.json +++ b/package.json @@ -4,28 +4,52 @@ "private": true, "scripts": { "docusaurus": "docusaurus", - "setup-cname": "node ./scripts/setup-cname.js", - "start": "docusaurus start", + "start": "docusaurus start --port 3000 --host 0.0.0.0", "build": "docusaurus build", "swizzle": "docusaurus swizzle", - "deploy": "npm run setup-cname && docusaurus deploy", "clear": "docusaurus clear", "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", - "write-heading-ids": "docusaurus write-heading-ids" + "write-heading-ids": "docusaurus write-heading-ids", + "lint": "yarn lint:js && yarn lint:style && yarn lint:spelling", + "lint:ci": "yarn lint:js --quiet && yarn lint:style && yarn lint:spelling", + "lint:js": "eslint --cache --report-unused-disable-directives \"**/*.{js,jsx,ts,tsx,mjs}\"", + "lint:spelling": "cspell \"**\" --no-progress", + "lint:style": "stylelint \"**/*.css\"", + "format": "prettier --write .", + "format:diff": "prettier --list-different ." }, "dependencies": { - "@docusaurus/core": "2.0.0-beta.6", - "@docusaurus/plugin-content-docs": "2.0.0-beta.6", - "@docusaurus/preset-classic": "2.0.0-beta.6", - "@mdx-js/react": "^1.6.21", + "@algolia/client-search": "^4.20.0", + "@docusaurus/core": "^3.0.0", + "@docusaurus/plugin-content-docs": "^3.0.0", + "@docusaurus/plugin-sitemap": "^3.0.0", + "@docusaurus/preset-classic": "^3.0.0", + "@docusaurus/utils": "^3.0.0", + "@docusaurus/utils-common": "^3.0.0", + "@mdx-js/react": "^3.0.0", + "@radix-ui/react-switch": "^1.0.3", + "@vercel/analytics": "^0.1.11", + "autoprefixer": "^10.4.16", + "axios": "^1.6.0", + "change-case": "^5.1.2", "clsx": "^1.1.1", - "docusaurus2-dotenv": "^1.4.0", + "docusaurus-plugin-sass": "^0.2.5", "dotenv": "^8.2.0", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "rehype-katex": "^4.0.0", - "remark-math": "3.0.1" + "ethers": "^6.7.1", + "postcss": "^8.4.31", + "prism-react-renderer": "^2.1.0", + "prop-types": "^15.8.1", + "protect-button": "^0.4.6", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-loadable": "^5.5.0", + "rehype-katex": "^7", + "remark-math": "^6", + "sass": "^1.69.5", + "search-insights": "^2.8.3", + "tailwindcss": "^3.3.3", + "webpack": "^5.88.1" }, "browserslist": { "production": [ @@ -40,11 +64,43 @@ ] }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.6", - "@tsconfig/docusaurus": "^1.0.2", - "@types/react": "^17.0.3", - "@types/react-helmet": "^6.1.0", - "@types/react-router-dom": "^5.1.7", - "typescript": "^4.2.4" + "@docusaurus/eslint-plugin": "^3.0.0", + "@docusaurus/module-type-aliases": "^3.0.0", + "@docusaurus/tsconfig": "^3.0.0", + "@flashbots/mev-share-client": "^0.7.10", + "@tsconfig/docusaurus": "^2.0.2", + "@types/react": "^18.2.23", + "@types/react-helmet": "^6.1.2", + "@types/react-router-dom": "^5.1.8", + "@typescript-eslint/eslint-plugin": "^6.7.3", + "@typescript-eslint/parser": "^6.7.3", + "cspell": "^6.31.2", + "debug": "^4.3.4", + "eslint": "^8.48.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-prettier": "^9.0.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-header": "^3.1.1", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-jest": "^27.4.2", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-mdx": "^2.2.0", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-regexp": "^1.15.0", + "lint-staged": "^13.2.3", + "markdownlint-cli2": "^0.9.2", + "mocha": "^10.2.0", + "prettier": "^3.0.2", + "prettier-plugin-organize-imports": "^3.2.3", + "prettier-plugin-tailwindcss": "^0.5.6", + "stylelint": "^14.16.1", + "stylelint-config-prettier": "^9.0.5", + "stylelint-config-standard": "^29.0.0", + "typescript": "^5.2.2" + }, + "engines": { + "node": ">=18.0" } } diff --git a/project-words.txt b/project-words.txt new file mode 100644 index 00000000..f58ef539 --- /dev/null +++ b/project-words.txt @@ -0,0 +1,13 @@ +camelcase +dogfood +flashbot +flashbots +Flashbots +hideable +Inpage +katex +MMSDK +rehype +SEPOLIA +stylelint +tailwindcss diff --git a/scripts/setup-cname.js b/scripts/setup-cname.js deleted file mode 100644 index df271fa5..00000000 --- a/scripts/setup-cname.js +++ /dev/null @@ -1,8 +0,0 @@ -require('dotenv').config() - -var fs = require('fs'); - -fs.writeFile('./static/CNAME', process.env.TARGET_URL, function (err) { - if (err) throw err; - console.log('CNAME created '); -}); diff --git a/src/components/Banner/Banner.custom.module.scss b/src/components/Banner/Banner.custom.module.scss new file mode 100644 index 00000000..712a63ac --- /dev/null +++ b/src/components/Banner/Banner.custom.module.scss @@ -0,0 +1,21 @@ +@use '_base'; + +/* +Add custom CSS styling for your banner here + +You can add any classes you'd like based on the markup for your banner +The .banner class is already provided and apply to the parent element of +the banner. + +The '@extend %banner-structure' defines the structural properties for the +banner and should not be removed. +*/ + +.banner { + @extend %banner-structure; // Do not remove +} + + +[data-theme=dark] .banner { + @extend %banner-structure; // Do not remove +} diff --git a/src/components/Banner/Banner.module.scss b/src/components/Banner/Banner.module.scss new file mode 100644 index 00000000..fb95fa28 --- /dev/null +++ b/src/components/Banner/Banner.module.scss @@ -0,0 +1,12 @@ +@use 'base'; + +.banner { + @extend %banner-structure; + + background-color: var(--banner-background-color, var(--ifm-navbar-background-color)); + color: var(--banner-text-color, var(--ifm-font-color-base)); + + a { + color: var(--banner-text-color , var(--ifm-font-color-base)); + } +} diff --git a/src/components/Banner/Banner.tsx b/src/components/Banner/Banner.tsx new file mode 100644 index 00000000..ae51c7f1 --- /dev/null +++ b/src/components/Banner/Banner.tsx @@ -0,0 +1,82 @@ +/* Custom Banner Module +Use it to quickly deploy a simple banner to the Flashbots homepage + +To add a new banner all you need to do is edit the ./banner.config.tsx +file and set the applicable properties. No other work is necessary. + +You'll find more in-depth documentation there. +*/ + +import React from 'react' +import clsx from 'clsx' +import bannerConfig from './banner.config' +import customStyles from './Banner.custom.module.scss' +import bannerStyles from './Banner.module.scss' + +export interface BannerOptions { + bannerContent?: JSX.Element | string | null + backgroundColor: string + textColor: string + startDate: string | null + endDate: string | null + customBannerCSS: boolean +} + +class BannerConfigs { + options: BannerOptions + + constructor(options: BannerOptions) { + this.options = options + } + + // Sets the appropriate CSS rules for the element + // based on the `customCSS` option + getBannerStyle(): React.CSSProperties | null { + return !this.options.customBannerCSS + ? { + "--banner-text-color": this.options.textColor, + "--banner-background-color": this.options.backgroundColor + } + : null + } + + // Sets the appropriate class name for the element + // based on the `customCSS` option + getBannerClass(): string { + const styles = this.options.customBannerCSS ? customStyles : bannerStyles + + return clsx(styles.banner) + } + + // Determines whether the banner should appear based on: + // 1. Whether there is content to be shown + // 2. The start and end dates exist and are valid + shouldShowBanner(): boolean { + if (!this.options.bannerContent) { + return false + } + + const parsedStart = Date.parse(this.options.startDate) + const parsedEnd = Date.parse(this.options.endDate) + const currentDate = Date.now() + + return ( + (isNaN(parsedStart) || parsedStart <= currentDate) && + (isNaN(parsedEnd) || parsedEnd >= currentDate) + ) + } +} + +export default function Banner(): JSX.Element { + const configs = new BannerConfigs(bannerConfig) + + if (!configs.shouldShowBanner()) { + return null + } + + return ( +
+ {configs.options.bannerContent} +
+ ) +} diff --git a/src/components/Banner/_base.scss b/src/components/Banner/_base.scss new file mode 100644 index 00000000..615f14e8 --- /dev/null +++ b/src/components/Banner/_base.scss @@ -0,0 +1,19 @@ +%banner-structure { + height: fit-content; + padding: 0.5rem 2rem; + text-align: center; + line-height: 1.25; + + a{ + cursor: pointer; + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + + @media (max-width: 720px){ + padding: 0.5rem 2rem; + } +} diff --git a/src/components/Banner/banner.config.tsx b/src/components/Banner/banner.config.tsx new file mode 100644 index 00000000..7ace62ee --- /dev/null +++ b/src/components/Banner/banner.config.tsx @@ -0,0 +1,93 @@ +/* Custom Banner Module +Use it to quickly deploy a simple banner to the Flashbots homepage + +To add a new banner all you need to do is edit the properties below and set them +to your desired values. + +For simple banners with just a couple of colors - for copy and background - you +can use the properties here. But if the banner requires more sophisticated styling +you can override the color options by setting `customCSS: true` and adding your CSS +rules to ./Banner.custom.module.scss. + +There are detailed explanations for each property below, but here's a quick guide: + - bannerContent: What should appear inside the banner + - backgroundColor: Solid, single color for the banner + - textColor: Solid, single color for all the copy inside the banner + - startDate: When should the banner start appearing on the site + - endDate: When should the banner stop appearing on the site + - customCSS: Whether the banner should make use of custom CSS rules loaded from ./Banner.custom.module.scss +*/ + +import React from 'react' +import BannerOptions from './Banner' + +export const bannerConfig: BannerOptions = { + /* + bannerContent: The pure text or HTML markup to appear in the banner + - Banner won't appear when set to null + + Examples: + - bannerContent: null + - bannerContent: "Banner content!" + - bannerContent: (Banner content! Link) + */ + bannerContent: null, + + /* + backgroundColor: Single, solid background color for the banner + - Will default to the site's background when set to null + - Has no effect if customCSS is true + + Examples: + - backgroundColor: null + - backgroundColor: "#023047" + */ + backgroundColor: null, + + /* + textColor: Single, solid text color for the banner + - Will default to the site's text color when set to null + - Has no effect if customCSS is true + + Examples: + - textColor: null + - textColor: "#ffb703" + */ + textColor: null, + + /* + startDate: Date and time (UTC) when the banner should start appearing on the website + - When set to null a banner will always appear, provided there is content to be shown + and the endDate, if there is one, hasn't been reached + Format: "YYYY-MM-DD HH:mmZ" + + Examples: + - startDate: null + - startDate: "2001-09-14 16:00Z" + */ + startDate: null, + + /* + endDate: Date and time (UTC) when the banner should stop appearing on the website + - When set to null a banner will always appear, provided there is content to be shown + and the startDate, if there is one, has been reached + Format: "YYYY-MM-DD HH:mmZ" + + Examples: + - endDate: null + - endDate: "2007-02-01 00:00Z" + */ + endDate: null, + + /* + customCSS: Determines whether to use a custom CSS instead instead of the color options + - Custom CSS must be set in ./Banner.custom.module.scss + - Will completely bypass backgroundColor and textColor if set to true + + Examples: + - customCSS: true + */ + customBannerCSS: false +} + +export default bannerConfig diff --git a/src/components/BrandAssets/AssetCard.tsx b/src/components/BrandAssets/AssetCard.tsx new file mode 100644 index 00000000..a9857b81 --- /dev/null +++ b/src/components/BrandAssets/AssetCard.tsx @@ -0,0 +1,31 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import React, { ReactNode } from "react" +import styles from './styles.module.css'; +import Download from "./Download"; + +interface IAssetCard { + title?: string + cover?: string + svg?: string + png?: string +} + +function AssetCard({ title, cover, svg, png }: IAssetCard) { + return ( +
+ +
+

{ title }

+ + +
+
+ ) +} + +export default AssetCard diff --git a/src/components/BrandAssets/Download.tsx b/src/components/BrandAssets/Download.tsx new file mode 100644 index 00000000..4d1ad66c --- /dev/null +++ b/src/components/BrandAssets/Download.tsx @@ -0,0 +1,25 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import React, { ReactNode } from "react" + +interface IDownload { + file?: string +} + +function Download({ file, type }: IDownload) { + return ( + + + + + + { type } + + ) +} + +export default Download diff --git a/src/components/BrandAssets/index.tsx b/src/components/BrandAssets/index.tsx new file mode 100644 index 00000000..7dd9b3e2 --- /dev/null +++ b/src/components/BrandAssets/index.tsx @@ -0,0 +1,41 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import {useState} from 'react'; +import AssetCard from './AssetCard'; + +export default function BrandAssets() { + + return ( +
+
+ + +
+ +
+ +
+
+ +
+ ); +} diff --git a/src/components/BrandAssets/styles.module.css b/src/components/BrandAssets/styles.module.css new file mode 100644 index 00000000..d0f35e41 --- /dev/null +++ b/src/components/BrandAssets/styles.module.css @@ -0,0 +1,6 @@ +.root { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(clamp(100px,(1024px - 100vw) *1000, 100%), 1fr)); + gap: 1rem; + margin-bottom: 2rem; +} diff --git a/src/components/Checkbox/index.tsx b/src/components/Checkbox/index.tsx new file mode 100644 index 00000000..6255cf49 --- /dev/null +++ b/src/components/Checkbox/index.tsx @@ -0,0 +1,44 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +function Checkbox({ + label, + checked, + onChange, + disabled = false, +}: { + label: string; + checked: boolean; + onChange: (val: boolean) => void; + disabled: boolean; +}) { + const elements = [ + { + onChange(e.target.checked); + }} + />, + , + ]; + return ( +
+ {elements} +
+ ); +} + +export default Checkbox; diff --git a/src/components/Grid/Grid.tsx b/src/components/Grid/Grid.tsx new file mode 100644 index 00000000..c43a6ee5 --- /dev/null +++ b/src/components/Grid/Grid.tsx @@ -0,0 +1,21 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import { ReactNode } from "react" +import styles from './styles.module.css'; + +interface IGrid { + children: ReactNode | ReactNode[] +} + +function Grid({ children }: IGrid) { + + return (
+ { children } +
) +} + +export default Grid diff --git a/src/components/Grid/styles.module.css b/src/components/Grid/styles.module.css new file mode 100644 index 00000000..d0f35e41 --- /dev/null +++ b/src/components/Grid/styles.module.css @@ -0,0 +1,6 @@ +.root { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(clamp(100px,(1024px - 100vw) *1000, 100%), 1fr)); + gap: 1rem; + margin-bottom: 2rem; +} diff --git a/src/components/GridBlock/GridBlock.tsx b/src/components/GridBlock/GridBlock.tsx new file mode 100644 index 00000000..2f705fb1 --- /dev/null +++ b/src/components/GridBlock/GridBlock.tsx @@ -0,0 +1,45 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import { ReactNode } from "react" +import styles from './styles.module.css'; + +interface IGridBlock { + children: ReactNode | ReactNode[] + symbol: string + title: string +} + +function GridBlock({ children, symbol, title }: IGridBlock) { + return (
+
+
+
+ + + + +
+ { + title && ( +
+ { + symbol &&

{ symbol }

+ } + + { title } + +
+
+ ) + } +
+ {children} +
+
) +} + +export default GridBlock diff --git a/src/components/GridBlock/styles.module.css b/src/components/GridBlock/styles.module.css new file mode 100644 index 00000000..d65c8db7 --- /dev/null +++ b/src/components/GridBlock/styles.module.css @@ -0,0 +1,85 @@ +.root { + position: relative; + padding: 2rem 1rem 1.5rem; +} + +.background { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + z-index: -1; +} + +.background > *:first-child { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: calc((100% - 25px) + 1px); + border-top: 1px solid var(--ifm-color-emphasis-200); + border-left: 1px solid var(--ifm-color-emphasis-200); + border-right: 1px solid var(--ifm-color-emphasis-200); +} + +.background > *:nth-child(2) { + position: absolute; + bottom: 0; + left: 0; + width: calc((100% - 25px) + 1px); + height: 25px; + border-bottom: 1px solid var(--ifm-color-emphasis-200); + border-left: 1px solid var(--ifm-color-emphasis-200); +} + +.background > *:last-child { + position: absolute; + bottom: 0; + right: 0; +} + +.title { + text-align: center; + height: 7rem; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.title p { + margin-bottom: 8px; + font-size: 11px; + font-weight: 700; +} + +.title span { + flex-grow: 2; + font-size: 1.2rem; + line-height: 1.25; + font-weight: 500; + font-family: CMU-Serif, 'Times New Roman', Garamond, Georgia, serif; +} + +.title hr { + width: 48px; + margin: 16px auto; +} + +.content { + font-size: .9em; + line-height: var(--ifm-line-height-base); +} + +.content ul, .content ol { + padding-left: 1ch; +} + +.content ul li { + padding-inline-start: 1ch; + list-style-type: '•'; +} + +.content ul li::marker { + color: var(--ifm-color-primary); +} diff --git a/src/components/ProtectButton/index.tsx b/src/components/ProtectButton/index.tsx new file mode 100644 index 00000000..70c7d2c5 --- /dev/null +++ b/src/components/ProtectButton/index.tsx @@ -0,0 +1,36 @@ +/** + * Copyright (c) Flashbots Ltd. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { useEffect, useState } from 'react'; + +export default function ProtectButton() { + + // listen for light/dark theme changes + const [theme, setTheme] = useState('light') + useEffect(() => { + const htmlElement = document.documentElement; + const handleThemeChange = () => { + const currentTheme = htmlElement.getAttribute('data-theme'); + setTheme(currentTheme || 'light'); + }; + handleThemeChange(); + const observer = new MutationObserver(handleThemeChange); + observer.observe(htmlElement, { attributes: true, attributeFilter: ['data-theme'] }); + }, []) + + return ( +
+