skip to Main Content

I’m trying to execute a swap using Uniswap V2 SDK in a Node.js environment.
However, when I run the code below, I receive the following error:
"Warning! Error encountered during contract execution [execution reverted]"

async function createPair() {
  const pairAddress = Pair.getAddress(TOKEN, WETH9[TOKEN.chainId]);

  const pairContract = new ethers.Contract(pairAddress, UniswapV2PoolAbi, provider);

  const reserves = await pairContract['getReserves']();
  const [reserve0, reserve1] = reserves;

  const reserve0Parsed = BigInt(reserve0.toString()).toString();
  const reserve1Parsed = BigInt(reserve1.toString()).toString();

  const tokens = [TOKEN, WETH9[TOKEN.chainId]];
  const [token0, token1] = tokens[0].sortsBefore(tokens[1]) ? tokens : [tokens[1], tokens[0]];

  const pair = new Pair(
    CurrencyAmount.fromRawAmount(token0, reserve0Parsed),
    CurrencyAmount.fromRawAmount(token1, reserve1Parsed)
  );

  return pair;
}

async function swap() {
  const amountIn = ethers.parseEther('0.00001').toString();
  const slippageTolerance = new Percent('50', '10000');
  const to = WALLET_ADDRESS;
  const signer = new ethers.Wallet(WALLET_SECRET);
  const account = signer.connect(provider);
  const command = '0x08';
  const deadline = 2 * 10 ** 10;
  const fromEoa = true;

  const uniswap = new ethers.Contract(
    swapRouterAddress,
    [
      'function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external payable returns (bytes[] memory outputs)',
    ],
    account
  );

  const pair = await createPair();
  const route = new Route([pair], WETH9[TOKEN.chainId], TOKEN);
  const trade = new Trade(
    route,
    CurrencyAmount.fromRawAmount(WETH9[TOKEN.chainId], amountIn),
    TradeType.EXACT_INPUT
  );

  const amountOutMin = trade.minimumAmountOut(slippageTolerance).toExact();

  const amoutOut = ethers.parseEther(amountOutMin);

  const pathData = ethers.solidityPacked(
    ['address', 'address'],
    [WETH9[ChainId.BASE].address, TOKEN.address]
  );

  const v2Calldata = ethers.AbiCoder.defaultAbiCoder().encode(
    ['address', 'uint256', 'uint256', 'bytes', 'bool'],
    [to, amountIn, amoutOut, pathData, fromEoa]
  );

  const tx = await uniswap.execute(command, [v2Calldata], deadline, {
    value: amountIn,
    gasPrice: ethers.parseUnits('0.15', 'gwei'),
    gasLimit: 100000,
    chainId: ChainId.BASE,
    from: WALLET_ADDRESS,
  });

  console.log(`Transaction hash: ${tx.hash}`);
  const receipt = await tx.wait();

  console.log(`Transaction was mined in block ${receipt.blockNumber}`);
}

*/

Here’s a brief overview of what the code does:

  1. Imports necessary Uniswap V2 SDK components and ethers.js.
  2. Sets up provider with a QuickNode HTTP endpoint.
  3. Defines wallet address and secret.
  4. Creates a swapRouterAddress and a TOKEN.
  5. Defines a swap function that executes a swap using Uniswap V2.
  6. Inside the swap function:
  • a. Sets up amountIn, slippage tolerance, recipient address, and signer.
  • b. Creates a Uniswap contract instance.
  • c. Calls createPair() to create a Uniswap pair.
  • d. Calculates trade details and encodes calldata.
  • e. Executes the swap with Uniswap’s execute() function.

I suspect the issue might be related to how I’m encoding the data or setting up
the transaction. Can someone help me understand why I’m getting this error
and how I can resolve it?

Also check some of my transactions:
https://basescan.org/tx/0x5a4ccdf8476eac2b41e00927cae6cb5817cff4acfb1c4746244ebd3d22784e9e
tenderly analyzer

Thanks!


Updated question:
Here is my current code :

async function swap() {
const swapRouterAddress = '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad';
const TOKEN = new Token(ChainId.BASE, '0xBC45647eA894030a4E9801Ec03479739FA2485F0', 18);
const amountIn = ethers.parseEther('0.00001').toString();
  const to = WALLET_ADDRESS;
  const signer = new ethers.Wallet(WALLET_SECRET);
  const account = signer.connect(provider);
  const command = '0x0b08';
  const deadline = 2 * 10 ** 10;
  const fromEoa = false;
  const FEE = 500;

  const uniswap = new ethers.Contract(
    swapRouterAddress,
    [
      'function execute(bytes calldata commands, bytes[] calldata inputs) external payable returns (bytes[] memory outputs)',
    ],
    account
  );

  const pathData = ethers.AbiCoder.defaultAbiCoder().encode(
    ['address', 'address'],
    [WETH9[ChainId.BASE].address, TOKEN.address]
  );

  const wrap_calldata = ethers.AbiCoder.defaultAbiCoder().encode(
    ['address', 'uint256'],
    [swapRouterAddress, amountIn]
  );

  const v2Calldata = ethers.AbiCoder.defaultAbiCoder().encode(
    ['address', 'uint256', 'uint256', 'bytes', 'bool'],
    [to, amountIn, 0, pathData, fromEoa]
  );

  const tx = await uniswap.execute(command, [wrap_calldata, v2Calldata], {
    value: amountIn,
    gasPrice: ethers.parseUnits('0.15', 'gwei'),
    gasLimit: 150000,
    chainId: ChainId.BASE,
    from: WALLET_ADDRESS,
  });

  console.log(`Transaction hash: ${tx.hash}`);
  const receipt = await tx.wait();

  console.log(`Transaction was mined in block ${receipt.blockNumber}`);
}

Also I’m getting the error in the path as Maka mentioned in his answer :

https://basescan.org/tx/0xb661d0eb3fb7d4d6580424ce9c2462cdfa7735f256332c422187506f57a700f7

enter image description here

2

Answers


  1. Chosen as BEST ANSWER

    After some adjustments to the code, I managed to resolve the issue with the execution error. Here's the updated swap() function that works correctly:

    async function swap() {
      const swapRouterAddress = '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad';
      const TOKEN = new Token(ChainId.BASE, '0xBC45647eA894030a4E9801Ec03479739FA2485F0', 18);
      const amountIn = ethers.parseEther('0.00001').toString();
      const to = WALLET_ADDRESS;
      const signer = new ethers.Wallet(WALLET_SECRET);
      const account = signer.connect(provider);
      const command = '0x0b08';
      const deadline = 2 * 10 ** 10;
      const fromEoa = false;
      const FEE = 500;
    
      const uniswap = new ethers.Contract(
        swapRouterAddress,
        [
          'function execute(bytes calldata commands, bytes[] calldata inputs) external payable returns (bytes[] memory outputs)',
        ],
        account
      );
    
      const pathData = ethers.AbiCoder.defaultAbiCoder().encode(
        ['address', 'address'],
        [WETH9[ChainId.BASE].address, TOKEN.address]
      );
    
      const wrap_calldata = ethers.AbiCoder.defaultAbiCoder().encode(
        ['address', 'uint256'],
        [swapRouterAddress, amountIn]
      );
    
      const v2Calldata = ethers.AbiCoder.defaultAbiCoder().encode(
        ['address', 'uint256', 'uint256', 'address[]', 'bool'],
        [to, amountIn, 0, [WETH9[ChainId.BASE].address, TOKEN.address], fromEoa]
      );
    
      const tx = await uniswap.execute(command, [wrap_calldata, v2Calldata], {
        value: amountIn,
        gasPrice: ethers.parseUnits('0.15', 'gwei'),
        gasLimit: 200000,
        chainId: ChainId.BASE,
        from: WALLET_ADDRESS,
      });
    
      console.log(`Transaction hash: ${tx.hash}`);
      const receipt = await tx.wait();
    
      console.log(`Transaction was mined in block ${receipt.blockNumber}`);
    }
    

  2. The issue in the transaction you posted is it was trying to do a v3 swap, as you had set 0x00 for the command:

    v3SwapExactInput(map(recipient), amountIn, amountOutMin, path, payer);
    

    As the path did not have the needed values to generate an address for a pool that exists the transaction was failing with computePoolAddress:

    IUniswapV3Pool(computePoolAddress(tokenIn, tokenOut, fee))
    

    The code you posted has 08 as the command which is for a v2 swap, while in the most recent example listed at your address, you are using commands 0b00 and so failing at the same stage.

    In the second to last failure of the execute function you use 0b08 which attempts a v2 call. But fails at:

    (block.timestamp > allowed.expiration) revert AllowanceExpired(allowed.expiration);
    

    Appears you must have set it to take from wallet because it asks for a permit.
    A solution to get passed that stage is to set payer to false, as you have transferred to and wrapped eth at the contract.

    If I toggle the bit in that byte

    0x0000000000000000000000001991ac5419991ebd2c11783db5087644b125c912000000000000000000000000000000000000000000000000000009184e72a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000004200000000000000000000000000000000000006000000000000000000000000bc45647ea894030a4e9801ec03479739fa2485f0
    

    It gets further, failing at tokenOut.balanceOf:

    uint256 balanceBefore = tokenOut.balanceOf(recipient);
    

    The token is decoded as the zero address, and it cannot call balanceOf on that address as it does not have an interface for that function (or any code at all). Meaning the calldata around the path must be malformed.

    If I parrot the offset from successful transactions:

    0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000f71635b554633d00000000000000000000000000000000000000000000011c2867721c0a0702db00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000004200000000000000000000000000000000000006000000000000000000000000bc45647ea894030a4e9801ec03479739fa2485f0
    

    We get to fail with out of gas.
    Raising the gas, we find success:

    enter image description here

    If you have a failed transaction from the calldata generated via the exact code you posted please update with that, then I will update the answer to account for how you are encoding etc.

    Hopefully this can help.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search