Uniswap v3 Protocol
Overview
Uniswap is a decentralized exchange (DEX) protocol that allows users to provide and trade liquidity in a range of assets on EVM blockchains. Uniswap v3 is the 3rd iteration of the protocol which introduces the non-fungible liquidity positions and concentrated liquidity concepts, where liquidity providers (LPs) are able to specify a price range for their liquidity, thereby maximizing capital efficiency.
The Nexera-Fi UniswapAdapter interacts with and utilizes the following three key components of Uniswap v3:
- NonfungiblePositionManager contract
- SwapRouter contract
- TransferHelper library
In the following sections, we'll provide an overview of these contracts and their methods that Nexera-Fi UniswapAdapter interacts with.
Interactions with UniswapAdapter
The UniswapAdapter interacts with the Uniswap v3 protocol by calling the methods presented in the diagram below.
Each method serves a specific purpose within the adapter, enabling strategies to seamlessly integrate deposits, withdrawals, and swaps of assets on the Uniswap v3 platform.
NonfungiblePositionManager
The NonfungiblePositionManager contract is a core component of the Uniswap v3 protocol. It allows users to manage liquidity positions, create new positions, and modify existing ones.
In the context of the Nexera-Fi UniswapAdapter, these six methods come into play:
positions
: Retrieves information about a specific liquidity position.collect
: Collects fees earned from a liquidity position.mint
: Creates a new liquidity position by depositing assets into a specific pool.increaseLiquidity
: Adds additional liquidity to an existing position.decreaseLiquidity
: Reduces the liquidity of an existing position.refundETH
: Refunds excess ETH (if any) from a position after decreasing liquidity and swap actions.
Methods
positions
Retrieves information about a specific liquidity position associated with a give NFT LP token.
This method is invoked by the following UniswapAdapter functions:
When this function is executed with a non-zero tokenId
provided in the DepositExtraData
, the Adapter adds liquidity to an existing position.
To achieve this, the Adapter first obtains the addresses of the two tokens (token0
& token1
) in the associated Pool by invoking the positions
method.
These acquired addresses are cross-checked for inconsistencies with the respective provided data within DepositExtraData
.
Consequently, if any of the acquired addresses is zero address, they are replaced with the address of the wrapped native token stored in storage during initialization.
These addresses are then utilized to construct the necessary data for increasing liquidity within the target position.
This helper function invokes the positions
method to retrieve the addresses of the two tokens (token0
& token1
) associated with a particular liquidity position, identified by the provided NFT LP tokenId
.
This step is essential to verify and confirm the consistency between the tokens specified in the input data (expectedIn) and the actual tokens held within the liquidity position.
Thus, the Adapter ensures that it operates with precise information about the assets contained in the liquidity position, thereby safeguarding the integrity of the transactions.
This function invokes the positions
method to retrieve key data related to a specific liquidity position identified by the tokenId
within withdrawExtraData
.
This data includes the liquidity
, as well as the amounts of tokens owed (tokensOwed0
and tokensOwed1
) for the target position before and after the liquidity is decreased.
These steps are crucial for verifying the consistency between the actual input tokens (the assets received by the Adapter) and the expected input tokens defined in expectedIn
.
collect
Collects up to a maximum amount of fees owed to a specific position to the recipient
This method is invoked by the following UniswapAdapter function:
The collect
method is invoked to perform the operation of claiming earned fees from a specific liquidity position identified by the tokenId
within the extraData
input parameter.
In the context of the function the captured collected amounts (amount0
& amount1
) are cross-validated against the expected values specified in expectedIn
input parameter, thereby safeguarding the integrity of the transaction.
mint
Creates a new position wrapped in a NFT LP token.
This method is invoked by the following UniswapAdapter function:
When this function is executed with tokenId==0
provided in the DepositExtraData
, the Adapter creates a new NFT liquidity position by invoking the mint
method with the necessary params
input argument.
In the context of the function the captured amounts (amount0
& amount1
) are cross-validated against the expected amounts defined in expectedIn
to verify they meet or exceed the specified minimums for integrity.
increaseLiquidity
Increases the amount of liquidity in a position.
This method is invoked by the following UniswapAdapter function:
In the context of this function, when the DepositExtraData
.tokenId is non-zero, the Adapter is directed to add liquidity to an existing NFT LP position.
To accomplish this, the Adapter must interact with the increaseLiquidity
method provided by the NonfungiblePositionManager.
This method allows the Adapter to increase the liquidity within the specified NFT position by supplying the desired amounts of token0
and token1
.
decreaseLiquidity
Decreases the amount of liquidity in a position and accounts it to the position.
This method is invoked by the following UniswapAdapter function:
In the context of this function the Adapter is directed to remove liquidity from an existing NFT LP position.
To accomplish this, the Adapter must interact with the decreaseLiquidity
method provided by the NonfungiblePositionManager.
This method allows the Adapter to decrease the liquidity within the specified NFT position by supplying the desired amounts of token0
and token1
defined in withdrawExtraData
and expectedIn
input parameters, ensuring that it aligns with the provided percentage to withdraw.
refundETH
Refunds excess ETH (if any) held by the NonfungiblePositionManager contract after decreasing liquidity and swap actions.
This method is invoked by the following UniswapAdapter functions:
In both the _swap
and _deposit
functions of the Adapter, the refundETH
method provided by the NonfungiblePositionManager is invoked to ensure that any excess ETH sent during the transaction is returned to the Adapter.
This is a safety measure to prevent the loss of native currency in case it's not fully utilized during the operation.
SwapRouter
The SwapRouter contract enables the swapping of tokens within the Uniswap v3 protocol.
Methods
exactInputSingle
Performs a single token swap with a specific input amount.
This method is invoked by the following UniswapAdapter function:
In the context of this function, the Adapter invokes the exactInputSingle
method of the SwapRouter with parameters constructed from the extraData
, out
, and expectedIn
input arguments.
These parameters encompass the desired fee tier, the desired sqrtPriceLimitX96 for the swap, the target tokens (tokenIn & tokenOut) as well as the desired and minium amounts.
If any of the target token addresses provided are set to the zero address, they are replaced with the address of the wrapped native token stored in storage during initialization.
Moreover, the returned amount0
from the method is captured and internally cross-validated to ensure that it meets or exceeds the expected amount specified in the expectedIn
input argument.
TransferHelper
The TransferHelper library includes functions for safely transferring tokens and handling token approvals.
Methods
safeApprove
Safely approves a contract to spend a specified amount of tokens.
This method is invoked by the following UniswapAdapter functions:
In this function, the Adapter employs a multi-step approach to ensure secure token transfers during the deposit process.
First, it checks the current allowances of the NonFungiblePositionManager for the target tokens (token0 & token1).
If allowances are already set, it resets them to zero using the safeApprove
method.
Subsequently, it sets new allowances with the exact amounts defined in the out
input argument.
This process actively manages token spending permissions for the involved tokens, enhancing the security of the deposit operation.
In this function, the Adapter enables secure token swaps by setting the allowance for the SwapRouter contract.
The allowance is established using the safeApprove
method, where the exact spending permissions granted to the SwapRouter are provided.
Please note: For detailed information about Uniswap v3 protocol, consult the official Uniswap v3 documentation.