值得信赖的区块链资讯!
剖析DeFi交易产品之UniswapV3:工厂合约
文章内容:
UniswapV3Factory 合约主要用来创建不同代币对的流动性池子合约,其代码实现并不复杂,以下就是代码实现:
contract UniswapV3Factory is IUniswapV3Factory, UniswapV3PoolDeployer, NoDelegateCall {
address public override owner;
mapping(uint24 => int24) public override feeAmountTickSpacing;
mapping(address => mapping(address => mapping(uint24 => address))) public override getPool;
constructor() {
owner = msg.sender;
emit OwnerChanged(address(0), msg.sender);
// 初始化支持的费率以及对应的tickSpacing
feeAmountTickSpacing[500] = 10;
emit FeeAmountEnabled(500, 10);
feeAmountTickSpacing[3000] = 60;
emit FeeAmountEnabled(3000, 60);
feeAmountTickSpacing[10000] = 200;
emit FeeAmountEnabled(10000, 200);
}
function createPool(
address tokenA,
address tokenB,
uint24 fee
) external override noDelegateCall returns (address pool) {
require(tokenA != tokenB);
// 对两个token进行排序,小的排前面
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0));
int24 tickSpacing = feeAmountTickSpacing[fee];
require(tickSpacing != 0); //为0则说明该费率并不支持
require(getPool[token0][token1][fee] == address(0));
// 实际的部署新池子函数
pool = deploy(address(this), token0, token1, fee, tickSpacing);
// 两个方向的token都存储,方便查询
getPool[token0][token1][fee] = pool;
getPool[token1][token0][fee] = pool;
emit PoolCreated(token0, token1, fee, tickSpacing, pool);
}
function setOwner(address _owner) external override {
require(msg.sender == owner);
emit OwnerChanged(owner, _owner);
owner = _owner;
}
function enableFeeAmount(uint24 fee, int24 tickSpacing) public override {
require(msg.sender == owner);
require(fee < 1000000);
// tick spacing is capped at 16384 to prevent the situation where tickSpacing is so large that
// TickBitmap#nextInitializedTickWithinOneWord overflows int24 container from a valid tick
// 16384 ticks represents a >5x price change with ticks of 1 bips
require(tickSpacing > 0 && tickSpacing < 16384);
require(feeAmountTickSpacing[fee] == 0);
feeAmountTickSpacing[fee] = tickSpacing;
emit FeeAmountEnabled(fee, tickSpacing);
}
}
UniswapV3Factory 除了继承其 interface IUniswapV3Factory 之外,还继承了另外两个合约 UniswapV3PoolDeployer 和 NoDelegateCall。这两个合约后面再讲,先来看看构造函数。构造函数除了初始化 owner 之外,最主要就是初始化 feeAmountTickSpacing 状态变量。这个变量是用来存储支持的交易手续费率的配置的,key 代表费率,value 代表 tickSpacing。初始的费率值分别设为了 500、3000、10000,分别代表了 0.05%、0.3%、1%。tickSpacing 的概念需要解释一下。
当添加流动性时,虽然 UI 交互上选择的是一个价格区间,但实际调用合约时,传入的参数其实是一个 tick 区间。而如果低价或/和高价的 tick 还没有被已存在的头寸用作边界点时,该 tick 将被初始化。tickSpacing 就是用来限制哪些 tick 可以被初始化的。只有那些序号能够被 tickSpacing 整除的 tick 才能被初始化。当 tickSpacing = 10 的时候,则只有可以被 10 整除的 tick (…, -30, -20, -10, 0, 10, 20, 30, …) 才可以被初始化;当 tickSpacing = 200 时,则只有可以被 200 整除的 tick (…, -600, -400, -200, 0, 200, 400, 600, …) 才可被初始化。tickSpacing 越小,则说明可设置的价格区间精度越高,但可能会使得每次交易时损耗的 gas 也越高,因为每次交易穿越一个初始化的 tick 时,都会给交易者带来 gas 消耗。
为了更直观地理解 tickSpacing,我再用更具体的示例进行说明。我们知道,在 UniswapV2 中,在智能合约层面,价格精度其实可以达到 18 位小数,交易精度是可以非常小的。但是,在中心化交易所,不同代币的价格精度则是不一样的,比如 BTC 和 ETH 的价格精度大多为两个小数,MEME 的精度为 6 位小数,SHIB 的精度则为 8 位小数,这个价格精度也就是价格的最小变动单位,BTC 和 ETH 的最小变动单位为 0.01,SHIB 的最小变动单位为 0.00000001。类似地,tickSpacing 可以理解为就是 tick 变动的最小单位。而我们知道,每一个 tick 其实也对应了每一个价格点,因此 tickSpacing 其实和中心化交易所的价格精度类似,是用于限制每个池子的最小价格变动范围的。也因此,当你在 Uniswap 官网上添加流动性时,当你输入的区间价格为整数时,比如 1700,最终会变成 1699.4004,就是因为 1699.4004 才是符合 tickSpacing 限制的有效价格点。
从构造函数中可看出,三个不同费率对应的 tickSpacing 分别为 10、60 和 200。费率越高,tickSpacing 越高,即是说,费率越高,价格变动的最小单位也越高。
在 2021 年 11 月通过 DAO 治理增加了另一个手续费率配置,费率为 0.01%,tickSpacing 为 1,是通过调用了 enableFeeAmount 函数添加的。该函数只有 owner 才有权限调用,而 owner 其实是个 Timelock 合约。
createPool 是最核心的创建新池子的函数,其三个入参就是组成一个池子唯一性的 tokenA、tokenB 和 fee。代码实现里,各种 require 的检验都非常好理解,而实际的创建池子逻辑其实封装在了 deploy 内部函数里,而这个函数是在 UniswapV3PoolDeployer 合约中实现的。deploy 函数返回 pool 后,会存储到 getPool 状态变量里。
下面,来看看 UniswapV3PoolDeployer 合约实现,其代码如下:
contract UniswapV3PoolDeployer is IUniswapV3PoolDeployer {
struct Parameters {
address factory;
address token0;
address token1;
uint24 fee;
int24 tickSpacing;
}
Parameters public override parameters;
function deploy(
address factory,
address token0,
address token1,
uint24 fee,
int24 tickSpacing
) internal returns (address pool) {
parameters = Parameters({factory: factory, token0: token0, token1: token1, fee: fee, tickSpacing: tickSpacing});
pool = address(new UniswapV3Pool{salt: keccak256(abi.encode(token0, token1, fee))}());
delete parameters;
}
}
这套代码还是比较有意思的。首先,其定义了结构体 Parameters 和该结构体类型的状态变量 parameters。然后,在 deploy 函数里,先对 parameters 进行赋值,接着通过 new UniswapV3Pool 部署了新池子合约,使用 token0、token1 和 fee 三个字段拼接的哈希值作为盐值。最后再将 parameters 删除。总共就三行代码。但其中有两个用法,是在以前的项目中还没出现过的。
第一,使用 new UniswapV3Pool 部署新合约时,还可以指定 salt。这其实也是 create2 的一种新写法,相比于 UniswapV2Factory 中使用内联汇编的方式,明显简化了很多。
第二,parameters 其实是传给 UniswapV3Pool 的参数,在 UniswapV3Pool 的构造函数里,是如下所示来接收这些参数的:
constructor() {
int24 _tickSpacing;
(factory, token0, token1, fee, _tickSpacing) = IUniswapV3PoolDeployer(msg.sender).parameters();
tickSpacing = _tickSpacing;
maxLiquidityPerTick = Tick.tickSpacingToMaxLiquidityPerTick(_tickSpacing);
}
可见,其实就是通过调用了 IUniswapV3PoolDeployer(msg.sender).parameters() 来获取到几个参数。其中,msg.sender 其实就是工厂合约。
看了这段代码才明白,原来合约间传递参数还可以这么用。
回到 UniswapV3Factory 合约的 createPool 函数,函数体里还有加了 noDelegateCall 的函数修饰器,这是在 NoDelegateCall 抽象合约中定义的。以下是 NoDelegateCall 的代码实现:
abstract contract NoDelegateCall {
/// @dev The original address of this contract
address private immutable original;
constructor() {
// Immutables are computed in the init code of the contract, and then inlined into the deployed bytecode.
// In other words, this variable won't change when it's checked at runtime.
original = address(this);
}
/// @dev Private method is used instead of inlining into modifier because modifiers are copied into each method,
/// and the use of immutable means the address bytes are copied in every place the modifier is used.
function checkNotDelegateCall() private view {
require(address(this) == original);
}
/// @notice Prevents delegatecall into the modified method
modifier noDelegateCall() {
checkNotDelegateCall();
_;
}
}
这其实就是为了阻止用 delegatecall 来调用所修饰的函数。当使用 delegatecall 调用 createPool 函数的时候,那 address(this) 将是发起 delegatecall 的地址,而不是当前的工厂合约地址。
至此,我们就讲解完了 UniswapV3 的工厂合约。
比推快讯
更多 >>- 坚定做多鲸鱼平仓 40 倍杠杆 1318 万美元 BTC 多单
- Solana 昨日现货 DEX 交易额达 41.3 亿美元,创过去 38 天内最高水平
- LIT 近 1 小时反弹 18%,Polymarket 上预测其首日市值超 30 亿美元概率升至 52%
- 美银 CEO:美联储不应占据公众太多注意力
- STS Digital:机构投资者正将比特币期权策略应用于山寨币市场
- RWA 固定收益市场 Haven 以 3000 万美元估值完成种子轮融资,Candaq 等参投
- 数据:过去 24 小时全网爆仓 2.29 亿美元,多单爆仓 1.69 亿美元,空单爆仓 6,047.63 万美元
- 灰度:2026 年加密市场聚焦美监管立法与量子计算威胁
- 谭咏麟之子谭晓风曾负责 NFT 游戏 CryptoKitties,现任 Web3 公司高级软件工程师
- 比特币短时回升至 8.8 万美元上方,以太坊回升至 3000 美元上方
- 灰度:价值储存需求和监管明确将推动加密牛市,比特币明年上半年或创新高
- 黄金剧烈波动下 Byreal 链上交易升温,Bybit Alpha Farm 收益率走高
- 100%胜率 1%回撤交易员年赚 5 倍本金,与Paul Wei同看 BTC 空单触发位 9.02 万处
- OKX 将转换 LIT/USDT 盘前合约为标准永续合约
- 分析:白银波动性超越比特币,比特币年末交易量萎缩
- 0x 开发的 Matcha Meta 新增 World Chain 的 CCTP 支持,可直接桥接 USDC
- 沉寂 1.6 年巨鲸增持 359 万美元 LIT 多单,目前浮亏超 126 万美元
- Gate 创始人 Dr. Han:专注吸引全球人才,打造连接完整数字经济生活的 Gate App
- Pacifica 已将 Extended 纳入资金费率比较,目前 LIT 费率在各平台中差值较大
- Matrixport:以太坊“三角形”形态逼迫近临界位置,2026 年或将迎来方向确认
- 数据:ETH 全网合约持仓量 24h 减少 6.5%
- “Lighter 具体空投日期”在 Polymarket 上产生争议裁决
- 数据:监测到 4,555.27 万 USDT 转入 Binance
- Metaplanet:Q4 增持 4279 枚比特币,均价 105,412 美元
- Lighter:空投已分发完毕,代币交易即将开放
- 观点:比特币长期持有者自 2025 年 7 月以来首次停止派发,或引发反弹行情
- 易理华对手盘割肉平仓价值 1.06 亿美元空单,亏损 47.9 万美元
- 亿万富豪 Grant Cardone 将于 2026 年推出全球最大上市房地产比特币公司
- Binance Alpha:OOOO 空投门槛 241 积分
- MMA 完成 300 万美元私募轮融资拟构建 Web3 平台,特朗普长子参投
- LIT 盘前合约短时跌超 20%
- 1011 比特币巨鲸向币安存入 112,894 枚 ETH,价值 3.318 亿美元
- 数据:共计 11.29 万枚 ETH 转入 Binance,价值约 33.19 亿美元
- Star 发布 2025 年终信:系统稳定、安全与透明是通向金融自由的基础
- 数据:黄立成已将其 ETH 多单加仓至 8700 枚,目前浮亏 25.46 万美元
- “1011 内幕巨鲸”代理人:资金开始流入加密市场,贵金属空头挤压结束
- 易理华评美联储注入天量流动性:美联储放水力度会逐步放大,后市一旦上涨必然逼空
- Lighter 半小时前再次转移约 2.5 亿枚 LIT,并已转入 Lighter 平台
- 币安杠杆将移除部分交易对公告
- Lighter 推出原生代币 LIT,25%代币将用于未来积分季活动
- 21Shares 将 8900 枚 AAVE 存入 Coinbase Prime
- 灰度:2025 年 Q4 最佳表现加密资产中隐私币占主导
- 美联储今晨注入 160 亿美元流动性,为新冠疫情以来第二大规模
- 某鲸鱼买入 108,501 枚 HYPE,均价 25.63 美元
- Bitwise CEO:伊朗货币崩盘引发抗议,凸显比特币作为价值保护工具的必要性
- Wintermute OTC 负责人:银行参与加密交易本质为经纪模式,不能持有仓位或开展自营交易
- 某用户曾以约 45 万美元购入 MekaVerse NFT,现最高报价仅约 295 美元
- predict.fun 首周共发放 10 万积分,第二周积分活动将于今晚结束
- 数据:“1011 内幕巨鲸”整体仓位当前总浮亏已超 5000 万美元
- ZEC 最大空头止盈 300 万美元 ETH 后反手滚仓,持续加码 ZEC、MON 空单
比推专栏
更多 >>观点
比推热门文章
- RWA 固定收益市场 Haven 以 3000 万美元估值完成种子轮融资,Candaq 等参投
- 数据:过去 24 小时全网爆仓 2.29 亿美元,多单爆仓 1.69 亿美元,空单爆仓 6,047.63 万美元
- 灰度:2026 年加密市场聚焦美监管立法与量子计算威胁
- 谭咏麟之子谭晓风曾负责 NFT 游戏 CryptoKitties,现任 Web3 公司高级软件工程师
- 比特币短时回升至 8.8 万美元上方,以太坊回升至 3000 美元上方
- 灰度:价值储存需求和监管明确将推动加密牛市,比特币明年上半年或创新高
- 黄金剧烈波动下 Byreal 链上交易升温,Bybit Alpha Farm 收益率走高
- 100%胜率 1%回撤交易员年赚 5 倍本金,与Paul Wei同看 BTC 空单触发位 9.02 万处
- OKX 将转换 LIT/USDT 盘前合约为标准永续合约
- 分析:白银波动性超越比特币,比特币年末交易量萎缩
比推 APP



