UniswapFlashswapHandler
Inherits: IonHandlerBase, IUniswapV3SwapCallback
This contract allows for easy creation and closing of leverage positions through Uniswap flashswaps--flashloan not necessary! In terms of creation, this may be a more desirable path than directly minting from an LST provider since market prices tend to be slightly lower than provider exchange rates. DEXes also provide an avenue for atomic deleveraging since the LST -> ETH exchange can be made.
When using the UniswapFlashSwapHandler
, the IUniswapV3Pool pool
fed to the constructor should be the WETH/[LST] pool. Unlike Balancer flashloans, there is no concern here that somebody else could initiate a flashswap, then direct the callback to be called on this contract. Uniswap enforces that callback is only called on msg.sender
.
State Variables
MIN_SQRT_RATIO
The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4_295_128_739;
MAX_SQRT_RATIO
The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1_461_446_703_485_210_103_287_273_052_203_988_822_378_723_970_342;
UNISWAP_POOL
IUniswapV3Pool public immutable UNISWAP_POOL;
WETH_IS_TOKEN0
bool private immutable WETH_IS_TOKEN0;
Functions
constructor
Creates a new UniswapFlashswapHandler
instance.
constructor(IUniswapV3Pool _pool, bool _wethIsToken0);
Parameters
_pool
IUniswapV3Pool
Pool to perform the flashswap on.
_wethIsToken0
bool
Whether WETH is token0 or token1 in the pool.
flashswapLeverage
Transfer collateral from user -> initiate swap for collateral from WETH on Uniswap (contract will receive collateral first) -> deposit all collateral into IonPool
-> borrow WETH from IonPool
-> complete swap by sending WETH to Uniswap.
function flashswapLeverage(
uint256 initialDeposit,
uint256 resultingAdditionalCollateral,
uint256 maxResultingAdditionalDebt,
uint160 sqrtPriceLimitX96,
uint256 deadline,
bytes32[] calldata proof
)
external
checkDeadline(deadline)
onlyWhitelistedBorrowers(proof);
Parameters
initialDeposit
uint256
in collateral terms. [WAD]
resultingAdditionalCollateral
uint256
in collateral terms. [WAD]
maxResultingAdditionalDebt
uint256
in WETH terms. This value also allows the user to control slippage of the swap. [WAD]
sqrtPriceLimitX96
uint160
for the swap. Recommended value is the current exchange rate to ensure the swap never costs more than a direct mint would. Passing the current exchange rate means swapping beyond that point is worse than direct minting.
deadline
uint256
timestamp for which the transaction must be executed. This prevents txs that have sat in the mempool for too long to be executed.
proof
bytes32[]
that the user is whitelisted.
_flashswapLeverage
function _flashswapLeverage(
uint256 initialDeposit,
uint256 resultingAdditionalCollateral,
uint256 maxResultingAdditionalDebt,
uint160 sqrtPriceLimitX96
)
internal;
Parameters
initialDeposit
uint256
in terms of swETH
resultingAdditionalCollateral
uint256
in terms of swETH. How much collateral to add to the position in the vault.
maxResultingAdditionalDebt
uint256
in terms of WETH. How much debt to add to the position in the vault.
sqrtPriceLimitX96
uint160
for the swap. Recommended value is the current exchange rate to ensure the swap never costs more than a direct mint would.
flashswapDeleverage
Initiate swap for WETH from collateral (contract will receive WETH first) -> repay debt on IonPool
-> withdraw (and gem-exit) collateral from IonPool
-> complete swap by sending collateral to Uniswap.
The two function parameters must be chosen carefully. If maxCollateralToRemove
's ETH valuation were higher then debtToRemove
, it would theoretically be possible to sell more collateral then was required for debtToRemove
to be repaid (even if debtToRemove
is worth nowhere near that valuation) due to the slippage of the sell. maxCollateralToRemove
is essentially a slippage guard here.
function flashswapDeleverage(
uint256 maxCollateralToRemove,
uint256 debtToRemove,
uint160 sqrtPriceLimitX96,
uint256 deadline
)
external
checkDeadline(deadline);
Parameters
maxCollateralToRemove
uint256
he max amount of collateral user is willing to sell to repay debtToRemove
debt. [WAD]
debtToRemove
uint256
The desired amount of debt to remove. [WAD]
sqrtPriceLimitX96
uint160
for the swap. Can be set to 0 to set max bounds.
deadline
uint256
_initiateFlashSwap
Handles swap initiation logic. This function can only initiate exact output swaps.
function _initiateFlashSwap(
bool zeroForOne,
uint256 amountOut,
address recipient,
uint160 sqrtPriceLimitX96,
FlashSwapData memory data
)
private
returns (uint256 amountIn);
Parameters
zeroForOne
bool
Direction of the swap.
amountOut
uint256
Desired amount of output.
recipient
address
of output tokens.
sqrtPriceLimitX96
uint160
of the swap.
data
FlashSwapData
Arbitrary data to be passed through swap callback.
uniswapV3SwapCallback
From the perspective of the pool i.e. Negative amount means pool is sending. This function is intended to never be called directly. It should only be called by the Uniswap pool during a swap initiated by this contract.
One thing to note from a security perspective is that the pool only calls the callback on msg.sender
. So a theoretical attacker cannot call this function by directing where to call the callback.
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata _data) external override;
Parameters
amount0Delta
int256
change in token0
amount1Delta
int256
change in token1
_data
bytes
arbitrary data
Errors
InvalidUniswapPool
error InvalidUniswapPool();
InvalidZeroLiquidityRegionSwap
error InvalidZeroLiquidityRegionSwap();
InvalidSqrtPriceLimitX96
error InvalidSqrtPriceLimitX96(uint160 sqrtPriceLimitX96);
FlashswapRepaymentTooExpensive
error FlashswapRepaymentTooExpensive(uint256 amountIn, uint256 maxAmountIn);
CallbackOnlyCallableByPool
error CallbackOnlyCallableByPool(address unauthorizedCaller);
OutputAmountNotReceived
error OutputAmountNotReceived(uint256 amountReceived, uint256 amountRequired);
Structs
FlashSwapData
struct FlashSwapData {
address user;
uint256 changeInCollateralOrDebt;
bool zeroForOne;
}