JavaScript – Decode Uniswap Universal Router’s Execute Function Parameters with Ethers.js

etherjsethers.jsjavascriptuniswapuniswapv3

I used the method described in this thread (Decode Uniswap Universal Router transaction in ethers.js) and decoded most of the data of a transaction at this link: https://arbiscan.io/tx/0xfd288567b1a9c827a260b28ff0b6b183d256c60881f75c7d86d50a501593c6fd

Data: 0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000063e1579200000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000b2c73eba00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b82af49447d8a07e3bd95bd0d56f35241523fbab1002710602eb0d99a5e3e76d1510372c4d2020e12eaea8a000000000000000000000000000000000000000000

ExecuteWithCommandsAndInputs(ExecuteWithCommandsAndInputsCall { commands: Bytes(0x0b00), inputs: [Bytes(0x0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000002386f26fc10000), Bytes(0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000b2c73eba00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b82af49447d8a07e3bd95bd0d56f35241523fbab1002710602eb0d99a5e3e76d1510372c4d2020e12eaea8a000000000000000000000000000000000000000000)], deadline: 1675712402 })

The decoded data is as follows:

  • 0x0b00 = first argument of the execute function (commands byte)

  • 0x0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000002386f26fc10000 ([2, 10000000000000000]) = first input of the second argument of the execute function. This matches the data required for "WRAP_ETH"

  • 0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000b2c73eba00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b82af49447d8a07e3bd95bd0d56f35241523fbab1002710602eb0d99a5e3e76d1510372c4d2020e12eaea8a000000000000000000000000000000000000000000 = this part is giving me headaches. Based on the Uniswap Universal Router technical reference (https://docs.uniswap.org/contracts/universal-router/technical-reference), this should have 5 inputs (address, uint256, uint256, bytes, bool). However, I split the data into 64 characters long, and there are a total of 8 lines. Does that mean there are 8 inputs instead of 5?

Best Answer

You are correct that the V3_SWAP_EXACT_IN itself takes in 5 parameters.

But the 4th parameter(path) is a bytes array, and they also include fees and a number of offsets to properly build the path. You can check out more in their V3Path.sol smart contract and V3SwapRouter.sol.

Judging by the code snippet you included you managed to decode the universal function with ethers interface. I recommend you do the same with the V3 function too like so:

const abiCoder = new AbiCoder();
decoded = abiCoder.decode(["address", "uint256", "uint256", "bytes", "bool"], inputForFunction);

Using this you can get the corresponding parameter to each input for the V3_SWAP_EXACT_IN function. Basically you create a mini interface with just the function you need to decode. As long as you know the inputs it should give the correct results.

Running the code snippet should result in something like this:

[
  '0x0000000000000000000000000000000000000001',
  BigNumber { _hex: '0x06ccf946da6cf708', _isBigNumber: true },
  BigNumber { _hex: '0x04c72ae4b04a0a42db7f', _isBigNumber: true },
  '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc200271000c83aecc790e8a4453e5dd3b0b4b3680501a7a7',
  false
]

Now there are actually 5 inputs here (recipient,input,minOut,path,fromowner)

Next challenge would be decoding the path itself, since it is still in the incorrect format. If you check out the V3Path.sol you can see different offsets for address, fees you have to account for those when extracting the addresses from the path.

I use the following function for my application:

function extractPathFromV3(fullPath, reverse = false) {
    const fullPathWithoutHexSymbol = fullPath.substring(2);
    let path = [];
    let currentAddress = "";
    for (let i = 0; i < fullPathWithoutHexSymbol.length; i++) {
        currentAddress += fullPathWithoutHexSymbol[i];
        if (currentAddress.length === 40) {
            path.push('0x' + currentAddress);
            i = i + 6;
            currentAddress = "";
        }
    }
    if (reverse) {
        return path.reverse();
    }
    return path;
}

It takes each address from the path, excludes the fee(skipping 6 bytes) and can reverse the path since V3_SWAP_EXACT_OUT path is reversed by default so that might be needed too.

You can check out my full implementation here if you are interested uniswap-universal-decoder

Hope it clarifies it a bit more.

Related Topic