Не удается использовать Uniswap V3 SwapRouter для многоскачковых свопов, SwapRouter.exactInput(params) выдает «UNPREDICTABLE_GAS_LIMIT»

Я пытаюсь реализовать обмен с новыми контрактами Uniswap V3. Я использую контракт Quoter для получения котировок и SwapRouter для создания свопов. Если я использую методы для прямого обмена (когда токены имеют пулы), например -

      ethersProvider = new ethers.providers.Web3Provider(web3.currentProvider, 137);

uniSwapQuoter = new ethers.Contract(uniSwapQuoterAddress, QuoterAbi.abi, ethersProvider);

uniSwapRouterV3 = new ethers.Contract(uniSwapRouterAddress, RouterAbi.abi, 
ethersProvider.getSigner());

uniSwapQuoter.callStatic.quoteExactInputSingle(.....) 
uniSwapQuoter.callStatic.quoteExactOutputSingle(.....)
uniSwapRouterV3.exactInputSingle(params)

все работает нормально, но когда я пытаюсь использовать многоскачковые кавычки и многоскачковые свопы, если не получается с

      
    "reason": "cannot estimate gas; transaction may fail or may require manual gas limit",
    "code": "UNPREDICTABLE_GAS_LIMIT",
    "error": {
        "code": -32000,
        "message": "execution reverted"
    },
    "method": "estimateGas",
    "transaction": {
        "from": "0x532d647481c20f4422A8331339D76b25cA569959",
        "to": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
        "data": "0xc04b8d59000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000002a6b82b6dd3f38eeb63a35f2f503b9398f02d9bb0000000000000000000000000000000000000000000000000000000861c468000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000422791bca1f2de4661ed88a30c99a7a9449aa841740005007ceb23fd6bc0add59e62ac25578270cff1b9f619003000c26d47d5c33ac71ac5cf9f776d63ba292a4f7842000000000000000000000000000000000000000000000000000000000000",
        "accessList": null
    }

для кодирования параметров я использую пример uniswap из тестов:

      function encodePath(tokenAddresses, fees) {
  const FEE_SIZE = 3

  if (path.length != fees.length + 1) {
    throw new Error('path/fee lengths do not match')
  }

  let encoded = '0x'
  for (let i = 0; i < fees.length; i++) {
    // 20 byte encoding of the address
    encoded += path[i].slice(2)
    // 3 byte encoding of the fee
    encoded += fees[i].toString(16).padStart(2 * FEE_SIZE, '0')
  }
  // encode the final token
  encoded += path[path.length - 1].slice(2)

  return encoded.toLowerCase()
}

и, наконец, мой пример кода, который я делаю для кавычек:

          const routeAndFees = await getAddressPath(path);
    const encodedPath = await encodePath(routeAndFees.path, routeAndFees.fees);
    const usdcWithDecimals = parseFloat(usdcAmount) * 1000000
    const tokenDecimals = path[path.length - 1].tokenOut.decimals;

    try {
        const amountOut = await uniSwapQuoter.callStatic.quoteExactInput(encodedPath, usdcWithDecimals.toString());
        console.log("Token amount out:", parseFloat(amountOut) / (10 ** tokenDecimals));
        return {
            tokenOut: parseFloat(amountOut) / (10 ** tokenDecimals),
            usdcIn: parseFloat(usdcAmount)
        };
    } catch (e) {
        console.log(e);
        return e;
    }
}

и обмен:

      async function multiSwap(path, userAddress, usdcAmount) {
    const usdcWithDecimals = parseFloat(usdcAmount) * 1000000
    const routeAndFees = await getAddressPath(path);
    const encodedPath = await encodePath(routeAndFees.path, routeAndFees.fees);

    const params = {
        path: encodedPath,
        recipient: userAddress,
        deadline: Math.floor(Date.now() / 1000) + 900,
        amountIn: usdcWithDecimals.toString(),
        amountOutMinimum: 0,
    }
    try {
        return  await uniSwapRouterV3.exactInput(params);
    } catch (e) {
        console.log(e);
        return e;
    }
}

Путь [адрес, плата, адрес, плата, адрес], как и должно быть, я не уверен в кодировке этого, но не нашел другого примера. На самом деле не нашел ни одного примера выполнения многоскачкового свопа uniswap v3, даже в UniDocs есть пример торговли и своп с одним пулом ... Может ли кто-нибудь указать, что я мог сделать здесь неправильно? Та же ошибка в кавычках и при замене :/

Я тестирую в Polygon Mainnet, и я могу поменять тот же путь непосредственно в uniswap, но он терпит неудачу, когда я запускаю скрипт...

1 ответ

Вы должны хешировать значение комиссии. Вместо 0 добавьте 6. Это должно сработать для вас:

       async function encodePath(path, fees, exactInput) {
    const FEE_SIZE = 6
    if (path.length !== fees.length + 1) {
        throw new Error('path/fee lengths do not match')
    }
    if (!exactInput) {
        path = path.reverse();
        fees = fees.reverse();
    }

    let encoded = '0x'
    for (let i = 0; i < fees.length; i++) {
        encoded += path[i].slice(2)
        let fee = web3.utils.toHex(parseFloat(fees[i])).slice(2).toString();
        encoded += fee.padStart(FEE_SIZE, '0');
    }
    encoded += path[path.length - 1].slice(2)
    return encoded    
}
Другие вопросы по тегам