场景:只有usdc/weth, weth/wbtc的池子,但是用户希望用usdc兑换wbtc。
可能的路径:USDC → WETH → WBTC(两跳)
这种只有两个池子的情况下的话,路径就是单一的,考虑的问题是滑点?手续费?流动性?以确保amountOut最大化。
假设现在有多个池子,usdc/weth, weth/wbtc, wbtc/usdt,用户希望用usdc换usdt。
可能得路径:USDC → WETH → WBTC → USDT(三跳)
由于tick间隔也是一个标识池子的参数,于是:
USDC,60,WETH,10,WBTC,60,USDT
其中60、10都是tick间隔。当然都是假设。
路径构建
path = bytes.concat( bytes20(address(weth)), // WETH 的地址 (20 字节) bytes3(uint24(60)), // WETH 和 USDC 池子的 tick 间隔 60 (3 字节) bytes20(address(usdc)), // USDC 的地址 (20 字节) bytes3(uint24(10)), // USDC 和 USDT 池子的 tick 间隔 10 (3 字节) bytes20(address(usdt)), // USDT 的地址 (20 字节) bytes3(uint24(60)), // USDT 和 WBTC 池子的 tick 间隔 60 (3 字节) bytes20(address(wbtc)) // WBTC 的地址 (20 字节) );
定义常量
library Path { /// @dev The length the bytes encoded address uint256 private constant ADDR_SIZE = 20; /// @dev The length the bytes encoded tick spacing uint256 private constant TICKSPACING_SIZE = 3; // 到下一个token的偏移量 23 uint256 private constant NEXT_OFFSET = ADDR_SIZE + TICKSPACING_SIZE; // 到下一个池子的偏移量 43 uint256 private constant POP_OFFSET = NEXT_OFFSET + ADDR_SIZE; // 两个或以上池子的最小路径长度 66 uint256 private constant MULTIPLE_POOLS_MIN_LENGTH = POP_OFFSET + NEXT_OFFSET;
计算路径中池子数量
// 减去第一个token 3 function numPools(bytes memory path) internal pure returns (uint256) { return (path.length - ADDR_SIZE) / NEXT_OFFSET; }
判断一个路径是否有多个池子
// 只需要跟 MULTIPLE_POOLS_MIN_LENGTH 比较 function hasMultiplePools(bytes memory path) internal pure returns (bool) { return path.length >= MULTIPLE_POOLS_MIN_LENGTH; }
提取第一个池子的参数
function getFirstPool(bytes memory path) internal pure returns (bytes memory) { return path.slice(0, POP_OFFSET); } // path.slice(0, POP_OFFSET) 的作用是: // slice 方法:用于提取字节数组的一个子数组。它接受两个参数: // 第一个