# BSC meme 三明治机器人代码学习

By [NealZhu](https://paragraph.com/@nealzhu) · 2024-09-04

---

写在前面: 本文是 [https://github.com/fuzzland/fourmeme-god.git](https://github.com/fuzzland/fourmeme-god.git) 的学习笔记

三明治机器人原理

1.  有人使用较大的滑点进行交易, 称此交易为 victim tx ，后面简称为 vtx
    
2.  滑点代表的是对价格上升的容忍程度，较大的滑点导致在 vtx 买入代币，并且在 vtx 之后卖出代币的模式变得有利可图
    
3.  三明治机器人构造 buy tx 和 sell tx（可能还有额外的 approve tx，以保证卖出交易的成功），并且将这些交易与原始的 vtx 按照如下顺序排列：\[buy tx, vtx, approve tx(optional), sell tx\]
    
4.  找一个类似 flashbots 的交易捆绑服务商，将上面的交易 bundle(即上述的 tx 数组) 提交
    

构造一个三明治机器人的主要难点：

1.  检测到有利可图的交易、协议
    
2.  在合理的时间范围内构造出利润最大化的 bundle
    

个人感觉第 1 点，尤其对于短暂出现的 alpha 机会, 才是真正的难点。比如本例中的 meme 协议，合并并未开源，如何从一份未开源合约中提取到完成套利机器人的相关信息，是很复杂的.如何完成这一点在本文中不再展开，我们只需要知道 meme 协议是一个常量乘积 AMM 算法：即

> x \* y = k 并且会收取一定的交易手续费（体现在后续代码中的 fee\_rate 和 min\_fee）

下面主要讲套利交易构造部分: fourmeme-god 是基于 [burberry](https://github.com/tonyke-bot/burberry.git) (一个模块化的 mev 开发框架) 开发的。burberry 中, 一个 mev 项目被模块化的分解为:

*   collector(s), 负责搜集数据。支持多方数据源，异构数据源等
    
*   strategy, 负责解析搜集的数据,并且根据套利算法进行套利交易的构造
    
*   executor, 负责执行套利交易的最终执行
    

在本项目中, collectors 采用了两个 burberry 内置的数据采集类，主要负责采集最新的区块信息和 mempool pending tx 信息.两个数据源的主要作用分别为:

*   block 信息用于探测其他机器人竞争者，并且在后续的三明治套利中避免处理这些机器人地址的相关交易
    
*   pending tx 信息用于识别潜在的 victim tx.
    

在 strategy 中整体流程如下:

1.  检查交易是不是一个 meme::Buy tx （通过解析 tx.data）
    
2.  对于 buy 交易，根据 meme 当前池子信息和这个 buy tx 信息，计算最优的三明治交易组合(即计算提前买入多少)
    
3.  计算一下加上 gas 消耗以后是否还有利可图(gas 根据链上交易设定固定值进行估算)
    
4.  构造 bundle 提交到区块链上完成交易(未实现，可以自己选择 bundle 服务提供商)
    

这里重点讲一下 `search::go` 的逻辑。在不考虑任何数学和代码之前，很容易得到一个感性的结论:

*   在一个临界点之前, 三明治机器人的利润肯定是随着买入 mev 机器人提前买入的代币数量的增加而增加。
    
*   这个临界点存在的原因是买入太多会导致滑点太大，进而让 victim tx 失败 那如何找到这个临界点呢? 这里简单使用了一个类似二分搜索法的搜索: 将输入区间标记为 4 个点
    

    起点----起点+m(A)----起点+2m(B)----终点
    

我们只需要反复比较买入量为 A 和 B 时候，机器人的利润，然后再进行区间的收缩即可。即如果 Porfit(B) < Profit(A) ，则代表 B 已经超过了上面提到的临界点，最优解必然在起点到 B 之间的一个点, 我们重新对这部分输入进行等分搜索。通过反复迭代，我们可以找到最优解。(你可以问问 ai 看看有什么更好的寻求解的办法)需要指出的是，因为 mev 本质上还是需要和时间赛跑，而且最优解也没有那么重要，所以迭代次数被设置为 100，这个数据可以根据你的 CPU 性能进行调优（比如机器差，就改小点，机器好就调大一点）.

至于如何计算利润也比较简单，流程也是比较明朗的，给定你希望买入的 eth 数量(也就是 amount\_in):

1.  先计算可以 buy tx 的 amount\_out(买入的代币数量)
    
2.  模拟更新池子信息(内存中的数据)
    
3.  按照 victim tx 进行计算, 得到 victim tx 真正可以得到的代币
    
4.  模拟更新池子信息
    
5.  构造卖出交易(卖出数量为 1 中的 amount\_out), 得到卖出获取的 eth 数量
    
6.  计算 mev 机器人的整体收益，即最终卖出 ETH 的数量减去 amount\_in + fee
    

至此主要的逻辑我已经梳理完成,不过在读代码的过程中，我也遇到一些不理解的地方:

1.  在搜索最优解的时候，`trial_ultimate(&mut context, lower_bound + m)` 函数调用使用的相同的 context 引用，这会持续修改 context(也就是内存中虚拟池子的信息),但是这个修改其实是不应该发生的，也就是计算不同点的利润的时候，输入都应该是相同的 context. 不确定是代码确实有问题还是我的理解有误. 后面希望可以和作者请教讨论

---

*Originally published on [NealZhu](https://paragraph.com/@nealzhu/bsc-meme)*
