Uniswap / universal-router

Uniswap's Universal Router for NFT and ERC20 swapping
GNU General Public License v3.0
410 stars 210 forks source link

The correct way to encode transaction data to UniversalRouter #228

Closed Neronjust2017 closed 1 year ago

Neronjust2017 commented 1 year ago

Hi, because transactions to the UniversalRouter all go through the UniversalRouter.execute functions, the transaction data should be encoded using the ABI of function UniversalRouter.execute. My transaction is a swap from 0.005 WETH to some USDC, and its method bytecode is "0x0b08". I have two problems: 1) when I encode the first command (0b) inputs, using the following code:

let AmountIn = ethers.BigNumber.from("5000000000000000");
  inputs.push(abiCoder.encode(
    ["address", "uint256"],
    ["0x0000000000000000000000000000000000000000000000000000000000000002", AmountIn]));

there is an error:

reason: 'invalid address (argument="address", value="0x0000000000000000000000000000000000000000000000000000000000000002", code=INVALID_ARGUMENT, version=address/5.7.0)',
  code: 'INVALID_ARGUMENT',
  argument: null,
  value: '0x0000000000000000000000000000000000000000000000000000000000000002'

2) When I encode the second command (08), I encode "address" and ["uint256", "uint256", "address[]", "bool"] respectively and put them together:

inputs.push(
    "0x0000000000000000000000000000000000000000000000000000000000000001" +
    abiCoder.encode(
      ["uint256", "uint256", "address[]", "bool"],
      [AmountIn, MinRecv, [WETH, USDC], false]
    ).replace("0x", "")
  )
  );

There is another problem that it can not be decoded back:

  const abiCoder = ethers.utils.defaultAbiCoder;
  const d1 = "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000011c37937e08000000000000000000000000000000000000000000000000000001595eabc586b42000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000b4fbf271143f4fbf7b91a5ded31805e42b2208d60000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984";
  const r1 = abiCoder.decode(["address", "uint256", "uint256", "address[]", "bool"], d1);
  console.log(r1)

The decoded addresses are empty:

[
  '0x0000000000000000000000000000000000000001',
  BigNumber { _hex: '0x11c37937e08000', _isBigNumber: true },
  BigNumber { _hex: '0x1595eabc586b42', _isBigNumber: true },
  [],
  false
]

I need your help. and what's the right way to encode these data? Thanks a lot!

ewilz commented 1 year ago

Hi, you are free to use universal-router-sdk for encoding, but this also means using v2/v3 sdks for forming trade routes which could take some learning...

You can also use these test helpers here we use to encode: https://github.com/Uniswap/universal-router/blob/main/test/integration-tests/shared/planner.ts and here's an example using this library: https://github.com/Uniswap/universal-router/blob/main/test/integration-tests/Uniswap.test.ts#L92

Neronjust2017 commented 1 year ago

Thanks! That helps a lot. I found these test helpers use the defaultAbiCoder for encoding, just like I do. But by browsing the code you gave, I found the reason for the first error "INVALID_ARGUMENT" is that "0x0000000000000000000000000000000000000000000000000000000000000001" is not a 42-character hexadecimal address.

ewilz commented 1 year ago

thanks, closing for now