首先看一下v4版本pool的state结构
/// @notice The state of a pool
/// @dev Note that feeGrowthGlobal can be artificially inflated
/// For pools with a single liquidity position, actors can donate to themselves to freely inflate feeGrowthGlobal
/// atomically donating and collecting fees in the same unlockCallback may make the inflated value more extreme
struct State {
Slot0 slot0;
uint256 feeGrowthGlobal0X128;
uint256 feeGrowthGlobal1X128;
uint128 liquidity;
mapping(int24 tick => TickInfo) ticks;
mapping(int16 wordPos => uint256) tickBitmap;
mapping(bytes32 positionKey => Position.State) positions;
}
slot0
Slot0 是一个紧凑的结构体,使用 bytes32 类型来存储多个字段的数据。通过这种方式,可以在以太坊智能合约中节省存储成本,因为存储多个字段在一个存储槽中比单独存储每个字段更节省 gas。
type Slot0 is bytes32;
using Slot0Library for Slot0 global;
/// @notice Library for getting and setting values in the Slot0 type
library Slot0Library {
uint160 internal constant MASK_160_BITS = 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
uint24 internal constant MASK_24_BITS = 0xFFFFFF;
uint8 internal constant TICK_OFFSET = 160;
uint8 internal constant PROTOCOL_FEE_OFFSET = 184;
uint8 internal constant LP_FEE_OFFSET = 208;
// #### GETTERS ####
function sqrtPriceX96(Slot0 _packed) internal pure returns (uint160 _sqrtPriceX96) {
assembly ("memory-safe") {
_sqrtPriceX96 := and(MASK_160_BITS, _packed)
}
}
function tick(Slot0 _packed) internal pure returns (int24 _tick) {
assembly ("memory-safe") {
_tick := signextend(2, shr(TICK_OFFSET, _packed))
}
}
function protocolFee(Slot0 _packed) internal pure returns (uint24 _protocolFee) {
assembly ("memory-safe") {
_protocolFee := and(MASK_24_BITS, shr(PROTOCOL_FEE_OFFSET, _packed))
}
}
function lpFee(Slot0 _packed) internal pure returns (uint24 _lpFee) {
assembly ("memory-safe") {
_lpFee := and(MASK_24_BITS, shr(LP_FEE_OFFSET, _packed))
}
}
// #### SETTERS ####
function setSqrtPriceX96(Slot0 _packed, uint160 _sqrtPriceX96) internal pure returns (Slot0 _result) {
assembly ("memory-safe") {
_result := or(and(not(MASK_160_BITS), _packed), and(MASK_160_BITS, _sqrtPriceX96))
}
}
function setTick(Slot0 _packed, int24 _tick) internal pure returns (Slot0 _result) {
assembly ("memory-safe") {
_result := or(and(not(shl(TICK_OFFSET, MASK_24_BITS)), _packed), shl(TICK_OFFSET, and(MASK_24_BITS, _tick)))
}
}
function setProtocolFee(Slot0 _packed, uint24 _protocolFee) internal pure returns (Slot0 _result) {
assembly ("memory-safe") {
_result :=
or(
and(not(shl(PROTOCOL_FEE_OFFSET, MASK_24_BITS)), _packed),
shl(PROTOCOL_FEE_OFFSET, and(MASK_24_BITS, _protocolFee))
)
}
}
function setLpFee(Slot0 _packed, uint24 _lpFee) internal pure returns (Slot0 _result) {
assembly ("memory-safe") {
_result :=
or(and(not(shl(LP_FEE_OFFSET, MASK_24_BITS)), _packed), shl(LP_FEE_OFFSET, and(MASK_24_BITS, _lpFee)))
}
}
}
type Slot0 is bytes32; 其中byte32代表32个字节,每个字节8位,总共256位,其数据的布局如下
(从最低有效位到最高有效位):
- 160 bits:
sqrtPriceX96- 当前价格的平方根,编码为 Q96 格式。 - 24 bits:
tick- 当前的 tick 值。 - 12 bits:
protocolFee(方向 0->1) - 协议费用的上 12 位。 - 12 bits:
protocolFee(方向 1->0)

文章详细介绍了UniswapV3中tick的存储结构和价格计算方法,包括tick的流动性管理,Q64.94精度的定点数表示,以及如何通过位图高效管理大量ticks。在价格变动时,根据tick的liquidityNet和liquidityGross更新流动性,并展示了计算sqrtPriceX96的复杂但优化过的算法过程。
最低0.47元/天 解锁文章
845

被折叠的 条评论
为什么被折叠?



