跳转到主要内容

架构概览

Geode 是一个单一智能合约(GeodeHook.sol,约 1,190 行),实现了 Uniswap v4 IHooks 接口。它通过 beforeSwap 回调拦截池活动,并通过单独的入口点提供批量结算。 Hook 标志BEFORE_SWAP | BEFORE_SWAP_RETURNS_DELTA Hook 在部署时设置四个不可变量:
不可变量用途
poolManagerUniswap v4 PoolManager——核心交换和流动性引擎
permit2规范的 Permit2 合约——处理无 Gas 代币提取
protocolTreasury接收约 1/3 的直接交换费用
factoryGeodeFactory 地址——被授权注册发行池

两条交换路径

每个在 Geode 配置池上的交换采取两条路径之一:

路径 1:直接交换

通过 Hook 的 beforeSwap 回调的交换。行为取决于池类型: 曲线池(已发行代币):Hook 计算联合曲线输出,并通过 BEFORE_SWAP_RETURNS_DELTA 返回完整的 delta。v4 池没有流动性——Hook 就是做市商。0.3% 的费用三方分配:
  • 约 1/3 → 曲线 ETH 储备(永久提高地板价)
  • 约 1/3 → 协议金库
  • 约 1/3 → 每池盈余(资助结算者 Gas 报销)
标准池(现有 AMM 流动性):Hook 对交换的未指定(输出)侧收取费用:
  • 约 1/3 → 协议金库(通过 poolManager.take()
  • 约 2/3 → 每池盈余(由 Hook 作为 ERC20 余额持有)
当 Hook 路由剩余流量通过 AMM 进行批量结算时(sender == address(this)),不收取直接交换费用。只有外部交换者付费。

路径 2:意图批量结算

核心机制。无许可的结算者使用签名的买入和卖出意图数组调用 geodeSettleBatch()

结算流程

从入口到最终代币分配的完整调用流程:
geodeSettleBatch(key, buys[], sells[], buySigs[], sellSigs[])

  ├─ 验证批次间隔(自上次结算以来 ≥ 1 个区块)
  ├─ 验证意图绑定(poolId、截止时间)
  ├─ 计算出清价格 + 成交
  │   ├─ 曲线模式 → ConstantProductCurveLib.computeLaunchSettlement()
  │   └─ 标准模式 → ClearingPriceLib.computeClearingPrice()

  ├─ 更新批次状态,发出 GeodeIntentFilled 事件

  └─ poolManager.unlock(callbackData)
      └─ unlockCallback()
          └─ _settlementUnlockCallback()

              ├─ 通过 Permit2 从每个用户提取代币
              │   └─ permitWitnessTransferFrom(owner → poolManager)

              ├─ 路由和分配
              │   ├─ 标准:AMM 交换剩余
              │   ├─ 曲线:通过联合曲线分发/吸收
              │   ├─ 将 currency1 分配给买家(按 amountIn 比例)
              │   └─ 将 currency0 分配给卖家(按 amountIn 比例)

              └─ 支付结算者
                  ├─ 结算费用(来自未路由的输入存款)
                  └─ Gas 报销(来自盈余,有上限)

分步详解

1

批次验证

结算者提交买入意图、卖出意图及其 Permit2 签名的数组。Hook 检查:
  • 池已配置(poolInitialized[poolId]
  • 自上次结算以来已经过足够的区块(batchInterval
  • 所有意图针对正确的池(poolId 绑定)
  • 所有截止时间在未来
2

出清价格计算

出清价格等于 AMM 现货价格(v1 简化)。对于每个意图:
  • 买入意图成交条件:其隐含限价 ≥ 出清价格
    • 限价 = amountIn × Q128 / minAmountOut
  • 卖出意图成交条件:其隐含限价 ≤ 出清价格
    • 限价 = minAmountOut × Q128 / amountIn
不满足出清价格的意图被跳过——它们保留自己的代币。
3

费用扣除

结算费用从每个已成交意图的输入中扣除,任何路由之前:
grossInput = intent.amountIn
fee = grossInput × settlementFeeBps / 10,000
netInput = grossInput - fee
费用金额作为未路由余额保留在 PoolManager 中,供结算者领取。
4

内部撮合

算法确定买卖流量中有多少可以在内部交叉:
sellVolumeInQuote = netSellInput × clearingPrice / Q128

if netBuyInput ≥ sellVolumeInQuote:
    internalMatch = sellVolumeInQuote(所有卖家已匹配)
    residual = netBuyInput - sellVolumeInQuote(多余买入 → AMM/曲线)
else:
    internalMatch = netBuyInput(所有买家已匹配)
    residual = netSellInput - matchedSells(多余卖出 → AMM/曲线)
内部匹配的流量以出清价格执行,零 AMM 价差。
5

剩余路由

未匹配的流量通过相应的场所路由:
  • 标准池:通过 poolManager.swap() 对 AMM 执行
  • 曲线池:通过联合曲线分发/吸收(代币从/到 Hook 储备)
6

代币分配

输出代币根据每个意图的 amountIn 按比例分配给已成交的意图:
  • 买家收到 currency1(来自内部匹配 + 剩余输出)
  • 卖家收到 currency0(来自内部匹配 + 剩余输出)
分配使用余数归最后的方式处理尾数取整。
7

结算者支付

结算者收到:
  1. 结算费用——两种货币(来自未路由的输入存款)
  2. Gas 报销——从盈余中提取(上限为 maxGasReimbursement,默认 0.01 ETH)
SettlerPaid 事件发出每种货币的确切明细,用于链上审计。

闪电记账

结算发生在 Uniswap v4 的 unlock() 回调内——“闪电记账”上下文。在此窗口期间:
  • PoolManager 跟踪每种货币的贷方和借方
  • 代币提取(通过 Permit2)创建正 delta
  • 代币分配(通过 take())创建负 delta
  • AMM 交换创建配对 delta
  • unlock() 返回时所有 delta 必须归零
如果不归零,整个交易回滚。这是 Uniswap v4 的核心安全保障——什么都不能被创造或销毁,只能被移动。

直接曲线交换机制

对于曲线池,beforeSwap 通过联合曲线处理整个交换:
  1. Hook 使用 ConstantProductCurveLib.tokensForEth()(买入)或 ethReturnOnSell()(卖出)计算曲线输出
  2. 从输入中扣除 0.3% 的费用,三方分配(储备、金库、盈余)
  3. 买入时:ETH 进入 launchEthReserve,代币从 launchTokenReserve 分发
  4. 卖出时:代币被吸收回去,ETH 从储备返回
  5. Hook 通过 BeforeSwapDelta 返回完整 delta,因此 AMM 不处理任何内容
储备费用部分永久提高曲线的地板价——每次直接交换都会使最低价值向上攀升。

直接交换费用捕获(标准池)

当非意图用户通过标准 Geode 配置的池进行交换时,Hook 使用配对 delta 记账收取费用:
  1. poolManager.take(unspecified, hook, feeAmount) — 创建负 Hook delta
  2. BeforeSwapDelta(0, +feeAmount) — 创建正 Hook delta,向交换者收费
两者对 Hook 来说净值为零。交换者以减少的输出支付费用。约 1/3 进入协议金库;约 2/3 作为盈余累积,用于结算者 Gas 报销。
继续阅读意图了解签名和 Permit2 集成,或经济学了解完整的费用模型。