{"id":26153951,"url":"https://github.com/ChorusOne/solana-mev","last_synced_at":"2025-03-11T08:03:02.976Z","repository":{"id":103107617,"uuid":"593953101","full_name":"ChorusOne/solana-mev","owner":"ChorusOne","description":"Decentralized MEV extraction from inside the validator","archived":false,"fork":false,"pushed_at":"2024-01-23T01:20:37.000Z","size":281459,"stargazers_count":106,"open_issues_count":0,"forks_count":22,"subscribers_count":15,"default_branch":"mev-1.13","last_synced_at":"2025-03-04T06:41:29.404Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChorusOne.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-27T08:33:22.000Z","updated_at":"2025-02-22T07:35:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"a9523bfd-0fb9-4dfe-8b52-0d4f47c74b7c","html_url":"https://github.com/ChorusOne/solana-mev","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChorusOne%2Fsolana-mev","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChorusOne%2Fsolana-mev/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChorusOne%2Fsolana-mev/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChorusOne%2Fsolana-mev/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChorusOne","download_url":"https://codeload.github.com/ChorusOne/solana-mev/tar.gz/refs/heads/mev-1.13","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242995900,"owners_count":20218828,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-11T08:02:09.181Z","updated_at":"2025-03-11T08:03:02.944Z","avatar_url":"https://github.com/ChorusOne.png","language":"Rust","funding_links":[],"categories":["Solana Validator Implementations"],"sub_categories":["Validator Tools and Resources"],"readme":"# Solana-MEV\n\nSolana-MEV is a modification of the [upstream Solana validator][upstream] that\nhandles certain MEV opportunities right in the banking stage of the validator.\nRunning this validator instead of the upstream one can generate a small amount\nof additional income.\n\n**Warning:** This is a proof of concept. [Chorus One][c1] has used it in\nproduction for several months, but it is not at a level of polish where it is a\ndrop-in replacement for the upstream validator.\n\n[upstream]: https://github.com/solana-labs/solana\n[c1]:       https://chorus.one/\n\n## Further reading and other media\n\n * [Decentralizing MEV: An Alternative to Block-Building Marketplaces][talk],\n   a talk by Thalita Franklin at Breakpoint 2022.\n * [Breaking Bots: MEV on Solana and how to prevent frontrunning, spam attacks\n   and centralization][breaking-bots], whitepaper by Thalita Franklin, Enrique\n   Fynn, Umberto Natale, and Ruud van Asseldonk.\n * [Arbitrage as a Convex optimization problem][notion_page], a document by\n   Umberto Natale describing the mathematical framework used to detect if an\n   arbitrage exists.\n\n[talk]: https://www.youtube.com/watch?v=nTEnpuDHz3w\u0026t=6198s\n[notion_page]: https://www.notion.so/chorusone/Arbitrage-as-a-Convex-optimization-problem-f2490665033f41b6b6d41cfd5196acae\n[breaking-bots]: https://chorus.one/products/breaking-bots/\n\n## Status\n\nChorus One has developed this prototype as a proof of concept. Currently it is\nable to take arbitrage opportunities on Orca non-concentrated-liquidity pools.\nHowever, with the current trading volume on Solana, developing Solana-MEV is not\nsustaintable. Even if we were to cover the majority of Solana AMMs, as of\nDecember 2022, a validator with ~1% of leader slots would extract only a few\ndollars per day.\n\nAt this point, Chorus One does not plan to actively invest resources in\ndeveloping Solana-MEV further. We do hope that our prototype can serve as\nevidence that a centralized marketplace is not a technical prerequisite for MEV\nextraction, and we hope to get a discussion started around possible MEV\narchitectures on Solana to ensure that MEV benefits the entire community.\n\n## Details\n\nWe are interested making arbitrages on Automated Market Maker (AMM) pools. When\nwe are a validator during block production, we look at every transaction to see\nif the program id is one of the [configured](#configuration) known program ids.\nIf a transaction interacts with a known program id, we get all pools balances\nbefore and after the transaction executed and log this information. Futhermore,\nwe scan the pool for arbitrage opportunities only\n**after** the transaction is executed, in that way we forgo making sandwich\narbitrage transactions, i.e. acting in between the user's transactions.\n\nOur strategy for arbitraging is checking for every\n[configured](#configuration) path that start and finish at the same token if\nthere could be a transaction that generates profit.\n\n* We introduce a config file that statically configures all cycles to watch for\n   arbitrage opportunities. The config file is parsed and injected into the\n   banking stage when MEV is enabled.\n * In `BankingStage::process_and_record_transactions`, we introduce an\n   additional output: a single optional transaction, that should extract the MEV\n   created by the transaction batch.\n * At the call site, `BankingStage::process_transactions`, if an MEV transaction\n   was produced, we execute it.\n * `runtime/src/mev.rs` and `arbitrage.rs` contain methods that given a set of\n   AMM pools, compute optimal input amount that maximizes profit. When the\n   profit is smaller than the transaction fee, or even negative, we bail out.\n\nSolana transactions are organized in batches called **Entries** that can execute\nin parallel. Accounts in these entries can be referenced only once for\nwrite-access and multiple times for read-access. Due to this fact, when we\nencounter an arbitrage opportunity, we create a new Entry just for that\nopportunity, this Entry ought to be executed immediately after the transactions\nthat resulted in the arbitrage, but it might happen that the arbitrage\ntransactions are not executed atomically after we spotted the arbitrage, see\nmore details in the following [limitations](#limitations) section.\n\n## Limitations\n\nWe have some limitations when executing arbitrage transactions. The main one is\nthat we don't lock accounts in-between entries and it might happen that a worker\nthread executes other entries in-between the entry produced for arbitrage, this\ncan lead to an incorrect behavior of the program. This issue is remedied by\ndefining all *minimum_output* of the arbitrage instructions (except the first)\nas the input of the previous instruction. As an extra guarantee that the\ntransaction produces a profitable transaction, we check that the transaction is\nprofitable. Transactions that execute but fail are not included in the block.\nNote, it is possible to lift this limitation, but the changes with respect to\nthe upstream validator would become more invasive than our current patches.\n\nWe are limited to a maximum of three instructions per transaction, this is due\nto Solana's limitations on the transaction's length, one could extend an\narbitrage to spawn over multiple sequential transactions to circumvent the\nlimitation.\n\n## Comparison to alternatives\n\nCompared to [jito-solana][jito-solana], Solana-MEV differs in a few key aspects:\n\n * **No central server.** Solana-MEV does not introduce new connections to\n   third party servers, everything happens inside the validator.\n * **No mempool.** Solana-MEV does not buffer transactions. It inserts its own\n   transactions in between user transactions, but it does not change the way in\n   which user transactions are processed. This also means that Solana-MEV has\n   virtually zero latency impact compared to Jito, which introduces several\n   additional network hops in the transaction processing path.\n * **No transaction reordering.** Solana-MEV processes transactions in the same\n   order as upstream Solana. It does not buffer transactions, so it has no way\n   to reorder; it only inserts its own transactions in between user\n   transactions.\n * **Built-in searcher.** Solana-MEV does not rely on external searchers for\n   identifying MEV opportunities, it has a few basic strategies built-in. A\n   limitation of this is that the strategies are not as advanced as those of a\n   dedicated searcher, and Solana-MEV cannot respond as quickly to changes in\n   the ecosystem (e.g. the launch of a new AMM).\n\nDespite the differences, Solana-MEV and Jito are not incompatible, they are\ncomplementary. Jito’s patches stream groups of entries (parts of a block) to the\nvalidator, while Solana-MEV generates those internally based on the ones it saw\nbefore. There is no fundamental technical barrier to combining the two sources,\nhowever it is unclear what the marginal benefit is.\n\n[jito-solana]: https://github.com/jito-foundation/jito-solana\n\n## Reward distribution\n\nThe MEV module generates transactions that increase the balance of the SPL token\naccounts owned by the _MEV Authority_ (see also the configuration section\nbelow). Currently no mechanism is implemented to share those proceeds further.\nIn the case of a staking pool such as [Lido][lido], one simple way to share the\nrewards would be to transfer any excess balance to the pool’s reserve.\n\n[lido]: https://solana.lido.fi/\n\n## Configuration\n\nMEV extraction is enabled by providing the `--mev-config-path` command-line\noption to `solana-validator`. Without this option, the validator will run as\nusual. `--mev-config-path` should point to a TOML file with the following\nschema:\n\n```toml\n# File to log details about MEV opportunities and AMM pools to.\nlog_path = '/path/to/mev.log'\n\n# Programs to watch for interactions. After a user transaction interacts with\n# one of these programs, we check for MEV opportunities afterwards.\nwatched_programs = [\n  # Orca Swap v1\n  'DjVE6JNiYqPL2QXyCUUh8rNjHrbz9hXHNYt99MQ59qw1',\n  # Orca Swap v2\n  '9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP',\n]\n\n# Path to the keypair of the \"MEV Authority\". This address is the owner of all\n# SPL token accounts that are involved in MEV extraction, and it signs all\n# transactions generated by the MEV module. For example, if there exists a\n# triangular opportunity between the pools USDC/stSOL, stSOL/stETH, stETH/USDC,\n# then this address should have an associated token account for USDC, stSOL,\n# and stETH. This key is optional, if not provided, we only monitor for\n# opportunities but don't extract.\nuser_authority_path = '/path/to/keypair.json'\n\n[minimum_profit]\n# Per token mint address, the minimum profit before we generate a transaction.\n# This is to ensure that we don’t execute transactions whose profit is lower\n# than the cost of the transaction fees. Note that because we only execute\n# transactions when the validator itself is leading, we pay the fee to\n# ourselves. However, because half of the fee is burned, we still need a mimum\n# of half the transaction fee (5,000 lamports currently). The number is in the\n# smallest unit of the token (e.g. lamports for SOL, 1e-6 USDC for USDC).\n\"So11111111111111111111111111111111111111112\" = 2501  # 0.000_002_501 SOL\n\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" = 101  # 0.000_101 USDC\n\n# Next are the paths that we want to consider. A path is a sequence of Orca\n# pools that should form a cycle. Note, due to the transaction size limit on\n# Solana, it is generally not possible to use cycles of more than three hops,\n# because they would need to reference too many accounts.\n[[mev_path]]\nname = \"USDC-\u003ewstETH-\u003estSOL-\u003eUSDC\"\npath = [\n    { pool = \"v51xWrRwmFVH6EKe8eZTjgK5E4uC2tzY5sVt5cHbrkG\", direction = \"BtoA\" },\n    { pool = \"B32UuhPSp6srSBbRTh4qZNjkegsehY9qXTwQgnPWYMZy\", direction = \"BtoA\" },\n    { pool = \"EfK84vYEKT1PoTJr6fBVKFbyA7ZoftfPo2LQPAJG1exL\", direction = \"AtoB\" },\n]\n\n# For every Orca pool involved, we also need to specify its details.\n[[orca_account]]\n_id = \"stSOL/SOL\"\naddress = \"71zvJycCiY2JRRwKr27oiu48mFzrstCoP6riGEyCyEB2\"\npool_a_account = \"HQ2XUmQefvBdpN8nseBSWNP2D1crncodLL73AWnYBiSy\"\npool_b_account = \"8y8X4JuZn1MckRo5J6rirpr2Dxj1RKQshj7VzuX6dMUw\"\npool_mint = \"4jjQSgFx33DUb1a7pgPsi3FbtZXDQ94b6QywjNK3NtZw\"\npool_fee = \"7nxYhYUaD7og4rYce263CCPh9pPTnGixfBtQrXE7UUvZ\"\n\n# If we want to also extract MEV and not only monitor for opportunities, we also\n# need to provide the addresses of SPL associated token accounts, owned by the\n# MEV authority defined earlier, for token A and token B. These are called\n# \"source\" and \"destination\" respectively, though the roles can be reversed if\n# the pool is used with the BtoA swap direction.\nsource = \"...\"\ndestination = \"...\"\n```\n\n## Future work\n\n * For technical reasons, inserting the MEV-extracting `Entry` currently does\n   not happen atomically — it is not guaranteed that the entry lands directly\n   after the one that created the opportunity. Doing so is possible, but\n   requires more invasive changes to the codebase that would make the diff more\n   difficult to maintain. Solana-MEV _does_ ensure that it does not include\n   transactions that would make a loss, nor transactions that fail.\n * Currently Solana-MEV only observes Orca non-concentrated-liquidity pools,\n   a logical next step would be to watch concentrated liquidity pools as well.\n\n## License\n\nOur modifications are licensed under the Apache 2.0 license like the original\nSolana validator. As stated in the license, Chorus One is not liable for damages\nthat result from using this software.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChorusOne%2Fsolana-mev","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FChorusOne%2Fsolana-mev","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChorusOne%2Fsolana-mev/lists"}