mevbuild.com
Open in
urlscan Pro
45.141.59.160
Public Scan
Submitted URL: http://mevbuild.com/
Effective URL: https://mevbuild.com/
Submission: On February 19 via api from US — Scanned from DE
Effective URL: https://mevbuild.com/
Submission: On February 19 via api from US — Scanned from DE
Form analysis
1 forms found in the DOMPOST https://forms.hsforms.com/submissions/v3/public/submit/formsnext/multipart/5118396/222ecf08-c85d-411d-98cf-1a6927f7c917
<form id="hsForm_222ecf08-c85d-411d-98cf-1a6927f7c917_8624" method="POST" accept-charset="UTF-8" enctype="multipart/form-data" novalidate=""
action="https://forms.hsforms.com/submissions/v3/public/submit/formsnext/multipart/5118396/222ecf08-c85d-411d-98cf-1a6927f7c917"
class="hs-form-private hsForm_222ecf08-c85d-411d-98cf-1a6927f7c917 hs-form-222ecf08-c85d-411d-98cf-1a6927f7c917 hs-form-222ecf08-c85d-411d-98cf-1a6927f7c917_96a75ae0-0abe-4885-a522-1f6cf9f7db03 hs-form stacked hs-custom-form"
target="target_iframe_222ecf08-c85d-411d-98cf-1a6927f7c917_8624" data-instance-id="96a75ae0-0abe-4885-a522-1f6cf9f7db03" data-form-id="222ecf08-c85d-411d-98cf-1a6927f7c917" data-portal-id="5118396"
data-test-id="hsForm_222ecf08-c85d-411d-98cf-1a6927f7c917_8624" data-hs-cf-bound="true">
<fieldset class="form-columns-2">
<div class="hs_firstname hs-firstname hs-fieldtype-text field hs-form-field"><label id="label-firstname-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class="" placeholder="Enter your First name"
for="firstname-222ecf08-c85d-411d-98cf-1a6927f7c917_8624"><span>First name</span><span class="hs-form-required">*</span></label>
<legend class="hs-field-desc" style="display: none;"></legend>
<div class="input"><input id="firstname-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" name="firstname" required="" placeholder="Smiles" type="text" class="hs-input" inputmode="text" autocomplete="given-name" value=""></div>
</div>
<div class="hs_lastname hs-lastname hs-fieldtype-text field hs-form-field"><label id="label-lastname-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class="" placeholder="Enter your Last name"
for="lastname-222ecf08-c85d-411d-98cf-1a6927f7c917_8624"><span>Last name</span><span class="hs-form-required">*</span></label>
<legend class="hs-field-desc" style="display: none;"></legend>
<div class="input"><input id="lastname-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" name="lastname" required="" placeholder="Davis" type="text" class="hs-input" inputmode="text" autocomplete="family-name" value=""></div>
</div>
</fieldset>
<fieldset class="form-columns-1">
<div class="hs_email hs-email hs-fieldtype-text field hs-form-field"><label id="label-email-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class="" placeholder="Enter your Email address"
for="email-222ecf08-c85d-411d-98cf-1a6927f7c917_8624"><span>Email address</span><span class="hs-form-required">*</span></label>
<legend class="hs-field-desc" style="display: none;"></legend>
<div class="input"><input id="email-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" name="email" required="" placeholder="hello@gmail.com" type="email" class="hs-input" inputmode="email" autocomplete="email" value=""></div>
</div>
</fieldset>
<fieldset class="form-columns-1">
<div class="hs-dependent-field">
<div class="hs_business_use hs-business_use hs-fieldtype-checkbox field hs-form-field"><label id="label-business_use-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class=""
placeholder="Enter your Are you interested in Blocknative for business or personal use?" for="business_use-222ecf08-c85d-411d-98cf-1a6927f7c917_8624"><span>Are you interested in Blocknative for business or personal use?</span><span
class="hs-form-required">*</span></label>
<legend class="hs-field-desc" style="display: none;"></legend>
<div class="input">
<ul required="" role="checkbox" class="inputs-list multi-container">
<li class="hs-form-checkbox" role="checkbox"><label for="business_use0-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class="hs-form-checkbox-display"><input id="business_use0-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class="hs-input"
type="checkbox" name="business_use" value="Business_Use"><span> Business</span></label></li>
<li class="hs-form-checkbox" role="checkbox"><label for="business_use1-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class="hs-form-checkbox-display"><input id="business_use1-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class="hs-input"
type="checkbox" name="business_use" value="Personal_Use"><span>Personal</span></label></li>
</ul>
</div>
</div>
</div>
</fieldset>
<fieldset class="form-columns-1">
<div class="hs_is_there_anything_else_we_should_know_ hs-is_there_anything_else_we_should_know_ hs-fieldtype-textarea field hs-form-field"><label id="label-is_there_anything_else_we_should_know_-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class=""
placeholder="Enter your Tell us more about what you're working on." for="is_there_anything_else_we_should_know_-222ecf08-c85d-411d-98cf-1a6927f7c917_8624"><span>Tell us more about what you're working on.</span><span
class="hs-form-required">*</span></label>
<legend class="hs-field-desc" style="display: none;"></legend>
<div class="input"><textarea id="is_there_anything_else_we_should_know_-222ecf08-c85d-411d-98cf-1a6927f7c917_8624" class="hs-input hs-fieldtype-textarea" name="is_there_anything_else_we_should_know_" required="" placeholder=""></textarea></div>
</div>
</fieldset>
<div class="hs_submit hs-submit">
<div class="hs-field-desc" style="display: none;"></div>
<div class="actions"><input type="submit" class="hs-button primary large" value="Submit"></div>
</div><input name="hs_context" type="hidden"
value="{"embedAtTimestamp":"1708370960009","formDefinitionUpdatedAt":"1692716973059","lang":"en","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.184 Safari/537.36","pageTitle":"MEV Bot Guide: Create an Ethereum Arbitrage Trading Bot","pageUrl":"https://mevbuild.com/","pageId":"67066554285","isHubSpotCmsGeneratedPage":true,"canonicalUrl":"https://www.blocknative.com/blog/mev-and-creating-a-basic-arbitrage-bot-on-ethereum-mainnet","contentType":"blog-post","hutk":"102a95c88c850d36e0d019a052cd9e2e","__hsfp":4158071004,"__hssc":"8382957.1.1708370960267","__hstc":"8382957.102a95c88c850d36e0d019a052cd9e2e.1708370960267.1708370960267.1708370960267.1","formTarget":"#hs_form_target_form_305674839","formInstanceId":"8624","rawInlineMessage":"<p>Thank you for your request! We will be in touch, but you can get started by:</p>\n<ul>\n<li><a href=\"https://docs.blocknative.com/\" target=\"_blank\" rel=\"noopener\">Reviewing our documentation</a></li>\n<li><a href=\"https://discord.com/invite/KZaBVME\" target=\"_blank\" rel=\"noopener\">Joining our Discord</a> for immediate support from one of us or the community</li>\n<li><a href=\"https://www.blocknative.com/blog\" target=\"_blank\" rel=\"noopener\">Visiting our blog</a> for some great quick starts for a variety of use cases</li>\n</ul>","hsFormKey":"41e7bd28d42530382c54be6ae7591837","pageName":"MEV Bot Guide: Create an Ethereum Arbitrage Trading Bot","rumScriptExecuteTime":1436.8999996185303,"rumTotalRequestTime":1864.6999998092651,"rumTotalRenderTime":1884,"rumServiceResponseTime":427.80000019073486,"rumFormRenderTime":19.300000190734863,"connectionType":"4g","firstContentfulPaint":0,"largestContentfulPaint":0,"locale":"en","timestamp":1708370960271,"originalEmbedContext":{"portalId":"5118396","formId":"222ecf08-c85d-411d-98cf-1a6927f7c917","region":"na1","target":"#hs_form_target_form_305674839","isBuilder":false,"isTestPage":false,"isPreview":false,"formInstanceId":"8624","formsBaseUrl":"/_hcms/forms","css":"","inlineMessage":"<p>Thank you for your request! We will be in touch, but you can get started by:</p>\n<ul>\n<li><a href=\"https://docs.blocknative.com/\" target=\"_blank\" rel=\"noopener\">Reviewing our documentation</a></li>\n<li><a href=\"https://discord.com/invite/KZaBVME\" target=\"_blank\" rel=\"noopener\">Joining our Discord</a> for immediate support from one of us or the community</li>\n<li><a href=\"https://www.blocknative.com/blog\" target=\"_blank\" rel=\"noopener\">Visiting our blog</a> for some great quick starts for a variety of use cases</li>\n</ul>","isMobileResponsive":true,"rawInlineMessage":"<p>Thank you for your request! We will be in touch, but you can get started by:</p>\n<ul>\n<li><a href=\"https://docs.blocknative.com/\" target=\"_blank\" rel=\"noopener\">Reviewing our documentation</a></li>\n<li><a href=\"https://discord.com/invite/KZaBVME\" target=\"_blank\" rel=\"noopener\">Joining our Discord</a> for immediate support from one of us or the community</li>\n<li><a href=\"https://www.blocknative.com/blog\" target=\"_blank\" rel=\"noopener\">Visiting our blog</a> for some great quick starts for a variety of use cases</li>\n</ul>","hsFormKey":"41e7bd28d42530382c54be6ae7591837","pageName":"MEV Bot Guide: Create an Ethereum Arbitrage Trading Bot","pageId":"67066554285","contentType":"blog-post","formData":{"cssClass":"hs-form stacked hs-custom-form"},"isCMSModuleEmbed":true},"correlationId":"96a75ae0-0abe-4885-a522-1f6cf9f7db03","renderedFieldsIds":["firstname","lastname","email","business_use","is_there_anything_else_we_should_know_"],"captchaStatus":"NOT_APPLICABLE","emailResubscribeStatus":"NOT_APPLICABLE","isInsideCrossOriginFrame":false,"source":"forms-embed-1.4708","sourceName":"forms-embed","sourceVersion":"1.4708","sourceVersionMajor":"1","sourceVersionMinor":"4708","allPageIds":{"embedContextPageId":"67066554285","analyticsPageId":"67066554285","contentPageId":67066554285,"contentAnalyticsPageId":"67066554285"},"_debug_embedLogLines":[{"clientTimestamp":1708370960096,"level":"INFO","message":"Retrieved customer callbacks used on embed context: [\"getExtraMetaDataBeforeSubmit\"]"},{"clientTimestamp":1708370960096,"level":"INFO","message":"Retrieved pageContext values which may be overriden by the embed context: {\"pageTitle\":\"MEV Bot Guide: Create an Ethereum Arbitrage Trading Bot\",\"pageUrl\":\"https://mevbuild.com/\",\"userAgent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.184 Safari/537.36\",\"pageId\":\"67066554285\",\"contentAnalyticsPageId\":\"67066554285\",\"contentPageId\":67066554285,\"isHubSpotCmsGeneratedPage\":true}"},{"clientTimestamp":1708370960097,"level":"INFO","message":"Retrieved countryCode property from normalized embed definition response: \"DE\""},{"clientTimestamp":1708370960269,"level":"INFO","message":"Retrieved analytics values from API response which may be overriden by the embed context: {\"hutk\":\"102a95c88c850d36e0d019a052cd9e2e\",\"canonicalUrl\":\"https://www.blocknative.com/blog/mev-and-creating-a-basic-arbitrage-bot-on-ethereum-mainnet\",\"contentType\":\"blog-post\",\"pageId\":\"67066554285\"}"}]}"><iframe
name="target_iframe_222ecf08-c85d-411d-98cf-1a6927f7c917_8624" style="display: none;"></iframe>
</form>
Text Content
By clicking “Accept Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and provide you with a better browsing experience. More info ** If you decline, your information won’t be tracked when you visit this website. A single cookie will be used in your browser to remember your preference not to be tracked. Accept Cookies Decline Cookies * Solutions SOLUTIONS FOR WALLETS Make it easy for hundreds of Web3 applications to integrate your wallet. FOR TRADERS Power your trading strategies with real-time mempool data — gain an edge. FOR DAPPS Unrivaled transaction transparency with Blocknative's proven mempool platform. FOR RESEARCHERS Access the most comprehensive historical dataset of Ethereum mempool transaction events. * Products PRODUCTS ETHERNOW Go hands-on with real-time mempool data. Watch transactions complete their journey to finalization. MEMPOOL EXPLORER Monitor real-time transaction event streams with Mempool Explorer. MEMPOOL DATA ARCHIVE Access the most comprehensive historical dataset of Ethereum mempool transaction events. ETHEREUM GAS ESTIMATOR Get accurate gas estimations on Ethereum with full EIP-1559 support. POLYGON GAS ESTIMATOR Industry-leading Polygon (MATIC) gas estimates with full EIP-1559 support. TRANSACTION BOOST Protect users from frontrunning and sandwiching attacks without sacrificing visibility. * Dev Tools DEV TOOLS WEB3 ONBOARD Quick and easy way to add multi-chain and multi-wallet support to your Web3 project. MEMPOOL API & SDK Our API and SDK makes mempool data easy to build with and integrate. ETH & MATIC GAS API Harnesses real-time global mempool data infrastructure for accurate gas estimates. * Learn LEARN DOCS Start building today with comprehensive product and API documentation. RESOURCES In-depth resources for web3 searchers, validators, devs, and wallets. SOFTWARE AND SDKS Explore our Github repo and get started building. RESEARCH Open research and discourse from the Blocknative team. WEB3 WALLET REGISTRY View supported wallets and networks in Onboard. GLOSSARY Learn the ins and outs of blockchain technology. * Company COMPANY ABOUT Learn more about how we are shaping the future of DeFi, NFTs, and more. PRESS ROOM Articles, Podcasts, Interviews, Videos, and Announcements THE BLOCKNATIVE ADVANTAGE The Blocknative Advantage: Build Better, Trade Smarter, Win More CAREERS Join us and help shape the future of crypto, DeFi, and NFTs. CONTACT US Get in touch with Blocknative. EVENTS Browse upcoming and past events, talks, and workshops. * Blog BLOG View all INTRODUCING ETHERNOW: REAL-TIME OBSERVABILITY FOR ETHEREUM MEMPOOL ARCHIVE QUICKSTART: HOW TO USE BLOCKNATIVE'S HISTORICAL ETHEREUM MEMPOOL DATA TO ANALYZE PRIVATE TRANSACTIONS, MEV, AND OFAS THE FALSE NARRATIVE OF MEV PROTECTION: HOW PRIVATE TRANSACTIONS CAN RESULT IN A POORER SETTLEMENT THAN SENDING PUBLICLY BLOCKNATIVE ANNOUNCES TRANSACTION BOOST: A TOOL FOR MEV PROTECTION WHILE PRESERVING TRANSACTION OBSERVABILITY Pricing Observe Ethereum Pricing Observe Ethereum Ethereum MEV BEGINNER’S GUIDE TO AN MEV BOT: CREATING AN ARBITRAGE BOT ON ETHEREUM MAINNET Blocknative Ethereum Web3 Blair Marshall January 17, 2023 12 minute read Share Copied! January 2023 Update: If you are an MEV searcher, Blocknative now offers an MEV bundle RPC endpoint. Searchers can interact with the RPC endpoint at https://api.blocknative.com/v1/auction. The API provides JSON-RPC methods for interfacing with Blocknative builders, which are documented via our bundle docs. At Blocknative we are often asked about getting started in the world of MEV. In this blog, I will go over the creation of a very basic arbitrage script that highlights some key ideas in the world of MEV bots. MEV, or Maximal Extractable Value, is essentially the maximum value that can be extracted from a block. While this had traditionally been an opportunity that only miners could participate in—which is why it was sometimes called Miner Extractable Value—the democratization of the mempool has allowed more opportunities for traders to extract value by influencing what goes into a block. MEV Searchers can easily affect which transactions are included and excluded, or even change the order of transactions in a block, by seeing what’s already in the mempool and then timing and pricing their transactions accordingly. These Searchers will typically run algorithms to detect profitable MEV opportunities and have bots automatically submit any profitable transactions to the network. This blog details my attempt at creating one of these bots, and the lessons I learned along the way. You can treat this as a beginner’s guide to help you get your creative juices flowing and start thinking about other strategies unique to you. Please note the script and smart contract in this blog are for educational purposes only. You will not make any money using this code, so please do your own research before deploying any of your own money into any opportunity. Ethereum mainnet is extremely competitive, and this idea is quite common among the elite bots in the ecosystem. WHAT IS AN ARBITRAGE STRATEGY IN THE WORLD OF MEV? Arbitrage is an MEV strategy that allows traders to profit from price differences between the same asset in different markets. In the traditional financial world, this creates an opportunity to make two trades to get the two exchanges into equilibrium—and make a little profit for doing so. You would start with asset A and sell it for asset B on the exchange where asset B is cheaper. Then, you would take asset B and sell it for asset A on the other exchange, receiving more of asset A in return than when you started. This basic example is extremely competitive in traditional finance and many High Frequency Traders compete against each other to be the first ones to complete the arbitrage opportunity. In the MEV world, things are a little bit more complicated. In crypto, transactions are submitted to the mempool—which, for the most part, is public— for inclusion into the next block. This means traders can see pending transactions in the mempool and know what the effects will be once they are finalized on-chain. This added visibility results in MEV arbitrage working slightly differently than traditional arbitrage because traders don’t need to wait until transactions are on-chain to find an opportunity. As a result, MEV searchers need a real-time data feed of the mempool to analyze each transaction as it comes in. Once you detect a transaction that might cause an arbitrage opportunity when it lands on-chain, you can send your two transactions that will complete the arbitrage opportunity directly into the mempool or to the flashbots private relay as a bundle. If done correctly, this means the mempool transaction that creates the opportunity + your two transactions will all be mined in the same block. As a result, the moment that arbitrage opportunity is created it is also completed by the next two transactions—your two transactions. Let’s break this down with a completely unrealistic, but hopefully illuminating example. Suppose you are monitoring the mempool and you detect a transaction that will impact the liquidity pool on Uniswap V2 for token A and token B. Since you know that liquidity pools are governed by the equation x * y = k (I am ignoring fees in this example), then you know when you see somebody submit a swap for 2 of token A for as much of token B as possible, you can calculate (based on the reserves of those tokens in the liquidity pool, which, in this case, are 10 and 10) that they will receive 1.7 of token B in return. The key insight is that you know this transaction will impact the price between token A and token B on Uniswap V2, but not on another DEX like Sushiswap… at least not until somebody takes advantage of the arbitrage opportunity. The moment this transaction is mined, token A will be cheaper on Uniswap than Sushiswap, so whoever can sell token A on Sushiswap for token B and then sell those token Bs on Uniswap for token A should end up with more token A than they started. And that is exactly what this example illustrates. There is some specific math that you can do to calculate the optimal amount to trade back and forth, but is beyond the scope of this post. SEARCHING FOR ARBITRAGE OPPORTUNITIES While doing some research on the various opportunities in MEV, I stumbled upon a pre-built smart contract in this awesome github repo, which walks you through how to optimally calculate the correct amount needed to arbitrage between two Uniswap V2 DEXs—for example Uniswap V2 and Sushiswap. Since this project wasn’t really about taking a deep dive in solidity, this repo was perfect to get a proof of concept. The key insight with this smart contract is that you can supply it two pools—one Uniswap pool and one Sushiswap pool— and return whether there is any profit arbitraging the two pools. However, the calculation is being done by looking at the reserves of those two pools as they currently stand (ie. the latest block state). But what if you knew how those pools were going to change prior to the next block? Then you would know about arbitrage opportunities before they happen on-chain and you could submit your arbitrage transaction in the correct position to take advantage of these opportunities. My goal in this project was now to write a basic script that modifies this smart contract to successfully detect arbitrage opportunities using the Blocknative Simulation Platform’s net balance change calculation. WRITING A BASIC ARBITRAGE SCRIPT This post is not a post to learn about solidity. There are plenty of great posts and tutorials out there, but in order to truly compete for MEV opportunities (at least in the EVM world), you need to know some solidity. That said, I used my limited knowledge of solidity to update the smart contract to fit my needs. In order to calculate the real-time profit of an arbitrage opportunity, I would need to have some way of supplying my getProfit function with an adjustment on a liquidity pool. This adjustment is when I see a swap transaction in the mempool that will impact the Uniswap or Sushiswap liquidity pool. I incorporate the impact of the mempool transaction when I calculate the profit potential for the arbitrage opportunity. To incorporate this adjustment, I created a new struct called ‘Adjustments’ that would host the pool that needed to be adjusted, the direction it needed to be adjusted and the amount of adjustments to each token in the token pair. Then you will notice that getProfit relies on getOrderedReserves to calculate the reserves of each pool and the correct direction of the trades. Therefore, I added some logic to getOrderedReserves that would take in the mempool data of a token swap on Uniswap or Sushiswap and then adjust the token reserves of that pair so when getProfit was called it would incorporate the mempool data instead of just the latest chain state. function getOrderedReserves( address pool0, address pool1, Adjustments memory adjustment, bool baseTokenSmaller ) internal view returns ( address lowerPool, address higherPool, OrderedReserves memory orderedReserves ) { (uint256 pool0Reserve0, uint256 pool0Reserve1, ) = IUniswapV2Pair(pool0).getReserves(); (uint256 pool1Reserve0, uint256 pool1Reserve1, ) = IUniswapV2Pair(pool1).getReserves(); if (pool0 == adjustment.adjustmentPool) { if (adjustment.adjustmentToken0 == IUniswapV2Pair(pool0).token0()) { pool0Reserve0 -= adjustment.adjustment0; pool0Reserve1 += adjustment.adjustment1; } else { pool0Reserve1 -= adjustment.adjustment0; pool0Reserve0 += adjustment.adjustment1; } } else { if (adjustment.adjustmentToken0 == IUniswapV2Pair(pool1).token0()) { pool1Reserve0 -= adjustment.adjustment0; pool1Reserve1 += adjustment.adjustment1; } else { pool1Reserve1 -= adjustment.adjustment0; pool1Reserve0 += adjustment.adjustment1; } } Now that I have adjusted the smart contract to be able to incorporate the real-time mempool data, I can complete my script using Blocknative’s mempool API and flashbots private relay. Using Simulation Platform, each simulation is done in isolation against the current block state, meaning there is some degree of probability involved in the ‘pending-simulation’ payloads. However, if the transaction is at the top of the block, then that effectively means it is happening against the current block state, since there won’t be any transactions between the current block state and this one. The best way to ensure it gets to the top of the block (or at least close to it) is to use flashbots private relay. For this project, I looked at pending simulation events on the Uniswap V2 and Sushiswap routers using Blocknative’s Javascript SDK. The pending simulation payloads include net balance changes on all the addresses involved (like the liquidity pool), allowing me to do two things: 1. Check to see if that pair exists on the other exchange 2. Use the balance changes as inputs as the ‘adjustments’ in my getProfit function in my smart contract As I receive these events I loop through the netBalanceChange list in our Simulation Platform payload and I skip when the address is equal to the actual router itself (because I am only looking for liquidity pool addresses) or if the netBalanceChange[index].address doesn’t have 2 elements (if it only has 1 element, then it can’t be a pool, because a pool would have 2 or more token reserves with net balance changes). If one of the addresses in the netBalanceChange field is not one of the router addresses and has 2 different token addresses that have net balance changes, then it must be a pool address. I now have the pool address, the token addresses involved, and the net balance changes of each token. I can now check to see what the other DEX’s liquidity pool address is so that I can supply it to my smart contract. If the other DEX does not have a liquidity pool with the same token pair, then I can’t arbitrage between the two, so I move on. try { for (entry in transaction.netBalanceChanges) { if (transaction.netBalanceChanges[entry].balanceChanges.length !== 2 || blacklist.indexOf(transaction.netBalanceChanges[entry].address) !== -1 ) { continue } pairAddress = transaction.netBalanceChanges[entry].address; tokenAddress1 = transaction.netBalanceChanges[entry].balanceChanges[0].asset.contractAddress; tokenAddress0 = transaction.netBalanceChanges[entry].balanceChanges[1].asset.contractAddress; adjustment1 = transaction.netBalanceChanges[entry].balanceChanges[0].delta; adjustment0 = transaction.netBalanceChanges[entry].balanceChanges[1].delta.substring(1,); adjustment0 = ethers.utils.parseEther(ethers.utils.formatEther(adjustment0))._hex adjustment1 = ethers.utils.parseEther(ethers.utils.formatEther(adjustment1))._hex otherPairAddress = await getSushiPair(tokenAddress0, tokenAddress1) if (otherPairAddress === undefined) { otherPairAddress = await getUniPair(tokenAddress0, tokenAddress1) if (otherPairAddress === undefined) { continue } } Likewise, if the other DEX does have a liquidity pool with the same token pair, then I can arbitrage between the two. Using my script, this means I will have detected a pending swap on either Uniswap or Sushiswap in the mempool and I have located the same liquidity pool on the other DEX. Now I have all the information I need to supply my smart contract to see if there is a profit opportunity. The result I get from my smart contract doesn’t include gas, so I do a naive calculation to see what the all in gas cost would be (including my extra tip to the miners on the flashbots relay). I knew my two transactions would cost about 240K gas, so I hardcoded that in for my net-profit calculation. For my gas price, I assumed I would need to give up 95% of my gross profit to compete in the private relay. The 95% was hardcoded and arbitrary (room for improvement!). If the net calculation is greater than 0, I have successfully found an arbitrage opportunity where I will net 5% and give the miner 95%! profitHex = await arbContract.getProfit(pairAddress, otherPairAddress, pairAddress, tokenAddress0, adjustment0, adjustment1) const gross = ethers.utils.formatEther(profitHex.toString(10).split(',')[0]) const gasLimit = 240000 const gasFee = Math.floor(ethers.utils.parseEther(gross)*.95/gasLimit) const gasCost = gasLimit*gasFee const net = ethers.utils.parseEther(gross) - gasCost CONSTRUCTING A FLASHBOTS BUNDLE FOR ARBITRAGE Next, I needed to construct my flashbots bundle to send to the relay. Since the detected mempool transaction could be a type 0 or type 2 transaction, I must have scenarios for both. For more on using mempool transactions in your bundles, you can refer to our prior post on using Blocknative with Flashbots. if (transaction.type == 2) { params = [ '0x01', transaction.nonce === 0 ? '0x' : ethers.utils.hexlify(transaction.nonce), ethers.utils.parseEther(ethers.utils.formatEther(transaction.maxPriorityFeePerGas))._hex, ethers.utils.parseEther(ethers.utils.formatEther(transaction.maxFeePerGas))._hex, ethers.utils.hexlify(transaction.gas), transaction.to, transaction.value === '0' ? '0x' : ethers.utils.hexlify(transaction.value), transaction.input, [], transaction.v === '0x0' ? '0x' : transaction.v, transaction.r, transaction.s ] s1 = '0x02'+encode(params).toString('hex'); } else { params = [ transaction.nonce === 0 ? '0x' : ethers.utils.hexlify(transaction.nonce), ethers.utils.parseEther(ethers.utils.formatEther(transaction.gasPrice))._hex, ethers.utils.hexlify(transaction.gas), transaction.to, transaction.value === '0' ? '0x' : ethers.utils.hexlify(transaction.value), transaction.input, transaction.v, transaction.r, transaction.s ]; s1 = '0x'+encode(params).toString('hex'); } I used my modified smart contract to construct my transaction, which would include either two internal transactions or two swaps between the two DEXs. const s2 = await arbContract.populateTransaction.flashArbitrage( pairAddress, otherPairAddress, pairAddress, tokenAddress0, ethers.utils.parseEther('0')._hex, ethers.utils.parseEther('0')._hex ) s2.gasPrice = ethers.utils.hexlify(gasFee) s2.gasLimit = ethers.utils.hexlify(500000) s2.nonce = await wallet.getTransactionCount(); With the transaction constructed, I then created the flashbots bundle and simulated it to ensure the transaction wouldn’t fail for any reason. I also created a final net-profit calculation to ensure I was still actualizing a profit. If my transaction passed the simulation, and I was still making a profit, then I submitted it to the flashbots relay for inclusion. const signedTransactions = await flashbotsProvider.signBundle([ { signedTransaction: s1 }, { signer: wallet, transaction: s2 } ]) const blockNumber = transaction.pendingBlockNumber+1; const simulation = await flashbotsProvider.simulate(signedTransactions, blockNumber); if ('error' in simulation) { console.log(`Simulation Error: ${simulation.error.message}`) } else { if (simulation.firstRevert!==undefined) { console.log(simulation.firstRevert.revert) } else { const net2 = ethers.utils.parseEther(gross) - simulation.results[1].gasUsed*gasFee console.log(`Net: ${ethers.utils.formatEther(net2)} | Pair address: ${pairAddress} | TxHash: ${transaction.hash}`) console.log(simulation) if (net2>0) { console.log(`Coinbase diff: ${simulation.coinbaseDiff}`) const submittedBundle = await flashbotsProvider.sendRawBundle(signedTransactions, blockNumber); const bundleResponse = await submittedBundle.wait(); console.log(bundleResponse) } } } LESSONS LEARNED FROM CREATING A BASIC ARBITRAGE BOT I ran my script for several days and it worked exactly as intended—it detected profitable opportunities using Blocknative’s mempool API and submitted them to flashbots to compete for inclusion by a miner. However, the opportunities this script competed for were VERY competitive and I wasn’t able to outcompete the other bots. The biggest reason for this was that most of the other bot’s smart contracts were far more gas efficient than mine, allowing them to pay more to the miner to get included. Additionally, using flashswaps is pretty inefficient compared to just doing the swaps with tokens you already own. There are a whole host of other gas optimizations out there, but that is a very competitive, tough game to play against people far better at solidity (and Yul!) than I am. Other areas that I didn’t optimize include: 1. Choosing the correct tip to send to the miner. 2. Only looking at two DEXs. 3. Only looking at arbitrage between two tokens. A path-finding algorithm across many pairs could result in better profit potential. 4. Trying this out on other EVM compatible chains like Polygon. 5. Cross-chain MEV. TRADE WITH AN EDGE USING BLOCKNATIVE’S SIMULATION PLATFORM Finding the best arbitrage opportunities is impossible without the best mempool data feeds. Blocknative’s Simulation Platform leverages our Global Mempool Data Platform to provide probabilistic outcomes of every public pending Ethereum transaction, including detailed traces of each smart contract function call and net balance changes. MEV searchers can go hands-on today and monitor simulated transactions directly on Mempool Explorer. Our powerful UI enables users to filter on everything in the payload to ensure you get a fine-tuned view of the mempool that fits your exact needs. These saved configurations can easily be integrated into any project using websockets or webhooks. OBSERVE ETHEREUM Blocknative's proven & powerful enterprise-grade infrastructure makes it easy for builders and traders to work with mempool data. Visit ethernow.xyz TABLE OF CONTENTS * What is an arbitrage strategy in the world of MEV? * Searching for arbitrage opportunities * Writing a basic arbitrage script * Constructing a flashbots bundle for arbitrage * Lessons learned from creating a basic arbitrage bot * Trade with an edge using Blocknative’s Simulation Platform Share Copied! WANT TO KEEP READING? Good choice! We have more articles. Ethereum EIP-4844, Blobs, and Blob Gas: What you need to know With the upcoming Dencun upgrade, Ethereum will adopt EIP-4844, commonly called proto-danksharding... Bert Kellerman Ethereum Introducing Ethernow: Real-Time Observability for Ethereum On-chain data tells you what has happened. Pre-chain data tells you why it is happening. For anyone.. Blocknative Blog Nav Post Mempool Archive Quickstart: How to use Blocknative's historical Ethereum mempool data to analyze private transactions, MEV, and OFAs Blocknative offers the most exhaustive historical archive of Ethereum's mempool transaction events,.. Victoria Tran Connect with us. Build with us. We love to connect with teams who are building with Blocknative. Tell us about your team and what you would like to learn. "After first building our own infrastructure, we appreciate that mempool management is a difficult, expensive problem to solve at scale. That's why we partner with Blocknative to power the transaction notifications in our next-generation wallet." SCHEDULE A DEMO First name* Last name* Email address* Are you interested in Blocknative for business or personal use?* * Business * Personal Tell us more about what you're working on.* CONTACT US: Hello@blocknative.com Connect on Discord * Solutions * L2 Decoding * For Ethereum * For Wallets * For Dapps * For Traders * Products * Ethernow * Transaction Simulation * Mempool Explorer * ETH Gas Estimator * Polygon Gas Estimator * Gas Fee Extension * For Developers * Dencun Countdown * Transaction Boost * Docs * Web3 Dev Tools * Mempool API & SDK * ETH & MATIC Gas API * Web3 Onboard * Web3 Wallet Registry * Blocknative ® * Blog * About * Research * FAQs * Careers * Pricing * Brand * Connect With Us: © 2024 Blocknative. All Rights Reserved Privacy Policy Terms of Service