class PathFinder {
constructor(factoryAddress, provider) {
this.factory = new ethers.Contract(factoryAddress, factoryABI, provider);
this.provider = provider;
this.commonBases = [WJU_ADDRESS, USDC_ADDRESS, USDT_ADDRESS]; // 常用中间代币
}
async findBestPath(tokenIn, tokenOut, amountIn) {
const paths = [];
// 1. 直接路径
const directPath = await this.checkDirectPath(tokenIn, tokenOut, amountIn);
if (directPath) {
paths.push(directPath);
}
// 2. 通过常用基础代币的路径
for (const base of this.commonBases) {
if (base !== tokenIn && base !== tokenOut) {
const path = await this.checkTwoHopPath(tokenIn, base, tokenOut, amountIn);
if (path) {
paths.push(path);
}
}
}
// 3. 选择最优路径(输出最大)
return paths.reduce((best, current) =>
current.outputAmount.gt(best.outputAmount) ? current : best
);
}
async checkDirectPath(tokenIn, tokenOut, amountIn) {
const fees = [50, 100, 200, 300]; // 检查所有费率等级
let bestOutput = ethers.BigNumber.from(0);
let bestFee = 0;
for (const fee of fees) {
try {
const pairAddress = await this.factory.getPair(tokenIn, tokenOut, fee);
if (pairAddress === ethers.constants.AddressZero) continue;
const pair = new ethers.Contract(pairAddress, pairABI, this.provider);
const reserves = await pair.getReserves();
if (reserves.reserve0.gt(0) && reserves.reserve1.gt(0)) {
const output = this.calculateOutput(amountIn, reserves, fee, tokenIn, tokenOut);
if (output.gt(bestOutput)) {
bestOutput = output;
bestFee = fee;
}
}
} catch (error) {
continue;
}
}
if (bestOutput.gt(0)) {
return {
path: [tokenIn, tokenOut],
fees: [bestFee],
outputAmount: bestOutput,
hops: 1
};
}
return null;
}
async checkTwoHopPath(tokenIn, intermediate, tokenOut, amountIn) {
// 检查第一跳: tokenIn → intermediate
const firstHop = await this.checkDirectPath(tokenIn, intermediate, amountIn);
if (!firstHop) return null;
// 检查第二跳: intermediate → tokenOut
const secondHop = await this.checkDirectPath(intermediate, tokenOut, firstHop.outputAmount);
if (!secondHop) return null;
return {
path: [tokenIn, intermediate, tokenOut],
fees: [firstHop.fees[0], secondHop.fees[0]],
outputAmount: secondHop.outputAmount,
hops: 2
};
}
calculateOutput(amountIn, reserves, fee, tokenIn, tokenOut) {
// 简化的输出计算(实际应使用JAMMLibrary的逻辑)
const [reserveIn, reserveOut] = tokenIn < tokenOut
? [reserves.reserve0, reserves.reserve1]
: [reserves.reserve1, reserves.reserve0];
const amountInWithFee = amountIn.mul(10000 - fee);
const numerator = amountInWithFee.mul(reserveOut);
const denominator = reserveIn.mul(10000).add(amountInWithFee);
return numerator.div(denominator);
}
}
// 使用示例
const pathFinder = new PathFinder(FACTORY_ADDRESS, provider);
const bestPath = await pathFinder.findBestPath(
TOKEN_A_ADDRESS,
TOKEN_B_ADDRESS,
ethers.utils.parseEther("100")
);
console.log("最优路径:", bestPath);