4.Uniswap核心业务逻辑详解

文章目录

  • [3. 核⼼业务逻辑详解](#3. 核⼼业务逻辑详解)
    • [3.1 代币交换(Swap)业务](#3.1 代币交换(Swap)业务)
      • [3.1.1 交换业务的核⼼价值](#3.1.1 交换业务的核⼼价值)
      • [3.1.2 V3交换流程详解](#3.1.2 V3交换流程详解)
      • [3.1.3 交换核心代码实现](#3.1.3 交换核心代码实现)
      • [3.1.4 滑点保护机制](#3.1.4 滑点保护机制)
    • [3.2 流动性提供(Liquidity Provision)业务](#3.2 流动性提供(Liquidity Provision)业务)
      • [3.2.1 流动性提供的核⼼价值](#3.2.1 流动性提供的核⼼价值)
      • [3.2.2 V3添加流动性流程](#3.2.2 V3添加流动性流程)
      • [3.2.4 ⽆常损失(Impermanent Loss)详解](#3.2.4 ⽆常损失(Impermanent Loss)详解)
    • [3.3 路由算法详解](#3.3 路由算法详解)
      • [3.3.1 路由算法的核⼼价值](#3.3.1 路由算法的核⼼价值)
      • [3.3.2 路由算法架构](#3.3.2 路由算法架构)
      • [3.3.3 路径发现算法](#3.3.3 路径发现算法)
      • [3.3.4 最优路径选择](#3.3.4 最优路径选择)
    • [3.4 价格预⾔机详解](#3.4 价格预⾔机详解)
      • [3.4.1 Uniswap价格预⾔机的价值](#3.4.1 Uniswap价格预⾔机的价值)
      • [3.4.2 V3 TWAP实现](#3.4.2 V3 TWAP实现)

3. 核⼼业务逻辑详解

3.1 代币交换(Swap)业务

3.1.1 交换业务的核⼼价值

代币交换是Uniswap最核⼼的功能,允许⽤户⽤⼀种代币换取另⼀种代币。与传统中⼼化交易所不同,Uniswap的交换具有以下特点:

  1. ⽆需订单簿:通过AMM公式⾃动定价,⽆需等待对⼿⽅
  2. 即时成交:只要有流动性,交换⽴即执⾏
  3. ⽆需KYC:完全去中⼼化,⽆需身份验证
  4. 可组合性:可以与其他DeFi协议组合使⽤

3.1.2 V3交换流程详解

交换流程的重要性:

理解Uniswap的交换流程对于开发者和⽤户都⾄关重要。这个流程涉及多个组件的协作,每⼀步都有其特定的⽬的和安全检查。

流程详细说明:

  1. ⽤户发起请求:⽤户在界⾯上输⼊要交换的代币和数量
    • 例如:⽤户输⼊"⽤100 USDC换ETH"
    • 前端⽴即调⽤Quoter获取预估输出量,显示给⽤户
  2. 路由计算:Router需要找到最优的交换路径
    • 可能有多条路径:USDC→ETH(直接)、USDC→DAI→ETH(两跳)
    • Router会计算每条路径的输出量,选择最优的
  3. 价格查询:Quoter模拟交换,获取预估价格
    • Quoter不实际执⾏交换,只是模拟
    • 这样可以快速给⽤户反馈,⽆需等待链上确认
  4. 滑点检查:确保实际输出量不低于⽤户设定的最⼩值
    • ⽤户通常设置0.5%的滑点容忍度
    • 如果预估输出量变化超过这个值,交易会失败
  5. 执⾏交换:实际调⽤Pool合约执⾏交换
    • Pool合约更新价格和流动性
    • 转移代币给⽤户

实际应⽤场景:
场景1:简单单跳交换

⽤户⽤100 USDC换ETH:

  1. Router查询发现USDC→ETH直接路径最优
  2. Quoter模拟交换,预估输出0.05 ETH
  3. ⽤户确认,设置最⼩输出0.0495 ETH(1%滑点)
  4. Router调⽤Pool合约执⾏交换
  5. ⽤户收到0.05 ETH(如果价格没变)

场景2:复杂多跳交换

⽤户⽤1000 USDC换某个新代币NEW:

  1. Router查询发现没有USDC→NEW直接路径
  2. Router找到路径:USDC→ETH→WETH→NEW
  3. Quoter模拟三跳交换,预估输出500 NEW
  4. ⽤户确认,Router依次执⾏三笔交换
  5. ⽤户收到NEW代币

场景3:⼤额交换(滑点保护)

⽤户⽤100万USDC换ETH:

  1. Router查询最优路径
  2. Quoter模拟发现,由于流动性限制,预估输出490 ETH
  3. 但实际执⾏时,价格可能已经变化
  4. 如果实际输出<485 ETH(⽤户设定的最⼩值),交易失败
  5. 这保护了⽤户免受过⼤滑点

V3交换流程详解:

3.1.3 交换核心代码实现

Router合约实现:

c 复制代码
// Uniswap V3 Router核⼼交换逻辑
contract SwapRouter {
	ISwapRouter public immutable swapRouter;
	// 单路径交换
	function swapExactInputSingle(
		address tokenIn,
		address tokenOut,
		uint24 fee,
		address recipient,
		uint256 amountIn,
		uint256 amountOutMinimum,
		uint160 sqrtPriceLimitX96
	 ) external returns (uint256 amountOut) {
		// 1. 授权代币
		IERC20(tokenIn).approve(address(swapRouter), amountIn);
		// 2. 构建交换参数
		ISwapRouter.ExactInputSingleParams memory params =
		ISwapRouter.ExactInputSingleParams({
			tokenIn: tokenIn,
			tokenOut: tokenOut,
			fee: fee,
			recipient: recipient,
			deadline: block.timestamp + 300, // 5分钟超时
			amountIn: amountIn,
			amountOutMinimum: amountOutMinimum,
			sqrtPriceLimitX96: sqrtPriceLimitX96
		 });
		// 3. 执⾏交换
		amountOut = swapRouter.exactInputSingle(params);
		return amountOut;
	 }
	// 多路径交换(通过多个池⼦)
	function swapExactInputMultihop(
		address[] memory tokens,
		uint24[] memory fees,
		address recipient,
		uint256 amountIn,
		uint256 amountOutMinimum
	 ) external returns (uint256 amountOut) {
		// 1. 授权第⼀个代币
		IERC20(tokens[0]).approve(address(swapRouter), amountIn);
		// 2. 构建多跳路径
		bytes memory path = abi.encodePacked(tokens[0]);
		for (uint i = 0; i < fees.length; i++) {
			path = abi.encodePacked(path, fees[i], tokens[i + 1]);
	 	}
		// 3. 执⾏多跳交换
		ISwapRouter.ExactInputParams memory params =
		ISwapRouter.ExactInputParams({
			path: path,
			recipient: recipient,
			deadline: block.timestamp + 300,
			amountIn: amountIn,
			amountOutMinimum: amountOutMinimum
		 };
		amountOut = swapRouter.exactInput(params);
		return amountOut;
	 }
}

前端实现详解:

下⾯的代码展示了如何在前端实现Uniswap交换功能。这个实现使⽤了Wagmi(React Hooks for Ethereum)和Viem(现代化的以太坊库),⽐传统的ethers.js更类型安全和易⽤。

代码设计要点:

  1. 授权检查:在交换前检查代币授权,避免⽤户进⾏不必要的授权交易
  2. 错误处理:完善的错误处理,给⽤户友好的错误提示
  3. 状态管理:使⽤React Hooks管理交易状态(pending、confirming、success)
  4. ⽤户体验:显示交易状态,让⽤户知道交易进展

实际使⽤场景:

场景:⽤户在Uniswap界⾯交换代币

  1. ⽤户输⼊"⽤100 USDC换ETH"
  2. 前端调⽤ useSwap Hook
  3. Hook检查USDC授权额度
  4. 如果授权不⾜,弹出授权交易
  5. ⽤户确认授权,等待确认
  6. 授权确认后,⾃动发起交换交易
  7. 显示"交换中...",等待确认
  8. 交易确认后,显示"交换成功",更新余额

前端实现:交换交互:

c 复制代码
// 使⽤Wagmi和Viem实现交换
import { useWriteContract, useWaitForTransaction } from 'wagmi';
import { parseUnits, formatUnits } from 'viem';
// 交换Hook
export function useSwap() {
	const { writeContract, data: hash, isPending } = useWriteContract();
	const { isLoading: isConfirming, isSuccess } = useWaitForTransaction({ hash });
	const swap = async (
		tokenIn: string,
		tokenOut: string,
		amountIn: string,
		amountOutMin: string,
		fee: number
	 ) => {
		try {
			// 1. 检查并授权代币
			const tokenInContract = {
				address: tokenIn as `0x${string}`,
				abi: ERC20_ABI,
			 };
			// 检查授权额度
			const allowance = await readContract({
				...tokenInContract,
				functionName: 'allowance',
				args: [address, SWAP_ROUTER_ADDRESS],
			 });
			const amountInWei = parseUnits(amountIn, 18);
			if (allowance < amountInWei) {
				// 需要授权
				await writeContract({
				...tokenInContract,
				functionName: 'approve',
				args: [SWAP_ROUTER_ADDRESS, amountInWei],
			 });
		 	}
			// 2. 执⾏交换
			await writeContract({
				address: SWAP_ROUTER_ADDRESS,
				abi: SWAP_ROUTER_ABI,
				functionName: 'exactInputSingle',
				args: [
				 {
					tokenIn,
					tokenOut,
					fee,
					recipient: address,
					deadline: BigInt(Math.floor(Date.now() / 1000) + 300),
					amountIn: amountInWei,
					amountOutMinimum: parseUnits(amountOutMin, 18),
					sqrtPriceLimitX96: 0, // ⽆价格限制
				 },
				 ],
				 });
		 } catch (error) {
			console.error('交换失败:', error);
			throw error;
		 }
	 };
	return { swap, isPending, isConfirming, isSuccess };
}

3.1.4 滑点保护机制

滑点是指实际成交价格与预期价格的偏差。Uniswap通过 amountOutMinimum 参数提供滑点保护。

c 复制代码
// 滑点保护计算
function calculateSlippage(
	expectedAmountOut: bigint,
	actualAmountOut: bigint
	): number {
	if (expectedAmountOut === 0n) return 0;
	const slippage = Number(((expectedAmountOut - actualAmountOut) * 10000n) / expectedAmountOut) / 100;
	return slippage;
}
// 计算最⼩输出量(考虑滑点容忍度)
function calculateMinAmountOut(
	expectedAmountOut: bigint,
	slippageTolerance: number // 例如 0.5 表示 0.5%
): bigint {
	const slippageBps = BigInt(Math.floor(slippageTolerance * 100));
	const minAmountOut = (expectedAmountOut * (10000n - slippageBps)) / 10000n;
	return minAmountOut;
}

3.2 流动性提供(Liquidity Provision)业务

3.2.1 流动性提供的核⼼价值

流动性提供者(LP)是Uniswap⽣态的重要组成部分,他们通过提供代币对获得⼿续费收益。

LP的收益来源:

  1. 交易⼿续费:每次交换的0.05%-1%⼿续费分配给LP
  2. 流动性挖矿:部分协议提供额外代币奖励
  3. 价格优势:在价格区间内提供流动性可以获得更好的价格

LP⾯临的⻛险:

  1. ⽆常损失(Impermanent Loss):当代币价格变化时,LP的资产价值可能低于持有
  2. 价格区间⻛险:如果价格超出LP设置的范围,流动性⽆法被使⽤
  3. 智能合约⻛险:虽然Uniswap经过审计,但仍存在⻛险

3.2.2 V3添加流动性流程

3.2.4 ⽆常损失(Impermanent Loss)详解

⽆常损失概念:

⽆常损失是指LP的资产价值相对于简单持有代币的损失。当代币价格变化时,AMM会⾃动调整池⼦中的代币⽐例,导致LP的资产组合发⽣变化。

⽆常损失计算公式:

c 复制代码
// 计算⽆常损失
function calculateImpermanentLoss(
	priceRatio: number // 当前价格 / 初始价格
): number {
	// IL = 2 * sqrt(priceRatio) / (1 + priceRatio) - 1
	const sqrtPriceRatio = Math.sqrt(priceRatio);
	const il = (2 * sqrtPriceRatio) / (1 + priceRatio) - 1;
	return il * 100; // 转换为百分⽐
}
// 示例计算
const scenarios = [
 { priceChange: 0.5, il: calculateImpermanentLoss(0.5) }, // 价格下跌50%
 { priceChange: 0.8, il: calculateImpermanentLoss(0.8) }, // 价格下跌20%
 { priceChange: 1.0, il: calculateImpermanentLoss(1.0) }, // 价格不变
 { priceChange: 1.25, il: calculateImpermanentLoss(1.25) }, // 价格上涨25%
 { priceChange: 2.0, il: calculateImpermanentLoss(2.0) }, // 价格上涨100%
];
// 结果:
// 价格下跌50%: IL = -5.72%
// 价格下跌20%: IL = -0.60%
// 价格不变: IL = 0%
// 价格上涨25%: IL = -0.60%
// 价格上涨100%: IL = -5.72%

⽆常损失可视化:

3.3 路由算法详解

3.3.1 路由算法的核⼼价值

Uniswap的路由算法负责找到最优的交换路径,可能涉及多个池⼦和多个代币。好的路由算法可以:

  1. 最⼩化滑点:找到价格最好的路径
  2. 最⼤化输出:确保⽤户获得最多的代币
  3. 降低Gas成本:选择Gas效率⾼的路径
  4. 处理复杂路径:⽀持多跳交换

3.3.2 路由算法架构

路由算法的重要性:

路由算法是Uniswap的核⼼竞争⼒之⼀。⼀个好的路由算法可以:

  1. 节省⽤户资⾦:找到最优路径可以节省1-5%的成本
  2. 提升⽤户体验:⾃动找到最优路径,⽤户⽆需⼿动⽐较
  3. 提⾼资本效率:充分利⽤所有可⽤的流动性

路由算法的挑战:

  1. 路径数量爆炸:对于有N个代币的⽹络,可能的路径数量是O(N!)
    • 例如:10个代币,3跳路径可能有数千条
    • 需要智能算法筛选,不能全部计算
  2. 实时性要求:价格和流动性实时变化,算法必须快速
    • ⽤户等待时间不能超过1秒
    • 需要在速度和准确性之间平衡
  3. Gas成本考虑:多跳路径虽然可能价格更好,但Gas成本更⾼
    • 需要综合考虑价格优势和Gas成本
    • ⼩额交易时,Gas成本可能超过价格优势

实际应⽤举例:
场景1:简单路径最优

⽤户想⽤USDC换ETH:

  • 直接路径:USDC→ETH,输出0.5 ETH,Gas 100k
  • 两跳路径:USDC→DAI→ETH,输出0.501 ETH,Gas 150k
  • 选择:直接路径(Gas节省超过价格优势)

场景2:多跳路径更优

⽤户想⽤100万USDC换ETH:

  • 直接路径:输出490 ETH,Gas 100k,总成本490.02 ETH
  • 两跳路径:USDC→USDT→ETH,输出492 ETH,Gas 150k,总成本492.015 ETH
  • 选择:两跳路径(价格优势1.98 ETH > Gas成本0.015 ETH)

场景3:复杂多跳路径

⽤户想⽤新代币A换新代币B:

  • 没有直接路径

  • 路径1:A→ETH→B,输出100 B

  • 路径2:A→USDC→ETH→B,输出102 B

  • 路径3:A→USDC→DAI→ETH→B,输出103 B,但Gas成本⾼

  • 选择:根据交易⾦额选择,⼤额选路径3,⼩额选路径1

路由算法架构:

下⾯的架构图展示了路由算法的完整流程。这个流程确保了找到最优路径,同时保持合理的响应时间。

3.3.3 路径发现算法

路径发现算法的重要性:

路径发现是路由算法的核⼼。⼀个好的路径发现算法可以:

  1. 找到所有可能路径:不遗漏任何潜在的最优路径
  2. 快速执⾏:在合理时间内完成(<100ms)
  3. 避免循环:不产⽣循环路径(如A→B→A)

算法选择:深度优先搜索(DFS)vs ⼴度优先搜索(BFS)

DFS(深度优先):

  • 优点:内存占⽤少,适合深度搜索
  • 缺点:可能找到的路径不是最短的
  • 适⽤:路径⻓度不重要,更关注价格

BFS(⼴度优先):

  • 优点:找到的路径是最短的(跳数最少)
  • 缺点:内存占⽤⼤,不适合深度搜索
  • 适⽤:优先考虑Gas成本(跳数少=Gas少)

实际应⽤举例:

场景:查找USDC到NEW代币的路径

代币关系图:

  • USDC ↔ ETH
  • USDC ↔ DAI
  • ETH ↔ WBTC
  • DAI ↔ USDT
  • WBTC ↔ NEW
  • USDT ↔ NEW

DFS搜索过程:

  1. 从USDC开始
  2. 探索USDC→ETH→WBTC→NEW(3跳)
  3. 探索USDC→DAI→USDT→NEW(3跳)
  4. 探索USDC→ETH→...(继续搜索)

BFS搜索过程:

  1. 第1层:USDC的邻居(ETH, DAI)
  2. 第2层:ETH的邻居(WBTC),DAI的邻居(USDT)
  3. 第3层:WBTC的邻居(NEW),USDT的邻居(NEW)
  4. 找到两条3跳路径

算法优化技巧:

  1. 剪枝:如果当前路径的Gas成本已经超过已知最优路径,停⽌搜索
  2. 缓存:缓存常⽤路径,避免重复计算
  3. 并⾏搜索:使⽤多线程并⾏搜索不同分⽀
  4. 启发式搜索:优先搜索流动性⼤的池⼦

深度优先搜索(DFS)实现:

下⾯的代码展示了使⽤DFS算法发现所有可能路径的实现。这个实现包含了循环检测、路径记录等关键功能。

c 复制代码
// 路由路径发现
interface Route {
	path: string[]; // 代币地址路径
	fees: number[]; // 每个池⼦的⼿续费率
	pools: string[]; // 池⼦地址
}
class RouteFinder {
	private pools: Map<string, PoolInfo> = new Map();
	// 查找所有可能的路径
	findRoutes(
		tokenIn: string,
		tokenOut: string,
		maxHops: number = 3
	 ): Route[] {
	const routes: Route[] = [];
	const visited = new Set<string>();
	// DFS搜索
	this.dfs(
		tokenIn,
		tokenOut,
		 [tokenIn],
		 [],
		 [],
		routes,
		visited,
		maxHops
	 );
	return routes;
 }
private dfs(
		current: string,
		target: string,
		path: string[],
		fees: number[],
		pools: string[],
		routes: Route[],
		visited: Set<string>,
		maxHops: number
	 ) {
		// 找到⽬标
		if (current === target) {
			routes.push({
			path: [...path],
			fees: [...fees],
			pools: [...pools],
		 });
		return;
	 }
		// 超过最⼤跳数
		if (path.length > maxHops) {
			return;
		 }
		// 获取当前代币的所有池⼦
		const connectedPools = this.getConnectedPools(current);
		for (const pool of connectedPools) {
			const nextToken = pool.token0 === current ? pool.token1 : pool.token0;
			const key = `${current}-${nextToken}`;
			// 避免循环
			if (visited.has(key)) {
			continue;
		 }
		visited.add(key);
		path.push(nextToken);
		fees.push(pool.fee);
		pools.push(pool.address);
		// 递归搜索
		this.dfs(
			nextToken,
			target,
			path,
			fees,
			pools,
			routes,
			visited,
			maxHops
		 );
		// 回溯
		visited.delete(key);
		path.pop();
		fees.pop();
		pools.pop();
	 }
	}
	private getConnectedPools(token: string): PoolInfo[] {
		// 从缓存或链上获取连接池⼦
		return Array.from(this.pools.values()).filter(
		 (pool) => pool.token0 === token || pool.token1 === token
		 );
	 }
}

3.3.4 最优路径选择

路径选择的重要性:

找到所有可能路径后,需要选择最优路径。最优路径的定义不是唯⼀的,需要综合考虑:

  1. 输出量:⽤户最关⼼的,能获得多少代币
  2. Gas成本:影响实际收益
  3. 路径可靠性:路径中的池⼦是否稳定
  4. 执⾏时间:多跳路径需要更多时间

评分算法设计:

路径评分需要考虑多个因素,常⻅的评分公式:

score = (amountOut - gasCostInToken) / gasCostInToken

其中:

  • amountOut: 预估输出量
  • gasCostInToken: Gas成本(转换为代币单位)

这个公式的含义是:每单位Gas成本能获得多少代币。分数越⾼,路径越优。

实际应⽤举例:

场景:选择USDC到ETH的路径

找到3条路径:

  • 路径1:USDC→ETH(直接)
    • 输出:0.5 ETH
    • Gas:100k(约20,按ETH=2000计算,0.01 ETH)
    • 评分:(0.5 - 0.01) / 0.01 = 49
  • 路径2:USDC→DAI→ETH(两跳)
    • 输出:0.501 ETH
    • Gas:150k(约$30,0.015 ETH)
    • 评分:(0.501 - 0.015) / 0.015 ≈ 32.4
  • 路径3:USDC→USDT→DAI→ETH(三跳)
    • 输出:0.502 ETH
    • Gas:200k(约$40,0.02 ETH)
    • 评分:(0.502 - 0.02) / 0.02 = 24.1

选择:路径1评分最⾼,选择直接路径

但如果是⼤额交易(100万USDC):

  • 路径1:输出490 ETH,Gas 0.01 ETH,净收益489.99 ETH
  • 路径2:输出492 ETH,Gas 0.015 ETH,净收益491.985 ETH
  • 路径3:输出493 ETH,Gas 0.02 ETH,净收益492.98 ETH

选择:路径2净收益最⾼,选择两跳路径

路径评分算法:

下⾯的代码展示了路径评分和选择的完整实现。这个实现考虑了输出量、Gas成本等多个因素。

c 复制代码
// 路径评分和选择
interface PathScore {
	route: Route;
	amountOut: bigint;
	gasEstimate: bigint;
	score: number; // 综合评分
}
class OptimalRouteSelector {
	// 选择最优路径
	selectOptimalRoute(
		tokenIn: string,
		amountIn: bigint,
		tokenOut: string,
		routes: Route[]
	 ): Route {
		const scores: PathScore[] = [];
		for (const route of routes) {
			// 1. 计算输出量
			const amountOut = this.simulateSwap(route, amountIn);
			// 2. 估算Gas成本
			const gasEstimate = this.estimateGas(route);
			// 3. 计算综合评分
			// 评分 = 输出量 / (Gas成本 * Gas价格)
			const gasPrice = 20n * 10n ** 9n; // 20 Gwei
			const score = Number(amountOut) / Number(gasEstimate * gasPrice);
			scores.push({
				route,
				amountOut,
				gasEstimate,
				score,
			 });
		 }
		// 按评分排序,选择最优
		scores.sort((a, b) => b.score - a.score);
		return scores[0].route;
	 }
	// 模拟交换计算输出量
	private simulateSwap(route: Route, amountIn: bigint): bigint {
		let amountOut = amountIn;
		for (let i = 0; i < route.path.length - 1; i++) {
			const pool = this.getPool(route.pools[i]);
			amountOut = pool.getAmountOut(
				amountOut,
				route.path[i],
				route.path[i + 1]
			 );
		 }
		return amountOut;
	 }
	// 估算Gas成本
	private estimateGas(route: Route): bigint {
		const baseGas = 21000n; // 基础交易Gas
		const swapGas = 100000n; // 每次交换的Gas
		const hopGas = 50000n; // 每跳的额外Gas
		return baseGas + BigInt(route.path.length - 1) * swapGas +
		BigInt(route.path.length - 2) * hopGas;
	}
}

3.4 价格预⾔机详解

3.4.1 Uniswap价格预⾔机的价值

Uniswap的价格预⾔机是DeFi⽣态的重要基础设施,为其他协议提供可靠的价格数据。

应⽤场景:

  1. 借贷协议:计算抵押品价值和清算价格
  2. 衍⽣品协议:结算期货和期权合约
  3. 聚合器:⽐较不同DEX的价格
  4. 算法稳定币:维持稳定币锚定

3.4.2 V3 TWAP实现

TWAP的重要性:

时间加权平均价格(TWAP)是DeFi⽣态的重要基础设施。与现货价格不同,TWAP通过时间加权平均,可以有效抵抗价格操纵攻击。

为什么需要TWAP?

在DeFi中,价格操纵是⼀个严重问题:

  • 场景1:攻击者⽤⼤额资⾦在Uniswap上操纵价格,然后从借贷协议中借出更多资⾦
  • 场景2:攻击者操纵价格触发清算,然后低价买⼊资产

TWAP通过时间加权平均,使得短期价格操纵变得困难:

  • 攻击者需要维持操纵价格⼀段时间(通常30分钟以上)
  • 这⼤⼤增加了攻击成本,使得攻击不经济

TWAP的⼯作原理:

TWAP不是简单的平均价格,⽽是时间加权平均。这意味着:

  • 如果价格在2000维持了10分钟,然后跳到2100维持了1分钟
  • 平均价格 = (2000 * 10 + 2100 * 1) / 11 ≈ $2009
  • ⽽不是简单的 (2000 + 2100) / 2 = $2050

实际应⽤场景:
场景1:借贷协议使⽤TWAP

Aave协议使⽤Uniswap的TWAP价格:

  • ⽤户抵押100 ETH,想借出USDC
  • Aave查询Uniswap的30分钟TWAP价格:$2000
  • Aave计算:100 ETH * 2000 \* 75% = 150,000可借额度
  • 即使⽤户在Uniswap上操纵价格到2100,只要操纵时间\<30分钟,TWAP价格仍然接近2000
  • 结果:攻击失败,⽤户⽆法借出更多资⾦

场景2:算法稳定币使⽤TWAP

算法稳定币协议使⽤TWAP维持锚定:

  • ⽬标价格:$1.00
  • 当前TWAP价格:$0.98(低于⽬标)
  • 协议⾃动增发代币,降低价格
  • 如果使⽤现货价格,可能被操纵;使⽤TWAP,操纵成本⾼

时间加权平均价格(TWAP)原理:

下⾯的流程图展示了TWAP的计算过程。理解这个过程对于使⽤Uniswap价格预⾔机的开发者很重要。

代码实现:

c 复制代码
// Uniswap V3 价格预⾔机
library OracleLibrary {
	// 查询TWAP价格
	function consult(
		address pool,
		uint32 secondsAgo
	 ) internal view returns (int24 timeWeightedAverageTick) {
		require(secondsAgo > 0, 'BP');
		uint32[] memory secondsAgos = new uint32[](2);
		secondsAgos[0] = secondsAgo;
		secondsAgos[1] = 0;
		// 获取累积的tick和时间戳
		 (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) = IUniswapV3Pool(pool).observe(secondsAgos);
		int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
		uint32 timeDelta = secondsAgo;
		// 计算平均tick
		timeWeightedAverageTick = int24(tickCumulativesDelta / int56(uint56(timeDelta)));
		// 处理溢出情况
		if (tickCumulativesDelta < 0 && (tickCumulativesDelta % int56(uint56(timeDelta)) != 0)) {
			timeWeightedAverageTick--;
		 }
	 }
	// 从tick计算价格
	function getQuoteAtTick(
		int24 tick,
		uint128 baseAmount,
		address baseToken,
		address quoteToken
	 ) internal pure returns (uint256 quoteAmount) {
		uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick);
		// 计算价格⽐例
		uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96;
		quoteAmount = baseToken < quoteToken ? FullMath.mulDiv(ratioX192, baseAmount, 1 << 192)	: FullMath.mulDiv(1 << 192, baseAmount, ratioX192);
	}
}
// 使⽤示例
contract PriceOracle {
	function getTWAP(
		address pool,
		address tokenIn,
		address tokenOut,
		uint32 twapInterval
	 ) external view returns (uint256 price) {
		// 1. 获取平均tick
		int24 tick = OracleLibrary.consult(pool, twapInterval);
		// 2. 计算价格(使⽤1e18作为基础单位)
		uint128 baseAmount = 1e18;
		price = OracleLibrary.getQuoteAtTick(
			tick,
			baseAmount,
			tokenIn,
			tokenOut
		 );
		return price;
	 }
}
相关推荐
DICOM医学影像7 小时前
8. go语言从零实现以太坊响应端 - 查询区块链账户余额
golang·区块链·以太坊·web3.0·响应端·从零实现
TechubNews7 小时前
当跨链协议开始将业务从「搭桥」拓展至「swap」
区块链
oMcLin7 小时前
如何在 SUSE Linux Enterprise Server 15 上通过配置 Nginx 与 PHP‑FPM 提升大流量电商平台的服务器响应能力
centos·去中心化·区块链
oMcLin8 小时前
如何在 CentOS 7.9 上部署基于区块链的数字资产交易平台,确保交易透明度与去中心化安全性
centos·去中心化·区块链
MicroTech20259 小时前
后量子密码算法集成:微算法科技(NASDAQ: MLGO)构建区块链安全防护的量子盾牌
科技·安全·区块链
链科天下10 小时前
赵长鹏投资去中心化交易平台,想要打造“链上币安”?
区块链
老蒋每日coding10 小时前
Solidity入门(1)- Hardhat框架
区块链
视***间10 小时前
视程空间AIR算力开发平台:以边缘智能之核,驱动机器人产业迈入全域自动化时代
大数据·人工智能·机器人·区块链·边缘计算·视程空间
oMcLin11 小时前
如何在RHEL 8.6上部署并优化区块链节点,确保跨境支付平台的高安全性与快速交易验证
区块链
DICOM医学影像1 天前
7. go语言从零实现以太坊请求端 - 查询区块链账户余额 - 手写JSONRPC
golang·区块链·以太坊·web3.0·jsonrpc·从零实现以太坊