费用

库中提供了与费用相关的基本钩子,允许以灵活的方式调整或覆盖不同操作的费用,例如交换和流动性修改。

动态

BaseDynamicFee 允许动态设置和应用 LP (Liquidity Provider) 费用。实现者必须重写 _getFee 函数,以基于他们选择的逻辑返回以百分之一 Bip 表示的费用值。该费用在初始化后自动应用,并且可以通过调用无需许可的 poke 函数随时刷新。这允许基于外部数据或条件动态更新费用。但是,由于 poke 可以被任何人调用,因此实现者必须仔细考虑他们的_getFee 实现是否依赖于可能被攻击者操纵的外部状态。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {BaseDynamicFee, IPoolManager, PoolKey} from "src/fee/BaseDynamicFee.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @dev 一个允许所有者动态更新 LP 费用的钩子。
 */
contract DynamicLPFeeHook is BaseDynamicFee, Ownable {
    uint24 public fee;

    constructor(IPoolManager _poolManager) BaseDynamicFee(_poolManager) Ownable(msg.sender) {}

    /**
     * @inheritdoc BaseDynamicFee
     */
    function _getFee(PoolKey calldata) internal view override returns (uint24) {
        return fee;
    }

    /**
     * @notice 设置 LP 费用,以百分之一 Bip 为单位。
     */
    function setFee(uint24 _fee) external onlyOwner {
        fee = _fee;
    }
}

构造函数检查池是否配置了动态费用标志,如果没有,则恢复。

覆盖

BaseOverrideFee 允许动态设置和应用交换费用。与 BaseDynamicFee 类似,实现者必须重写 _getFee 函数以返回费用值,该费用值使用覆盖费用标志进行掩码,并在交换之前传递给 PoolManager

对于基于时间、基于交易量或基于波动性的费用,这种方法可能很有用,因为这些费用可能频繁波动。由于钩子在执行交换之前运行,因此实现者可以检查当前上下文(如流动性水平或外部价格预言机)以确定每笔交易的适当费用。它也不需要拨动(poke)钩子来刷新费用,因为费用是在每次交换之前动态获取的。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {BaseOverrideFee, IPoolManager, PoolKey} from "src/fee/BaseOverrideFee.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @dev 一个允许所有者动态更新交换费用的钩子。
 */
contract DynamicSwapFeeHook is BaseOverrideFee, Ownable {
    uint24 public fee;

    constructor(IPoolManager _poolManager) BaseOverrideFee(_poolManager) Ownable(msg.sender) {}

    /**
     * @inheritdoc BaseOverrideFee
     */
    function _getFee(address, PoolKey calldata, IPoolManager.SwapParams calldata, bytes calldata)
        internal
        view
        override
        returns (uint24)
    {
        return fee;
    }

    /**
     * @notice 设置交换费用,以百分之一 Bip 为单位。
     */
    function setFee(uint24 _fee) external onlyOwner {
        fee = _fee;
    }
}

交换后

BaseDynamicAfterFee 将调整应用于用户因精确输入交换而将收到的 token。此策略依赖于首先在 _beforeSwap 阶段捕获交换上下文并存储目标增量。一旦 PoolManager 处理了交换,钩子的 _afterSwap 方法会检查精确输入交换,并将实际用户输出与存储的目标增量进行比较。任何正差额都将成为对池的费用捐赠,从而有效地实现了一种动态费用,该费用仅在完成所有交换的内部计算后才最终确定。

实施者应仔细考虑如何缓解攻击者利用“即时”流动性增加来获得这些费用的超额份额的风险。正如合约所指出的那样,目标增量在每次交换后都会被清除,因此建议每次都在 _beforeSwap 中定义或重置它们,以确保一致性。