Skip to content

Commit

Permalink
Universal Router Documentation (#517)
Browse files Browse the repository at this point in the history
Co-authored-by: Adrian Kant <adrian.kant@uniswap.org>
  • Loading branch information
hensha256 and adjkant authored Dec 13, 2022
1 parent 2129b01 commit 9fa96df
Show file tree
Hide file tree
Showing 6 changed files with 302 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/contracts/permit2/_category_.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"label": "Permit2",
"position": 2,
"position": 3,
"collapsed": true
}

19 changes: 19 additions & 0 deletions docs/contracts/universal-router/01-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
id: overview
title: Overview
sidebar_position: 1
---

The `UniversalRouter` is an ETH, ERC20, and NFT swap router, that can aggregate trades across protocols to give users access highly-flexible and personalised transactions. The contract is unowned, and is not upgradeable.

The flexible command style allows us to provide users with:

- Splitting and interleaving of Uniswap trades
- Purchases of NFTs across 8 marketplaces
- Partial fills of trades
- Wrapping and Unwrapping of ETH
- Time-bound, signature controlled token approvals using [Permit2](../permit2/overview.md)

Transactions are encoded using a string of commands, allowing users to have maximum flexibility over what they want to perform. With all of these features available in a single transaction, the possibilities available to users are endless.

*Note: The `UniversalRouter` uses `Permit2` to remove the need for token approvals being provided directly to the `UniversalRouter`. The `Permit2` documentation can be found [here](../permit2/overview.md).*
274 changes: 274 additions & 0 deletions docs/contracts/universal-router/02-technical-reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
---
id: technical-reference
title: Technical Reference
sidebar_position: 1
---

## Functions

Transactions to the `UniversalRouter` all go through the `UniversalRouter.execute` functions:

- `execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline)`
- `execute(bytes calldata commands, bytes[] calldata inputs)`

The first of these functions adds the functionality to allow transactions to have a transaction deadline. If the `block.timestamp` is after the `deadline` provided the transaction will revert. After that check, the 2 functions otherwise execute identically.

The `execute` functions work like a simplified VM - they take in a list of commands, and a list of inputs for the commands and execute them in the order specified.

## Command Structure

The first parameter for the function (`bytes calldata commands`) is a list of commands for the contract to execute, in the order they should be executed. Each command is encoded in 1 byte, containing the following split of 8 bits:

| 0 | 1 2 | 3 4 5 6 7 |
| :- | :-- | :-------- |
| f | r | command |

### `f`
A single bit flag, that signals whether or not the command should be allowed to revert without the whole transaction failing.
- If `f` is `0` aka `false` and the command reverts, then the entire transaction will revert and none of the commands will be executed.
- If `f` is `1` aka `true` and the command reverts, then the transaction will continue, allowing us to achieve partial fills. If using this flag, be careful to include further commands that will remove any funds that could be left unused in the `UniversalRouter` contract.

### `r`
2 unused bytes, reserved for future use. Leaving these 2 bits as `0` will save gas, but any value passed into the contract will be ignored. Later versions of the `UniversalRouter` will likely expand the 5 bits used for `command` to use at least 1 of these bits.

### `command`
A 5 bit unique identifier for the command that should be carried out. The values of these commands can be found within [Commands.sol](https://github.com/Uniswap/universal-router/blob/main/contracts/libraries/Commands.sol), or can be viewed in the table below.

The command types that are not defined do not have an assigned command at this moment in time. Providing one of these identifiers will cause the transaction to revert with `InvalidCommandType`.

A complete list of commands can be found in the table below:

| Command | Value |
| :------ | :--------------------------------------------------------------------------------------- |
| `0x00` | [`V3_SWAP_EXACT_IN`](./02-technical-reference.md#v3_swap_exact_in) |
| `0x01` | [`V3_SWAP_EXACT_OUT`](./02-technical-reference.md#v3_swap_exact_out) |
| `0x02` | [`PERMIT2_TRANSFER_FROM`](./02-technical-reference.md#permit2_transfer_from) |
| `0x03` | [`PERMIT2_PERMIT_BATCH`](./02-technical-reference.md#permit2_permit_batch) |
| `0x04` | [`SWEEP`](./02-technical-reference.md#sweep) |
| `0x05` | [`TRANSFER`](./02-technical-reference.md#transfer) |
| `0x06` | [`PAY_PORTION`](./02-technical-reference.md#pay_portion) |
| `0x07` | |
| `0x08` | [`V2_SWAP_EXACT_IN`](./02-technical-reference.md#v2_swap_exact_in) |
| `0x09` | [`V2_SWAP_EXACT_OUT`](./02-technical-reference.md#v2_swap_exact_out) |
| `0x0a` | [`PERMIT2_PERMIT`](./02-technical-reference.md#permit2_permit) |
| `0x0b` | [`WRAP_ETH`](./02-technical-reference.md#wrap_eth) |
| `0x0c` | [`UNWRAP_WETH`](./02-technical-reference.md#unwrap_eth) |
| `0x0d` | [`PERMIT2_TRANSFER_FROM_BATCH`](./02-technical-reference.md#permit2_transfer_from_batch) |
| `0x0e` | |
| `0x0f` | |
| `0x10` | [`SEAPORT`](./02-technical-reference.md#seaport) |
| `0x11` | [`LOOKS_RARE_721`](./02-technical-reference.md#looks_rare_721) |
| `0x12` | [`NFTX`](./02-technical-reference.md#nftx) |
| `0x13` | [`CRYPTOPUNKS`](./02-technical-reference.md#cryptopunks) |
| `0x14` | [`LOOKS_RARE_1155`](./02-technical-reference.md#looks_rare_1155) |
| `0x15` | [`OWNER_CHECK_721`](./02-technical-reference.md#owner_check_721) |
| `0x16` | [`OWNER_CHECK_1155`](./02-technical-reference.md#owner_check_1155) |
| `0x17` | [`SWEEP_ERC721`](./02-technical-reference.md#sweep_erc721) |
| `0x18` | [`X2Y2_721`](./02-technical-reference.md#x2y2_721) |
| `0x19` | [`SUDOSWAP`](./02-technical-reference.md#sudoswap) |
| `0x1a` | [`NFT20`](./02-technical-reference.md#nft20) |
| `0x1b` | [`X2Y2_1155`](./02-technical-reference.md#x2y2_1155) |
| `0x1c` | [`FOUNDATION`](./02-technical-reference.md#foundation) |
| `0x1d` | [`SWEEP_ERC1155`](./02-technical-reference.md#sweep_erc1155) |
| `0x1e` | |
| `0x1f` | |

## Command Inputs

The second parameter for the function is an array of bytes strings. Each element in the array is the abi-encoded input that will be used for the respective command.

`commands[i]` is the command that will use `inputs[i]` as its encoded input parameters.

The router uses the command type to know how to decode the encoded input parameters - depending on the command chosen, the required inputs is different.

The input parameters required for each command are outlined below:

### `V3_SWAP_EXACT_IN`

- `address` The recipient of the output of the trade
- `uint256` The amount of input tokens for the trade
- `uint256` The minimum amount of output tokens the user wants
- `bytes` The UniswapV3 encoded path to trade along
- `bool` A flag for whether the input tokens should come from the `msg.sender` (through Permit2) or whether the funds are already in the `UniversalRouter`

### `V3_SWAP_EXACT_OUT`

- `address` The recipient of the output of the trade
- `uint256` The amount of output tokens to receive
- `uint256` The maximum number of input tokens that should be spent
- `bytes` The UniswapV3 encoded path to trade along
- `bool` A flag for whether the input tokens should come from the `msg.sender` (through Permit2) or whether the funds are already in the `UniversalRouter`

### `PERMIT2_TRANSFER_FROM`

- `address` The token to fetch from Permit2
- `address` The recipient of the tokens fetched
- `uint256` The amount of token to fetch

The individual that the tokens are fetched from is always the `msg.sender` of the transaction

### `PERMIT2_PERMIT_BATCH`

- `IAllowanceTransfer.PermitBatch` A `PermitBatch` struct outlining all of the Permit2 permits to execute.
- `bytes` The signature to provide to Permit2

The individual that signed the permits must be the `msg.sender` of the transaction

### `SWEEP`

- `address` The ERC20 token to sweep (or Constants.ETH for ETH)
- `address` The recipient of the sweep
- `uint256` The minimum required tokens to receive from the sweep

### `TRANSFER`

- `address` The ERC20 token to transfer (or Constants.ETH for ETH)
- `address` The recipient of the transfer
- `uint256` The amount to transfer

### `PAY_PORTION`

- `address` The ERC20 token to transfer (or Constants.ETH for ETH)
- `address` The recipient of the transfer
- `uint256` In basis points, the percentage of the contract’s balance to transfer

### `V2_SWAP_EXACT_IN`

- `address` The recipient of the output of the trade
- `uint256` The amount of input tokens for the trade
- `uint256` The minimum amount of output tokens the user wants
- `address[]` The UniswapV2 token path to trade along
- `bool` A flag for whether the input tokens should come from the `msg.sender` (through Permit2) or whether the funds are already in the `UniversalRouter`

### `V2_SWAP_EXACT_OUT`

- `address` The recipient of the output of the trade
- `uint256` The amount of output tokens to receive
- `uint256` The maximum number of input tokens that should be spent
- `address[]` The UniswapV2 token path to trade along
- `bool` A flag for whether the input tokens should come from the `msg.sender` (through Permit2) or whether the funds are already in the `UniversalRouter`

### `PERMIT2_PERMIT`

- `IAllowanceTransfer.PermitSingle` A `PermitSingle` struct outlining the Permit2 permit to execute
- `bytes` The signature to provide to Permit2

The individual that signed the permit must be the `msg.sender` of the transaction

### `WRAP_ETH`

- `address` The recipient of the WETH
- `uint256` The amount of ETH to wrap

### `UNWRAP_ETH`

- `address` The recipient of the ETH
- `uint256` The minimum required ETH to receive from the unwrapping

### `PERMIT2_TRANSFER_FROM_BATCH`

- `IAllowanceTransfer.AllowanceTransferDetails[]` An array of `AllowanceTransferDetails` structs that each describe a Permit2 transfer to perform

### `SEAPORT`

- `uint256` The ETH value to forward to the Seaport contract
- `bytes` The calldata to use to call the Seaport contract

### `LOOKS_RARE_721`

- `uint256` The ETH value to forward to the LooksRare contract
- `bytes` The calldata to use to call the LooksRare contract
- `address` The recipient of the ERC721
- `address` The ERC721 token address
- `uint256` The ID of the ERC721

### `NFTX`

- `uint256` The ETH value to forward to the NFTX contract
- `bytes` The calldata to use to call the NFTX contract

### `CRYPTOPUNKS`

- `uint256` The PunkID to purchase
- `address` The recipient for the cryptopunk
- `uint256` The ETH value to forward to the Cryptopunks contract

### `LOOKS_RARE_1155`

- `uint256` The ETH value to forward to the LooksRare contract
- `bytes` The calldata to use to call the LooksRare contract
- `address` The recipient of the ERC1155
- `address` The ERC1155 token address
- `uint256` The ID of the ERC1155
- `uint256` The amount of the ERC1155 to transfer

### `OWNER_CHECK_721`

- `address` The required owner of the ERC721
- `address` The ERC721 token address
- `uint256` The ID of the ERC721

### `OWNER_CHECK_1155`

- `address` The required owner of the ERC1155
- `address` The ERC721 token address
- `uint256` The ID of the ERC1155
- `uint256` The minimum required amount of the ERC1155

### `SWEEP_ERC721`

- `address` The ERC721 token address to transfer
- `address` The recipient of the transfer
- `uint256` The token ID to transfer

### `X2Y2_721`

- `uint256` The ETH value to forward to the X2Y2 contract
- `bytes` The calldata to use to call the X2Y2 contract
- `address` The recipient of the ERC721
- `address` The ERC721 token address
- `uint256` The ID of the ERC721

### `SUDOSWAP`

- `uint256` The ETH value to forward to the Sudoswap contract
- `bytes` The calldata to use to call the Sudoswap contract

### `NFT20`

- `uint256` The ETH value to forward to the NFT20 contract
- `bytes` The calldata to use to call the NFT20 contract

### `X2Y2_1155`

- `uint256` The ETH value to forward to the X2Y2 contract
- `bytes` The calldata to use to call the X2Y2 contract
- `address` The recipient of the ERC1155
- `address` The ERC1155 token address
- `uint256` The ID of the ERC1155
- `uint256` The amount of the ERC1155 to transfer

### `FOUNDATION`

- `uint256` The ETH value to forward to the Foundation contract
- `bytes` The calldata to use to call the Foundation contract
- `address` The recipient of the ERC721
- `address` The ERC721 token address
- `uint256` The ID of the ERC721

### `SWEEP_ERC1155`

- `address` The ERC1155 token address to sweep
- `address` The recipient of the sweep
- `uint256` The token ID to sweep
- `uint256` The minimum required tokens to receive from the sweep

## Example: Reverting Commands

For a Sudoswap command, that should be *allowed to revert*, the following 8 bit command should be provided:

```markdown
command = 0x80 (10000000) && 0x19 (00011001) = 0x99 (10011001)
```

Take care when working with reverting commands - ensure you have appended commands to deal with funds that could remain in the contract after either outcomes. For example, if the Sudoswap command reverts, a following `SWEEP` can be added to ensure that any ETH that was not spent does not get left in the router.
6 changes: 6 additions & 0 deletions docs/contracts/universal-router/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"label": "Universal Router",
"position": 2,
"collapsed": true
}

2 changes: 1 addition & 1 deletion docs/contracts/v1/_category_.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"label": "V1 Protocol",
"position": 4,
"position": 5,
"collapsed": true
}
2 changes: 1 addition & 1 deletion docs/contracts/v2/_category_.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"label": "V2 Protocol",
"position": 3,
"position": 4,
"collapsed": true
}

1 comment on commit 9fa96df

@vercel
Copy link

@vercel vercel bot commented on 9fa96df Dec 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./

docs-uniswap.vercel.app
docs-git-main-uniswap.vercel.app
docs.uniswap.org

Please sign in to comment.