Unlock Callback & Deltas
Refresher
In order to have access to the liquidity inside the PoolManager
,
it needs to be unlocked to begin with. After being unlocked, any
number of operations can be executed, which at the end of must be locked
again. At this point, if there are any non-zero deltas, meaning the
PoolManager is owed or owes tokens back to some address, the whole
execution reverts. Otherwise, both parties have paid or received
the right amount of tokens and the operations have successfully
carried out.
Unlocking the PoolManager
Implementing the unlock callback
Prior to unlocking the PoolManager, the integrating contract must
implement the unlockCallback
function. This function will be
called by the PoolManager after being unlocked. An easy way to
do this is to inherit the SafeCallback
abstract contract.
import {SafeCallback} from "v4-periphery/src/base/SafeCallback.sol";
contract IntegratingContract is SafeCallback {
constructor(IPoolManager _poolManager) SafeCallback(_poolManager) {}
}
Calling the unlock function
After implementing the callback, the integrating contract can now
invoke the unlock()
function. It receives a bytes parameter
that is further passed to your callback function as an argument.
This parameter is used to encode the sequence of operations to be
executed in the context of the PoolManager
.
bytes memory unlockData = abi.encode(encode_operations_here);
bytes memory unlockResultData = poolManager.unlock(unlockData);
Next, we must override the _unlockCallback
function inherited from
the SafeCallback
contract. In your implementation, you should
decode your operations and continue with the desired logic.
function _unlockCallback(bytes calldata data) internal override returns (bytes memory) {
(...) = abi.decode(data, (...));
}
Operations
There are 9 operations that can be done in the PoolManager
which fall in two categories: liquidity-accessing and delta-resolving.
Deltas
Deltas are the PoolManager
's method to keep track of token amounts it
needs to receive, respectively to distribute. A negative delta signals that
the PoolManager
is owed tokens, while a positive one expresses a
token balance that needs to be paid to its user.
Liquidity-accessing
Liquidity-accessing operations will create non-zero deltas and produce a state transition of the selected pool. They are the following:
- modify liquidity - used to increase or decrease liquidity; increasing liquidity will result in a negative token delta, while decreasing yields a positive one
- swap - used to trade one token for another; will result in a negative tokenA delta and a positive tokenB delta
- donate - used to provide direct token revenue to positions in range; will result in a negative delta for the pool's tokens the user wishes to provide
Delta-resolving
Delta-resolving operations are used to even out the deltas created by the liquidity-accessing operations. They are the following:
- settle - used following token transfers to the manager or burning of ERC6909 claims to resolve negative deltas
- take - transfer tokens from the manager, used to resolve positive deltas but also provide token loans, producing negative deltas
- mint - used to create ERC6909 claims, creating a negative delta that needs to be resolved by transferring the corresponding token and settling afterwards
- burn - removes ERC6909 claims, creating a positive delta for tokens to be transferred back to the owner or used in settling negative balances
- clear - used to zero out positive token deltas, helpful to forfeit insignificant token amounts in order to avoid paying further transfer costs