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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
| // 核心 swap 函数: // - zeroForOne = true 表示 token0 → token1 // - zeroForOne = false 表示 token1 → token0 // - amountSpecified > 0 表示 exactInput(输入固定) // - amountSpecified < 0 表示 exactOutput(输出固定) function swap( address recipient, // 最终接收输出代币的地址 bool zeroForOne, // 交易方向,token0→token1 为 true int256 amountSpecified, // exactInput 或 exactOutput 的数量 uint160 sqrtPriceLimitX96, // 本次 swap 可允许触达的价格下限/上限 bytes calldata data // 传给 callback 的数据 ) external override noDelegateCall returns (int256 amount0, int256 amount1) {
// 不能为 0,否则 swap 没意义 require(amountSpecified != 0, 'AS');
// 读取插槽变量 slot0(包含 tick、价格、锁状态、观察者指针等) Slot0 memory slot0Start = slot0;
// 必须未锁(防止重入) require(slot0Start.unlocked, 'LOK');
// 检查 sqrtPriceLimit 是否朝正确方向移动,避免 invalid price 移动 require( zeroForOne ? sqrtPriceLimitX96 < slot0Start.sqrtPriceX96 && sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO : sqrtPriceLimitX96 > slot0Start.sqrtPriceX96 && sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO, 'SPL' );
// 上锁(整个 swap 期间锁住 pool) slot0.unlocked = false;
// 初始化 SwapCache,用于缓存 swap 过程中的共享信息 SwapCache memory cache = SwapCache({ liquidityStart: liquidity, // 初始总流动性 blockTimestamp: _blockTimestamp(), // 当前时间戳,用于 oracle feeProtocol: zeroForOne ? (slot0Start.feeProtocol % 16) // token0 手续费协议分成 : (slot0Start.feeProtocol >> 4), // token1 手续费协议分成 secondsPerLiquidityCumulativeX128: 0, // 初始化 tickCumulative: 0, // 初始化 computedLatestObservation: false // 标记是否查询过 oracle });
// exactInput = true => 用户提供输入 A,求输出 B bool exactInput = amountSpecified > 0;
// 初始化 swap 状态 SwapState memory state = SwapState({ amountSpecifiedRemaining: amountSpecified, // 输入/输出剩余数量 amountCalculated: 0, // 已计算的输出/输入数量 sqrtPriceX96: slot0Start.sqrtPriceX96, // 当前价格 tick: slot0Start.tick, // 当前 tick feeGrowthGlobalX128: zeroForOne ? feeGrowthGlobal0X128 // 使用哪一边的 feeGrowth : feeGrowthGlobal1X128, protocolFee: 0, // 累计协议收入 liquidity: cache.liquidityStart // 当前活跃区间的流动性 });
// 主循环:只要没完成指定数量,并且价格没到限制,就继续 swap while (state.amountSpecifiedRemaining != 0 && state.sqrtPriceX96 != sqrtPriceLimitX96) {
StepComputations memory step;
// 当前步骤的起始价格 step.sqrtPriceStartX96 = state.sqrtPriceX96;
// 查找下一个初始化 tick(是否存在流动性边界) (step.tickNext, step.initialized) = tickBitmap .nextInitializedTickWithinOneWord( state.tick, tickSpacing, zeroForOne );
// 限制 tickNext 不越界(bitmap 不知道 min/max) if (step.tickNext < TickMath.MIN_TICK) { step.tickNext = TickMath.MIN_TICK; } else if (step.tickNext > TickMath.MAX_TICK) { step.tickNext = TickMath.MAX_TICK; }
// 计算 tickNext 对应的 sqrt(price) step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext);
// 调用 SwapMath,计算该步: // - 新价格 // - 本 step 的输入 amountIn // - 输出 amountOut // - 本 step 手续费 feeAmount (state.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount) = SwapMath.computeSwapStep( state.sqrtPriceX96, ( zeroForOne ? step.sqrtPriceNextX96 < sqrtPriceLimitX96 : step.sqrtPriceNextX96 > sqrtPriceLimitX96 ) ? sqrtPriceLimitX96 : step.sqrtPriceNextX96, state.liquidity, state.amountSpecifiedRemaining, fee );
// // 处理 exactInput / exactOutput 两种计算方式 // if (exactInput) { // 输入用掉(含 fee),输出累加 state.amountSpecifiedRemaining -= (step.amountIn + step.feeAmount).toInt256();
state.amountCalculated -= step.amountOut.toInt256(); } else { // 输出减少,输入累加 state.amountSpecifiedRemaining += step.amountOut.toInt256();
state.amountCalculated += (step.amountIn + step.feeAmount).toInt256(); }
// 协议分成(如 feeProtocol > 0) if (cache.feeProtocol > 0) { uint256 delta = step.feeAmount / cache.feeProtocol; // 分给协议的部分 step.feeAmount -= delta; // 剩余的计入 LP feeGrowth state.protocolFee += uint128(delta); }
// 更新 feeGrowthGlobal if (state.liquidity > 0) state.feeGrowthGlobalX128 += FullMath.mulDiv( step.feeAmount, FixedPoint128.Q128, state.liquidity );
// // 是否跨过 tickNext // if (state.sqrtPriceX96 == step.sqrtPriceNextX96) { // tickNext 是已初始化的 tick,需要计算 liquidityNet if (step.initialized) {
// 第一次跨 tick 才计算 oracle(节省 gas) if (!cache.computedLatestObservation) { (cache.tickCumulative, cache.secondsPerLiquidityCumulativeX128) = observations.observeSingle( cache.blockTimestamp, 0, slot0Start.tick, slot0Start.observationIndex, cache.liquidityStart, slot0Start.observationCardinality ); cache.computedLatestObservation = true; }
// 计算 liquidityNet(可能会增加或减少) int128 liquidityNet = ticks.cross( step.tickNext, (zeroForOne ? state.feeGrowthGlobalX128 : feeGrowthGlobal0X128), (zeroForOne ? feeGrowthGlobal1X128 : state.feeGrowthGlobalX128), cache.secondsPerLiquidityCumulativeX128, cache.tickCumulative, cache.blockTimestamp );
// 当 zeroForOne 时(价格左移),liquidityNet 要取反 if (zeroForOne) liquidityNet = -liquidityNet;
// 更新当前活跃区间流动性 state.liquidity = LiquidityMath.addDelta(state.liquidity, liquidityNet); }
// next tick 成为 current tick(左移时 -1) state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext;
} else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) { // 若未跨到完整 tick,则根据 sqrtPrice 反算 tick state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96); } }
// // swap 结束,更新 slot0 // if (state.tick != slot0Start.tick) { // tick 变了,需要写 oracle observation (uint16 observationIndex, uint16 observationCardinality) = observations.write( slot0Start.observationIndex, cache.blockTimestamp, slot0Start.tick, cache.liquidityStart, slot0Start.observationCardinality, slot0Start.observationCardinalityNext );
// 更新存储 ( slot0.sqrtPriceX96, slot0.tick, slot0.observationIndex, slot0.observationCardinality ) = ( state.sqrtPriceX96, state.tick, observationIndex, observationCardinality ); } else { // tick 未变化只更新价格 slot0.sqrtPriceX96 = state.sqrtPriceX96; }
// 如果流动性变化,则写回 if (cache.liquidityStart != state.liquidity) liquidity = state.liquidity;
// 更新 feeGrowthGlobal 和协议费用 if (zeroForOne) { feeGrowthGlobal0X128 = state.feeGrowthGlobalX128; if (state.protocolFee > 0) protocolFees.token0 += state.protocolFee; } else { feeGrowthGlobal1X128 = state.feeGrowthGlobalX128; if (state.protocolFee > 0) protocolFees.token1 += state.protocolFee; }
// 计算最终的交易结果 (amount0, amount1) = ( zeroForOne == exactInput ? (amountSpecified - state.amountSpecifiedRemaining, state.amountCalculated) : (state.amountCalculated, amountSpecified - state.amountSpecifiedRemaining) );
// // 最终的外部代币转账与回调校验 // if (zeroForOne) { // 如果 output token1 需要转给 recipient if (amount1 < 0) TransferHelper.safeTransfer(token1, recipient, uint256(-amount1));
// 检查 callback 是否真的支付了 amount0 uint256 balance0Before = balance0(); IUniswapV3SwapCallback(msg.sender).uniswapV3SwapCallback(amount0, amount1, data); require(balance0Before + uint256(amount0) <= balance0(), 'IIA');
} else { if (amount0 < 0) TransferHelper.safeTransfer(token0, recipient, uint256(-amount0));
uint256 balance1Before = balance1(); IUniswapV3SwapCallback(msg.sender).uniswapV3SwapCallback(amount0, amount1, data); require(balance1Before + uint256(amount1) <= balance1(), 'IIA'); }
// 记录事件 emit Swap(msg.sender, recipient, amount0, amount1, state.sqrtPriceX96, state.liquidity, state.tick);
// 解锁 pool slot0.unlocked = true; }
|