What Uniswap Universal Router commands are actually used?
Published: 2023-12-20 11:08:13

## Context

There are more than [30 functions](https://github.com/Uniswap/universal-router#how-the-command-byte-is-structured) implemented in the Universal Router (UR) at the moment, in the repository main branch.

As the author of the [Python Uniswap Universal Router SDK](https://github.com/Elnaril/uniswap-universal-router-decoder), I always wonder what should be the next one(s) this library should support.

Until now, I've added the most obvious functions:

- the ones that allow to swap ERC-20 tokens:
  - `V3_SWAP_EXACT_IN`
  - `V3_SWAP_EXACT_OUT`
  - `V2_SWAP_EXACT_IN`
  - `V2_SWAP_EXACT_OUT`
- those often needed before or after:
  - `WRAP_ETH`
  - `UNWRAP_WETH`
  - `PERMIT2_PERMIT`
- and a couple ones that allow more possibilities:
  - `SWEEP`
  - `PAY_PORTION`

But for the next supported functions, I decided to list those that are actually used, and order them from the most to the least called.

## Methodology

To reach this goal, I wrote a simple Python script that looks into all blocks included in Mainnet during November 2023, gets all transactions sent to the Universal Router, discards those with a too small input field, and decodes them. And counts how many times each command (function) is used.

This script can be found [here](https://gist.github.com/Elnaril/e6d51bcc43c81d5cbd9a4a494bcb2876), so the results can be reproduced. Just change the RPC providers.

No fancy optimizations were implemented in the script apart from good ol' `asyncio` and it does not check whether the transactions were rejected by the EVM or not, to avoid requesting the receipts. This is a bit annoying in terms of clean data, but allowed me to get the results in less than half a day.

Another limitation with this method: it does not take into account transactions using the UR through custom contracts.

## Results

The scripts scanned:
- `214 307` blocks (from `18 473 543` to `18 687 850`)
- `2 453 214` transactions sent to the UR
- `5 435 322` commands

And the raw results is given in the below dict, with the decimal commands as keys and the number of calls as values:

```
Results: {11: 1362528, 8: 1886773, 9: 97389, 1: 52226, 12: 856319, 10: 593542, 0: 494207, 5: 8346, 4: 36076, 6: 47881, 16: 25, 25: 2, 14: 8}
```
There were 32 transactions that could not be decoded, either because they are wrongly formatted and rejected by the EVM, or their format does not respect the specifications (as I understand them) but still were accepted by the EVM (more on them in another post). Anyway they are not statistically relevant, so let's just disregard them for now.

The following table lists the results with the function names, ordered by counts (desc) and whether or not it is already supported by the codec:

| Dec - Hex Code | Name | Counts | Supported
| -------------- | ---- | ------ | ---------
| 8 - 0x08 | V2_SWAP_EXACT_IN | 1886773 | ✅
| 11 - 0x0b | WRAP_ETH | 1362528 | ✅
| 12 - 0x0c | UNWRAP_WETH | 856319 | ✅
| 10 - 0x0a | PERMIT2_PERMIT | 593542 | ✅
| 0 - 0x00 | V3_SWAP_EXACT_IN | 494207 | ✅
| 9 - 0x09 | V2_SWAP_EXACT_OUT | 97389 | ✅
| 1 - 0x01 | V3_SWAP_EXACT_OUT | 52226 | ✅
| 6 - 0x06 | PAY_PORTION | 47881 | ✅
| 4 - 0x04 | SWEEP | 36076 | ✅
| 5 - 0x05 | TRANSFER | 8346 | ❌
| 16 - 0x10 | SEAPORT_V1_5 | 25 | ❌
| 14 - 0x0e | placeholder | 8 | N/A
| 25 - 0x19 | SUDOSWAP | 2 | ❌


As a Pie Chart:

![Usage Distribution of the Uniswap Universal Router Commands](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vyyzjr7r9hd07rvzpqdw.png)

So, basically, most of the used commands (99.8% of the calls) are already supported by the [Python UR SDK](https://github.com/Elnaril/uniswap-universal-router-decoder). The only one really missing is `TRANSFER` with 8346 counts (< 0.2%), the others are anecdotal:
- `SEAPORT_V1_5` with 25 counts
- a placeholder with no function yet (8 counts)
- `SUDOSWAP` with 2 counts

## Other interesting results

1/ The 4 swap functions (`V2_SWAP_EXACT_IN`, `V3_SWAP_EXACT_IN`, `V2_SWAP_EXACT_OUT` and `V3_SWAP_EXACT_OUT`) were called `2 530 595` times:
- `1 984 162` (78.4%) for a V2 pool, most of it (74.6%) through the `V2_SWAP_EXACT_IN` function
- `546 433` (21.6%) for a V3 pool

2/ The second most used function is `WRAP_ETH` with `1 362 528` calls, which is 53.8% of all swap commands. Knowing that several swap commands can be chained after a single `WRAP_ETH`, this suggests that ETH is largely used to initiate a swap.

3/ There are 2.2 commands/functions per transaction on average.

4/ Still on average, each block contains 11.4 transactions sent to the Universal Router!

## Conclusion

As expected, the functions related to ERC-20 DeFi are extensively used. But, basically, nothing else is used apart the `TRANSFER` function: no batch ones, no permit2 transfers, no NFTs, ...
So, I guess I'll implement `TRANSFER` sooner or later, but what about the other ones?
Do you think there is an interest in them? If, yes which ones and why are they not already used?