Swap操作

关于DAI/USDT的单交换

image.png

逻辑:

  1. Router02.sol
  • SwapexactTokensForTokens( )
  • SwapTokensForexactTokens( )
  1. 资金转换 transferFrom( ) [ pair DAI/USDT]

  2. Swap

  3. transfer(币转给用户)


多Tokens之间的交换

此时path参数

1
path = [DAI, WBTC, USDC];

流程图:

image.png

逻辑:

  1. 用户调用 Router02 的 swapExactTokensForTokens,传入 path = [DAI, WBTC, USDC]

  2. Router02 先把用户的 DAI 转入 DAI-WBTC Pair。

  3. DAI-WBTC Pair 执行 swap,把 WBTC 发给下一个 Pair(由 Router02 转发)。

  4. Router02 把 WBTC 继续送入 WBTC-USDC Pair。

  5. WBTC-USDC Pair 执行 swap,把 USDC 最终发给用户。

  6. 用户完成从 DAI → WBTC → USDC 的兑换。


多跳交换 = 一次函数调用 + 多个 Pair 的 swap() 串联


源代码部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}

getAmountsOut( )&getAmountsIn( )

ba166abfd595c589a17f9f67c19f153b.jpg

什么时候收取手续费

每次 swap 都会收取一次手续费(每笔交易执行时收取,且直接从交易金额中扣除)

  • 所以用户会找短的 swap 路径
  • 但有时套利机器人会选择更长的路径(终可获得 Z 数量最多)

🔹 为什么套利机器人会选择更长路径?

  1. 追求更高利润
    • 直接 A → Z 交易可能滑点大,兑换率不高
    • 经过中间代币 B、C,可能找到更优的汇率
    • 机器人计算路径收益:选择 最终可获得 Z 数量最多的路径
  2. 捕捉跨池套利机会
    • A → B → C → D → Z 可能涉及不同交易对
    • 某些小池子价格偏离较大,通过多跳可以 利用价格差套利
  3. 减少滑点(Slippage)
    • 大额交易直接 A → Z 会导致池子价格大幅变化
    • 分多跳交易,每一跳量小,减少对单个池子的冲击
    • 最终拿到更多目标代币
  4. 结合多个 DEX
    • 虽然 V2 Router 只在单链 Uniswap V2,但套利机器人会模拟多跳路径,包括跨 DEX(SushiSwap、Curve)
    • 长路径可以把不同池子的价格差整合起来,提高 MEV 或套利收益
  5. Gas 成本 vs 收益平衡
    • 多跳增加交易复杂度和 Gas,但如果利润足够大,机器人仍然选择长路径

🔹 总结

  • 短路径:直接交易,Gas 低,但可能兑换率不佳
  • 长路径:多跳交易,可以:
    • 获得更优汇率
    • 捕捉多个池子间的套利机会
    • 减少单池滑点,提高最终收益

✅ 一句话概括:
套利机器人选择更长的 swap 路径,是为了最大化最终收益,同时降低滑点和利用跨池套利机会。


手续费机制

手续费分配

  • 手续费直接加入 流动性池(Pool)
  • LP(流动性提供者)按份额共享手续费收益
  • Protocol fee

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
address _feeTo = IUniswapV2Factory(factory).feeTo();
feeOn = _feeTo != address(0);
uint _kLast = kLast; // 上一次存储的储备乘积
if (feeOn) {
if (_kLast != 0) {
uint rootK = Math.sqrt(uint(_reserve0) * _reserve1);
uint rootKLast = Math.sqrt(_kLast);
if (rootK > rootKLast) {
uint numerator = totalSupply * (rootK - rootKLast);
uint denominator = rootK * 5 + rootKLast;
uint liquidity = numerator / denominator;
if (liquidity > 0) _mint(_feeTo, liquidity);
}
}
}
kLast = uint(_reserve0) * _reserve1; // 更新 kLast
}

0405b6f2c5e0c2a30f8ae87b83d212a1.jpg

最后蓝字部分解释:

Protocol Fee(协议费) 并不是默认开启的,而是通过 UniswapV2FactoryUniswapV2Pair 的一些变量和函数控制的。

1
2
address public feeTo;       // 协议费用接收地址
address public feeToSetter; // 谁可以设置 feeTo

补充:

MEV

🔹 什么是 MEV?

MEV (Maximum Extractable Value)
= 最大可提取价值

它指的是:

区块链中的 区块生产者(矿工/验证者/排序者),通过对 区块中交易的排序、插入、删除 等操作,可以获得的额外收益。


🔹 为什么会有 MEV?

因为区块链交易执行顺序不是完全固定的:

  • 当你提交一笔交易到 mempool(交易池)时,矿工/验证者有权决定 哪些交易打包、以什么顺序执行
  • 在 DeFi 场景下,交易顺序影响结果(尤其是 AMM 交易价格)。

于是,矿工/验证者(或者 MEV Bot)就能利用这个“排序权”来获利。


🔹 MEV 常见类型

  1. 套利(Arbitrage)
    • 当不同 DEX(Uniswap、SushiSwap、Curve)间存在价格差时,MEV bot 会抢先打包套利交易。
  2. 三明治攻击(Sandwich Attack)
    • 用户要在 Uniswap 买入某代币,MEV bot 看到这笔交易:
      • 先抢先买入(推高价格)。
      • 等用户交易执行(在高价买)。
      • 再立即卖出获利。
    • 用户因此付出了更高的滑点。
  3. 清算(Liquidation)
    • 在借贷协议(Aave、Compound)中,当有人抵押物不足时,MEV bot 会抢先清算,赚取清算奖励。
  4. 时间套利 / 跨链套利
    • 抢先在跨链桥、预言机更新等场景中获取收益。

🔹 MEV 与 Uniswap 的关系

  • Uniswap V2/V3 里,交易价格由 恒定乘积公式 x*y=k 决定。
  • 任何大额交易都会影响价格(滑点)。
  • MEV bot 会监听 mempool,发现大额交易时,利用 三明治攻击 来赚取差价。

🔹 MEV 的利与弊

    • 保持市场价格一致(套利让不同市场趋于平衡)。
    • 提供流动性效率。
    • 用户体验差(被三明治攻击,付出更高费用)。
    • Gas 费大战(多个 bot 竞争插队,推高网络拥堵)。
    • 中心化风险(MEV 收益过于集中在少数矿工/验证者)。

🔹 如何缓解 MEV?

  • Flashbots / MEV-Boost
    • 提供一个“公平竞拍”的系统,让 MEV 更透明。
  • 私有交易池(如 Eden Network):
    • 用户把交易发到私有通道,避免被三明治攻击。
  • 协议级防护
    • 一些 DEX(如 CowSwap)尝试使用批量拍卖机制,减少 MEV 攻击面。

✅ 一句话总结:
MEV = 区块链世界里的“隐藏税”,是由区块生产者/排序者通过操纵交易顺序所获取的额外收益,在 Uniswap 等 DeFi 协议里尤其常见。

三明治攻击

🔹 什么是三明治攻击?

三明治攻击是一种 针对去中心化交易所(DEX)的前后夹击攻击,常发生在 Uniswap V2/V3 这样的 AMM 上。

简单来说:

攻击者在用户交易前买入代币,然后在用户交易后卖出代币,从中赚取差价。


🔹 例子理解

假设用户想用 ETH 换 DAI

  1. 用户提交交易:买 1000 DAI。
  2. MEV bot 前置交易:抢先买入 DAI → 导致 DAI 价格上涨。
  3. 用户交易执行:因为价格被抬高,用户买入 DAI 的成本更高。
  4. MEV bot 后置交易:卖出之前买入的 DAI → 获利。

所以整个过程就像“三明治”:

  • MEV bot 买 → 用户交易 → MEV bot 卖
  • 用户被夹在中间 → 支付了更高价格

🔹 特点

  • 利用 交易顺序权(矿工或验证者可以决定区块交易顺序)。
  • 攻击者无需抵押,只需抢先提交交易即可获利。
  • 用户承受额外滑点和手续费。

MEV 三明治攻击流程图

image.png

  • _mintFee 会在 每次 swap、mint 或 burn 时调用
  • 核心逻辑:
    1. 通过 feeTo 判断是否开启协议费
    2. 计算额外 LP token 数量
    3. mint 给 feeTo 地址