5.Uniswap 技术架构详解

文章目录

  • [4. 技术架构详解](#4. 技术架构详解)
    • [4.1 智能合约架构](#4.1 智能合约架构)
      • [4.1.1 V3合约架构图](#4.1.1 V3合约架构图)
    • [4.1.2 核⼼合约详解](#4.1.2 核⼼合约详解)
    • [4.2 前端架构](#4.2 前端架构)
      • [4.2.1 前端技术栈](#4.2.1 前端技术栈)
    • [4.3 安全机制](#4.3 安全机制)
      • [4.3.1 重⼊攻击防护](#4.3.1 重⼊攻击防护)
      • [4.3.2 价格操纵防护](#4.3.2 价格操纵防护)
      • [4.3.3 闪电贷防护](#4.3.3 闪电贷防护)
    • [4.4 Gas优化技术](#4.4 Gas优化技术)
      • [4.4.1 存储优化](#4.4.1 存储优化)
      • [4.4.2 批量操作优化](#4.4.2 批量操作优化)
    • [4.5 跨链架构](#4.5 跨链架构)
      • [4.5.1 多链部署架构](#4.5.1 多链部署架构)
      • [4.5.2 跨链路由](#4.5.2 跨链路由)

4. 技术架构详解

4.1 智能合约架构

4.1.1 V3合约架构图

合约架构设计理念:

Uniswap V3的合约架构采⽤模块化设计,每个组件都有明确的职责。这种设计的优势:

  1. 可维护性:每个合约职责单⼀,便于理解和维护
  2. 可升级性:可以独⽴升级某个组件,不影响其他组件
  3. 安全性:核⼼逻辑在Pool合约,外围合约即使有问题也不影响核⼼
  4. Gas优化:Library合约可以被多个Pool合约共享,节省部署成本

各层详细说明:
Factory层:

  • 职责:创建和管理Pool合约
  • 关键功能:确保每个交易对只有⼀个Pool(每个费率⼀个)
  • 使⽤场景:当有⼈想创建新的ETH/USDC 0.3%费率池⼦时,Factory检查是否已存在,如果不存在则部署新Pool

Pool层:

  • 职责:存储流动性、执⾏交换、管理价格
  • 关键功能:每个Pool合约管理⼀个交易对的⼀个费率层级
  • 使⽤场景:ETH/USDC可能有3个Pool:0.05%、0.3%、1%,每个都是独⽴合约
  • 为什么这样设计:不同费率需要不同的tickSpacing,分开管理更清晰

Periphery层:

  • 职责:提供⽤户友好的接⼝,处理复杂逻辑
  • SwapRouter:处理代币授权、滑点检查、多跳交换
  • NFT Position Manager:管理LP头⼨,铸造NFT
  • Quoter:查询价格,不实际执⾏交换
  • 使⽤场景:⽤户通过Router交换,Router内部可能调⽤多个Pool

Library层:

  • 职责:提供数学计算函数

  • TickMath:价格和tick转换,这是V3的核⼼数学

  • SqrtPriceMath:平⽅根价格计算

  • LiquidityMath:流动性计算

  • SwapMath:交换计算

  • 为什么⽤Library:这些函数被多个合约使⽤,Library可以节省Gas

实际交互流程举例:

场景:⽤户创建新池⼦并添加流动性

  1. ⽤户调⽤Factory.createPool(ETH, USDC, 3000) // 0.3%费率
  2. Factory检查:getPool[ETH][USDC][3000]是否存在
  3. 如果不存在,Factory部署新的Pool合约
  4. Factory记录:getPool[ETH][USDC][3000] = 新Pool地址
  5. ⽤户通过NFT Position Manager添加流动性
  6. Position Manager调⽤Pool.mint()添加流动性
  7. Pool使⽤LiquidityMath计算所需代币数量
  8. Pool使⽤TickMath更新价格和tick
  9. Position Manager铸造NFT给⽤户

V3合约架构图:

4.1.2 核⼼合约详解

Factory合约:

c 复制代码
// Uniswap V3 Factory核⼼逻辑
contract UniswapV3Factory is IUniswapV3Factory {
	// 池⼦地址映射: (token0, token1, fee) => pool address
	mapping(address => mapping(address => mapping(uint24 => address))) 
	public override getPool;
	// 创建池⼦
	function createPool(
		address tokenA,
		address tokenB,
		uint24 fee
	 ) external override returns (address pool) {
		require(tokenA != tokenB, 'IA'); // Identical addresses
		 (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
		require(token0 != address(0), 'ZA'); // Zero address
		require(fee > 0, 'F0'); // Fee must be positive
		require(getPool[token0][token1][fee] == address(0), 'PE'); // Pool exists
		// 部署新池⼦合约
		pool = address(
			new UniswapV3Pool{
				salt: keccak256(abi.encode(token0, token1, fee))
			 }()
		 );
		// 记录池⼦地址
		getPool[token0][token1][fee] = pool;
		getPool[token1][token0][fee] = pool; // 填充反向映射
		emit PoolCreated(token0, token1, fee, pool);
		return pool;
	 }
	// 设置协议⼿续费率
	function setOwner(address _owner) external override {
		require(owner == msg.sender, 'FNA'); // Forbidden
		owner = _owner;
	 }
	function enableFeeAmount(uint24 fee, int24 tickSpacing) external override {
		require(msg.sender == owner, 'FNA');
		require(fee < 1000000, 'F'); // Fee too high
		require(tickSpacing > 0 && tickSpacing < 16384, 'TS'); // Tick spacing invalid
		feeAmountTickSpacing[fee] = tickSpacing;
		emit FeeAmountEnabled(fee, tickSpacing);
	 }
}

Pool合约核⼼状态:

c 复制代码
// Uniswap V3 Pool核⼼状态和函数
contract UniswapV3Pool is IUniswapV3Pool {
	// 池⼦参数
	address public override factory;
	address public override token0;
	address public override token1;
	uint24 public override fee;
	int24 public override tickSpacing;
	// 全局状态
	uint128 public override liquidity; // 当前活跃流动性
	uint160 public override sqrtPriceX96; // 当前价格(Q64.96格式)
	int24 public override tick; // 当前tick
	// Tick信息
	mapping(int24 => Tick.Info) public override ticks;
	mapping(int16 => uint256) public override tickBitmap;
	// 观察者(⽤于价格预⾔机)
	struct Observation {
		uint32 blockTimestamp;
		int56 tickCumulative;
		uint160 secondsPerLiquidityCumulativeX128;
		bool initialized;
	 }
	Observation[65535] public override observations;
	// 协议⼿续费
	uint128 public override protocolFeesToken0;
	uint128 public override protocolFeesToken1;
	// 交换函数
	function swap(
		address recipient,
		bool zeroForOne,
		int256 amountSpecified,
		uint160 sqrtPriceLimitX96,
		bytes calldata data
	 ) external override returns (int256 amount0, int256 amount1) {
		// 实现交换逻辑
		// ...
	 }
	// 观察函数(⽤于价格预⾔机)
	function observe(uint32[] calldata secondsAgos)	external	view	override
	returns (
		int56[] memory tickCumulatives,
		uint160[] memory secondsPerLiquidityCumulativeX128s
	 )
	 {
		// 实现观察逻辑
		// ...
	 }
}

4.1.3 数学库详解
TickMath库详解:

TickMath是V3最核⼼的数学库之⼀,它处理价格和tick之间的转换。理解这个库对于理解V3的价格机制⾄关重要。

为什么需要Tick?

在V3中,价格不是连续的值,⽽是离散的tick。这样设计的原因:

  1. Gas优化:离散值可以⽤整数存储,计算更快
  2. 精度控制:tick spacing控制价格精度
  3. 流动性管理:每个tick可以存储流动性

Tick和价格的关系:

price = 1.0001^tick

例如:

  • tick = 0: price = 1.0001^0 = 1.0
  • tick = 6931: price = 1.0001^6931 ≈ 2.0
  • tick = -6931: price = 1.0001^(-6931) ≈ 0.5

为什么⽤1.0001?

1.0001是⼀个精⼼选择的常数:

如果tick spacing = 60,相邻tick的价格差异约为0.6%

这个差异⾜够⼩(滑点可控),⼜⾜够⼤(Gas可接受)

TickMath库:处理价格和tick之间的转换

下⾯的代码展示了TickMath库的核⼼实现。这个实现使⽤了⾼效的位操作和数学技巧,确保计算的准确性和Gas效率。

c 复制代码
// TickMath库:价格和tick转换
library TickMath {
	// 最⼩tick(对应最⼩价格)
	int24 internal constant MIN_TICK = -887272;
	// 最⼤tick(对应最⼤价格)
	int24 internal constant MAX_TICK = -MIN_TICK;
	// 最⼩价格(sqrtPrice)
	uint160 internal constant MIN_SQRT_RATIO = 4295128739;
	// 最⼤价格(sqrtPrice)
	uint160 internal constant MAX_SQRT_RATIO =
	1461446703485210103287273052203988822378723970342;
	// 从tick计算sqrtPrice
	function getSqrtRatioAtTick(int24 tick) 	internal	pure returns (uint160 sqrtPriceX96) 
	 {
		require(tick >= MIN_TICK && tick <= MAX_TICK, 'T'); // Tick out of range
		uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
		require(absTick <= uint256(int256(MAX_TICK)), 'T');
		uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001: 0x100000000000000000000000000000000;
		if (absTick & 0x2 != 0) 
			ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
		if (absTick & 0x4 != 0) 
			ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
		// ... 更多位操作
		if (tick > 0) ratio = type(uint256).max / ratio;
		sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
	 }
	
	// 从sqrtPrice计算tick
	function getTickAtSqrtRatio(uint160 sqrtPriceX96) 	internal	pure returns (int24 tick) 
	 {
		require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,'R');
		uint256 ratio = uint256(sqrtPriceX96) << 32;
		uint256 r = ratio;
		uint256 msb = 0;
		// 找到最⾼有效位
		// ...
		r = (r * 0x5d6af8dedb81196699c329225ee604) >> 128;
		r = (r * 0x2216e584f5fa1ea926041bedfe98) >> 128;
		r = (r * 0x48a170391f7dc42444e8fa2) >> 128;
		int256 log_2 = (int256(msb) - 128) << 64;
		// ... 计算log
		tick = int24((log_2 - 3402992956809132418596140100660240240) >> 128);
	 }
}

SwapMath库详解:

SwapMath是V3交换计算的核⼼库,它负责计算单步交换的输⼊输出量。这个库的复杂性在于需要处理多种情况:

  1. 精确输⼊ vs 精确输出:⽤户可能指定输⼊量或输出量
  2. 价格限制:⽤户可能设置价格上限或下限
  3. 流动性变化:交换过程中可能跨越多个tick,流动性会变化
  4. ⼿续费计算:需要准确计算⼿续费

交换步骤的计算过程:

在V3中,⼀次交换可能跨越多个tick,每个tick内的流动性是固定的。SwapMath计算的是单个tick内的交换步骤:

  1. 计算⽬标价格:根据剩余输⼊量和当前流动性,计算能到达的价格
  2. 检查边界:如果⽬标价格超出当前tick,只能到达tick边界
  3. 计算输⼊输出:根据价格变化计算实际的输⼊输出量
  4. 计算⼿续费:根据输⼊量和费率计算⼿续费

实际计算示例:

场景:在单个tick内交换

当前状态:

  • 当前价格:sqrtPrice = 44.72(对应$2000)
  • 当前tick:6931
  • 当前流动性:L = 1000
  • ⽤户输⼊:1000 USDC(精确输⼊)

计算过程:

  1. 计算⽬标价格:根据L和输⼊量,计算新的sqrtPrice
  2. 检查是否超出tick:如果新价格仍在tick 6931内,继续;否则只能到达tick边界
  3. 计算输出量:根据价格变化计算ETH输出量
  4. 计算⼿续费:1000 USDC × 0.3% = 3 USDC

SwapMath库:计算交换步骤

下⾯的代码展示了SwapMath库的核⼼实现。这个实现处理了精确输⼊、精确输出、价格限制等多种情况。

c 复制代码
// SwapMath库:交换计算
library SwapMath {
	// 计算单步交换
	function computeSwapStep(
		uint160 sqrtRatioCurrentX96,
		uint160 sqrtRatioTargetX96,
		uint128 liquidity,
		int256 amountRemaining,
		uint24 feePips
	 )
	internal pure returns (
		uint160 sqrtRatioNextX96,
		uint256 amountIn,
		uint256 amountOut,
		uint256 feeAmount
	 )
	 {
		bool zeroForOne = sqrtRatioCurrentX96 >= sqrtRatioTargetX96;
		bool exactIn = amountRemaining >= 0;
		uint256 amountRemainingLessFee = FullMath.mulDiv(uint256(amountRemaining < 0 ? -amountRemaining : amountRemaining),1e6 - feePips,1e6 );
		if (exactIn) { 
			amountIn = zeroForOne ? SqrtPriceMath.getAmount0Delta(sqrtRatioTargetX96,sqrtRatioCurrentX96,liquidity,true): SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96,sqrtRatioTargetX96,liquidity,true);
			if (amountRemainingLessFee >= amountIn) {
				sqrtRatioNextX96 = sqrtRatioTargetX96;
			 } else {
				sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromInput(sqrtRatioCurrentX96,liquidity,	amountRemainingLessFee,zeroForOne);
			 }
		 } else {
			amountOut = zeroForOne ? SqrtPriceMath.getAmount1Delta(sqrtRatioTargetX96,sqrtRatioCurrentX96,liquidity,false ): SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96,sqrtRatioTargetX96,liquidity,false);
			if (uint256(-amountRemaining) >= amountOut) {
				sqrtRatioNextX96 = sqrtRatioTargetX96;
			 } else {
				sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromOutput(sqrtRatioCurrentX96,liquidity,	uint256(-amountRemaining),zeroForOne);
			 }
		 }
		bool max = sqrtRatioTargetX96 == sqrtRatioNextX96;
		// 计算实际输⼊输出量
		if (zeroForOne) {
			amountIn = max && exactIn ? amountIn	: SqrtPriceMath.getAmount0Delta(	sqrtRatioNextX96,	sqrtRatioCurrentX96,liquidity,	true );
			amountOut = max && !exactIn ? amountOut	: SqrtPriceMath.getAmount1Delta(	sqrtRatioNextX96,	sqrtRatioCurrentX96,liquidity,false );
		 } else {
			amountIn = max && exactIn? amountIn	: SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96,sqrtRatioNextX96,	liquidity,true );
			amountOut = max && !exactIn ? amountOut: SqrtPriceMath.getAmount0Delta(		sqrtRatioCurrentX96,sqrtRatioNextX96,	liquidity,	false);
		 }
		// 计算⼿续费
		if (!exactIn && amountOut > uint256(-amountRemaining)) {
			amountOut = uint256(-amountRemaining);
		 }
		if (exactIn && sqrtRatioNextX96 != sqrtRatioTargetX96) {
			feeAmount = uint256(amountRemaining) - amountIn;
		 } else {
			feeAmount = FullMath.mulDivRoundingUp(amountIn,feePips,1e6 - feePips);
		}
	 }
}

4.2 前端架构

4.2.1 前端技术栈

前端架构设计说明:

Uniswap的前端架构采⽤现代化的React技术栈,结合Web3库实现与区块链的交互。这个架构的设计考虑了:

  1. ⽤户体验:快速响应、流畅交互、清晰反馈
  2. 开发效率:使⽤成熟的库和框架,减少开发时间
  3. 可维护性:模块化设计,便于团队协作
  4. 性能优化:缓存、懒加载、代码分割

各层详细说明:

UI层:

React组件:可复⽤的UI组件,如TokenInput、SwapButton等

Tailwind CSS:实⽤优先的CSS框架,快速构建界⾯

React Router:单⻚应⽤路由,实现⻚⾯导航

使⽤场景:⽤户打开Uniswap界⾯,看到交换⻚⾯,点击"Pool"跳转到流动性⻚⾯

状态管理:

Zustand/Redux:全局状态管理,存储⽤户选择的代币、⾦额等

TanStack Query:数据获取和缓存,缓存价格、余额等数据

Wagmi状态:钱包连接状态、当前账户等

使⽤场景:⽤户选择USDC作为输⼊代币,状态更新,触发价格查询

区块链交互:

Wagmi Hooks:React Hooks封装,简化Web3交互

Viem:类型安全的以太坊库,⽐ethers.js更现代

Uniswap SDK:Uniswap官⽅SDK,处理路由计算、价格计算等

使⽤场景:⽤户点击"交换"按钮,前端使⽤Wagmi发送交易

数据层:

The Graph API:查询历史交易、流动性数据等

Uniswap Routing API:获取最优交换路径

价格API:实时价格数据

使⽤场景:前端需要显示"24⼩时交易量",调⽤The Graph API获取数据

实际应⽤流程举例:

场景:⽤户完成⼀次交换

  1. ⽤户输⼊:⽤户在界⾯输⼊"100 USDC换ETH"
  2. 状态更新:Zustand更新tokenIn和amountIn状态
  3. 触发查询:TanStack Query⾃动调⽤Routing API查询最优路径
  4. 显示结果:前端显示预估输出"0.05 ETH"
  5. ⽤户确认:⽤户点击"交换"按钮
  6. 检查授权:Wagmi检查USDC授权额度
  7. 授权不⾜:如果授权不⾜,弹出授权交易
  8. 执⾏交换:授权后,发送交换交易
  9. 等待确认:显示"交易确认中..."
  10. 完成:交易确认后,显示成功,更新余额

前端技术栈:

4.3 安全机制

4.3.1 重⼊攻击防护

c 复制代码
// Uniswap V3 重⼊攻击防护
contract UniswapV3Pool {
	// 使⽤ReentrancyGuard
	modifier lock() {
		require(unlocked == 1, 'LOK'); // Locked
		unlocked = 0;
		_;
		unlocked = 1;
	 }
	uint8 private unlocked = 1;
	function swap(...) external override lock returns (...) {
		// 交换逻辑
	 }
	function mint(...) external override lock returns (...) {
		// 添加流动性逻辑
	 }
}

4.3.2 价格操纵防护

价格操纵攻击的威胁:

在AMM中,价格由池⼦中的代币⽐例决定,这使得价格操纵成为可能。攻击者可以通过⼤额交易临时操纵价格,然后利⽤这个价格在其他协议中获利。

攻击场景举例:

场景1:借贷协议价格操纵攻击

  1. 攻击者观察:Aave使⽤Uniswap的现货价格计算抵押率
  2. 攻击者在Uniswap上⽤⼤额资⾦买⼊ETH,将价格从2000推到2100
  3. 攻击者⽴即在Aave上⽤ETH作为抵押品借出USDC
  4. 由于ETH价格被操纵到$2100,攻击者可以借出更多USDC
  5. 攻击者卖出ETH,价格回到$2000
  6. 攻击者获利:借出的USDC - 实际ETH价值

防护措施:

  1. 价格限制(sqrtPriceLimitX96):⽤户可以设置价格变化的上限
    • 例如:⽤户设置价格不能超过$2050
    • 如果交换会导致价格超过$2050,交易失败
    • 这保护了⽤户,但也限制了交换的灵活性
  2. TWAP价格预⾔机:使⽤时间加权平均价格,⽽不是现货价格
    • 短期价格操纵⽆法影响TWAP
    • 攻击者需要维持操纵价格30分钟以上
    • 这⼤⼤增加了攻击成本
  3. 滑点保护:⽤户设置最⼩输出量
    • 如果实际输出低于最⼩值,交易失败
    • 这保护⽤户免受价格突然变化的影响

实际应⽤场景

场景:⽤户设置价格限制交换

⽤户想⽤100万USDC换ETH,担⼼价格被操纵:

  1. ⽤户设置价格限制:不能超过2050(当前价格2000)
  2. 如果交换会导致价格超过$2050,交易失败
  3. 这保护了⽤户,但也可能因为正常的价格波动导致交易失败
  4. 建议:⼤额交易使⽤价格限制,⼩额交易可以放宽
    价格操纵防护机制:
    下⾯的流程图展示了价格限制检查的完整流程。这个机制确保了价格不会超出⽤户设定的范围。

代码实现:

c 复制代码
// 价格限制检查
function swap(
	address recipient,
	bool zeroForOne,
	int256 amountSpecified,
	uint160 sqrtPriceLimitX96, // 价格限制
	bytes calldata data
) external override lock returns (int256 amount0, int256 amount1) {
	// 1. 检查价格限制
	require(
		zeroForOne
		 ? sqrtPriceLimitX96 < sqrtPriceX96 && sqrtPriceLimitX96 >
		TickMath.MIN_SQRT_RATIO
		: sqrtPriceLimitX96 > sqrtPriceX96 && sqrtPriceLimitX96 <
		TickMath.MAX_SQRT_RATIO,
		'SPL' // Square root price limit
		 );
		// 2. 执⾏交换
		// ...
}

4.3.3 闪电贷防护

功能作⽤: 闪电贷是DeFi的创新⾦融⼯具,允许⽤户在单个交易中⽆抵押借⼊⼤量资⾦,只要在同⼀个交易中归还即可。这种机制为套利、债务重组、清算等操作提供了强⼤的⼯具。

核⼼特点:

  1. ⽆抵押借贷:不需要提供任何抵押品
  2. 即时执⾏:借款和还款在同⼀个交易中完成
  3. 原⼦性操作:要么全部成功,要么全部失败
  4. 低成本:通常只收取0.05%-0.1%的⼿续费
  5. ⾼流动性:可以借⼊协议中的全部可⽤资⾦

闪电贷执⾏流程详解

对接流程:

  1. 发起请求:⽤户调⽤闪电贷合约的借款函数
  2. 资⾦转移:协议将资⾦转移到⽤户指定的合约
  3. 回调执⾏:协议调⽤⽤户合约的executeOperation函数
  4. ⽤户逻辑:⽤户在回调中执⾏套利、清算等操作
  5. 余额检查:协议检查资⾦和⼿续费是否已归还
  6. 交易完成:如果归还成功,交易确认;否则整个交易回滚
c 复制代码
// 闪电贷检查
function swap(...) external override lock returns (...) {
	// 记录交换前的余额
	uint256 balance0Before = IERC20(token0).balanceOf(address(this));
	uint256 balance1Before = IERC20(token1).balanceOf(address(this));
	// 执⾏交换逻辑
	// ...
	// 验证余额变化(防⽌闪电贷攻击)
	require(
		balance0After >= balance0Before,
		'IIA' // Insufficient input amount
	 );
	require(
		balance1After >= balance1Before,
		'IIA'
	 );
}

4.4 Gas优化技术

4.4.1 存储优化

c 复制代码
// 使⽤打包存储减少SSTORE操作
struct Slot0 {
	uint160 sqrtPriceX96; // 20 bytes
	int24 tick; // 3 bytes
	uint16 observationIndex; // 2 bytes
	uint16 observationCardinality; // 2 bytes
	uint16 observationCardinalityNext; // 2 bytes
	uint8 feeProtocol; // 1 byte
	bool unlocked; // 1 byte
} // 总共31字节,可以打包在⼀个slot中
Slot0 public slot0; // 单个SSTORE操作

4.4.2 批量操作优化

c 复制代码
// V4 Flash Accounting:批量操作
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {
	results = new bytes[](data.length);
	for (uint256 i = 0; i < data.length; i++) {
		 (bool success, bytes memory result) = address(this).delegatecall(data[i]);
		require(success, 'MC'); // Multicall failed
		results[i] = result;
	 }
}

4.5 跨链架构

4.5.1 多链部署架构

4.5.2 跨链路由

c 复制代码
// 跨链交换实现
async function crossChainSwap(
	tokenIn: Token,
	tokenOut: Token,
	amountIn: bigint,
	sourceChain: Chain,
	targetChain: Chain
) {
	// 1. 在主⽹执⾏交换
	if (sourceChain.id === 1) {
		await swapOnMainnet(tokenIn, tokenOut, amountIn);
	 }
	// 2. 跨链桥接
	await bridgeToken(tokenOut, sourceChain, targetChain);
	// 3. 在⽬标链执⾏交换
	if (targetChain.id !== 1) {
		await swapOnL2(tokenOut, targetToken, targetChain);
	 }
}
相关推荐
fakerth2 小时前
【OpenHarmony】Hiview架构
架构·操作系统·openharmony
山峰哥3 小时前
Python爬虫实战:从零构建高效数据采集系统
开发语言·数据库·爬虫·python·性能优化·架构
Snail_2025121412 小时前
海光DCU节点架构
架构·cpu·dcu·海光
间彧12 小时前
30+程序员的自白:我与架构师之间,隔了多少个分布式锁?
架构
CloudWeGo16 小时前
当 ABCoder 遇上 Deep Code Research
架构
Wang2012201317 小时前
RNN和LSTM对比
人工智能·算法·架构
TG:@yunlaoda360 云老大17 小时前
如何使用华为云国际站代理商WSA配置与架构交付中的安全策略?
网络·架构·华为云
ppo9218 小时前
Spring Boot 集成 Kafka 3.9.0:部署、监控与消息发送教程
java·架构
RaymondZhao3418 小时前
【深度硬核】AI Infra 架构漫游指南
人工智能·深度学习·架构