-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* forge install: v3-periphery v1.3.0 * Added a basic Uniswap v3 zap contract * Added a Uni v3 zap for `closeLong` and improved the zap for `openLong` * Added a zap for `addLiquidity` * Cleaned up the validation logic for Uni v3 zaps * Adds zaps for `removeLiquidity` and `redeemWithdrawalShares` * Added the remaining zaps * Started writing tests for `addLiquidityZap` * Updated the zap to use multi-hop routing * Wrote some more tests * Refactored the `addLiquidityZap` tests * Added tests for `openLongZap` * Added a full test suite for `openLongZap` * Broke out the zap tests and added test for `openShortZap` * Added support for zaps out starting with ETH * Added tests for `removeLiquidity` * Added tests for `redeemWithdrawalSharesZap` * Added tests for `redeemWithdrawalSharesZap` * Added tests for `closeLongZap` * Added tests for `closeShortZap` * Cleaned up the tests * Bump the version * Remaining cleanup * Fixed the UniV3Zap * Added wrapping tests * Some cleanup * Some cleanup * Addressed review feedback from @jrhea * Addressed remaining review feedback from @jrhea * Appeased the linter gods * Addressed review feedback from @mcclurejt
- Loading branch information
1 parent
a4c481f
commit be243b6
Showing
19 changed files
with
5,610 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.22; | ||
|
||
interface ISwapRouter { | ||
struct ExactInputSingleParams { | ||
address tokenIn; | ||
address tokenOut; | ||
uint24 fee; | ||
address recipient; | ||
uint256 deadline; | ||
uint256 amountIn; | ||
uint256 amountOutMinimum; | ||
uint160 sqrtPriceLimitX96; | ||
} | ||
|
||
function exactInputSingle( | ||
ExactInputSingleParams calldata params | ||
) external payable returns (uint256 amountOut); | ||
|
||
struct ExactInputParams { | ||
bytes path; | ||
address recipient; | ||
uint256 deadline; | ||
uint256 amountIn; | ||
uint256 amountOutMinimum; | ||
} | ||
|
||
function exactInput( | ||
ExactInputParams calldata params | ||
) external payable returns (uint256 amountOut); | ||
|
||
struct ExactOutputSingleParams { | ||
address tokenIn; | ||
address tokenOut; | ||
uint24 fee; | ||
address recipient; | ||
uint256 deadline; | ||
uint256 amountOut; | ||
uint256 amountInMaximum; | ||
uint160 sqrtPriceLimitX96; | ||
} | ||
|
||
function exactOutputSingle( | ||
ExactOutputSingleParams calldata params | ||
) external payable returns (uint256 amountIn); | ||
|
||
struct ExactOutputParams { | ||
bytes path; | ||
address recipient; | ||
uint256 deadline; | ||
uint256 amountOut; | ||
uint256 amountInMaximum; | ||
} | ||
|
||
function exactOutput( | ||
ExactOutputParams calldata params | ||
) external payable returns (uint256 amountIn); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,289 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.20; | ||
|
||
import { IHyperdrive } from "./IHyperdrive.sol"; | ||
import { ISwapRouter } from "./ISwapRouter.sol"; | ||
|
||
/// @title IUniV3Zap | ||
/// @author DELV | ||
/// @notice The interface for the UniV3Zap contract. | ||
/// @custom:disclaimer The language used in this code is for coding convenience | ||
/// only, and is not intended to, and does not, have any | ||
/// particular legal or regulatory significance. | ||
interface IUniV3Zap { | ||
/// Errors /// | ||
|
||
/// @notice Thrown when attempting to zap to an invalid input token. | ||
error InvalidInputToken(); | ||
|
||
/// @notice Thrown when attempting to zap to an invalid output token. | ||
error InvalidOutputToken(); | ||
|
||
/// @notice Thrown when attempting to zap to an invalid recipient. | ||
error InvalidRecipient(); | ||
|
||
/// @notice Thrown when attempting to zap with an invalid source amount. If | ||
/// the source asset doesn't needs to be wrapped, this needs to be | ||
/// the same as the swap's input amount. | ||
error InvalidSourceAmount(); | ||
|
||
/// @notice Thrown when attempting to zap with an invalid source asset. If | ||
/// the source asset needs to be wrapped, this shouldn't be the same | ||
/// address as the input token to the swap. Otherwise, they should | ||
/// be the same. | ||
error InvalidSourceAsset(); | ||
|
||
/// @notice Thrown when attempting to zap from an asset to itself. This | ||
/// protects users from swaps that could only lead them to incur | ||
/// losses through fees and slippage. | ||
error InvalidSwap(); | ||
|
||
/// @notice Thrown when receiving ether outside of an zap. | ||
error InvalidTransfer(); | ||
|
||
/// @notice Thrown when ether is sent to an instance that doesn't accept | ||
/// ether as a deposit asset. | ||
error NotPayable(); | ||
|
||
/// @notice Thrown when we should be wrapping assets, but the zap isn't | ||
/// configured to wrap. | ||
error ShouldWrapAssets(); | ||
|
||
/// @notice Thrown when an ether transfer fails. | ||
error TransferFailed(); | ||
|
||
/// Structs /// | ||
|
||
/// @dev The options parameter provided to all of the functions that zap | ||
/// funds into Hyperdrive. | ||
struct ZapInOptions { | ||
/// @dev The Uniswap swap parameters to use when swapping assets to the | ||
/// deposit asset. | ||
ISwapRouter.ExactInputParams swapParams; | ||
/// @dev In most cases, this should be equal to the input token of the | ||
/// swap. In some cases, this will be a rebasing token like stETH | ||
/// that needs to be wrapped to make it suitable for swapping on | ||
/// Uniswap. | ||
address sourceAsset; | ||
/// @dev The amount of source tokens that should be swapped. In most | ||
/// cases, this should be equal to the `swapParams.amountIn`, but | ||
/// in the case of wrapped tokens, this amount will supersede that | ||
/// quantity. | ||
uint256 sourceAmount; | ||
/// @dev A flag that indicates whether or not the source token should | ||
/// be wrapped into the input token. Uniswap v3 demands complete | ||
/// precision on the input token amounts, which makes it hard to | ||
/// work with rebasing tokens that have imprecise transfer | ||
/// functions. Wrapping tokens provides a workaround for these | ||
/// issues. | ||
bool shouldWrap; | ||
/// @dev A flag that indicates whether or not the Hyperdrive vault | ||
/// shares token is a vault shares token. This is used to ensure | ||
/// that the input into Hyperdrive properly handles rebasing tokens. | ||
bool isRebasing; | ||
} | ||
|
||
/// Metadata /// | ||
|
||
/// @notice Returns the name of this zap. | ||
/// @return The name of this zap. | ||
function name() external view returns (string memory); | ||
|
||
/// @notice Returns the kind of this zap. | ||
/// @return The kind of this zap. | ||
function kind() external view returns (string memory); | ||
|
||
/// @notice Returns the version of this zap. | ||
/// @return The version of this zap. | ||
function version() external view returns (string memory); | ||
|
||
/// LPs /// | ||
|
||
/// @notice Executes a swap on Uniswap and uses the proceeds to add | ||
/// liquidity on Hyperdrive. | ||
/// @param _hyperdrive The Hyperdrive pool to open the long on. | ||
/// @param _minLpSharePrice The minimum LP share price the LP is willing | ||
/// to accept for their shares. LPs incur negative slippage when | ||
/// adding liquidity if there is a net curve position in the market, | ||
/// so this allows LPs to protect themselves from high levels of | ||
/// slippage. The units of this quantity are either base or vault | ||
/// shares, depending on the value of `_options.asBase`. | ||
/// @param _minApr The minimum APR at which the LP is willing to supply. | ||
/// @param _maxApr The maximum APR at which the LP is willing to supply. | ||
/// @param _hyperdriveOptions The options that configure how the Hyperdrive | ||
/// operation is settled. | ||
/// @param _zapInOptions The options that configure how the zap will be | ||
/// settled. | ||
/// @return lpShares The LP shares received by the LP. | ||
function addLiquidityZap( | ||
IHyperdrive _hyperdrive, | ||
uint256 _minLpSharePrice, | ||
uint256 _minApr, | ||
uint256 _maxApr, | ||
IHyperdrive.Options calldata _hyperdriveOptions, | ||
IUniV3Zap.ZapInOptions calldata _zapInOptions | ||
) external payable returns (uint256 lpShares); | ||
|
||
/// @notice Removes liquidity on Hyperdrive and converts the proceeds to the | ||
/// traders preferred asset by executing a swap on Uniswap v3. | ||
/// @param _hyperdrive The Hyperdrive pool to open the long on. | ||
/// @param _lpShares The LP shares to burn. | ||
/// @param _minOutputPerShare The minimum amount the LP expects to receive | ||
/// for each withdrawal share that is burned. The units of this | ||
/// quantity are either base or vault shares, depending on the value | ||
/// of `_options.asBase`. | ||
/// @param _options The options that configure how the operation is settled. | ||
/// @param _swapParams The Uniswap swap parameters for a multi-hop fill. | ||
/// @param _shouldWrap A flag indicating whether or not the proceeds need to | ||
/// be wrapped. | ||
/// @return proceeds The proceeds of removing liquidity. These proceeds will | ||
/// be in units determined by the Uniswap swap parameters. | ||
/// @return withdrawalShares The base that the LP receives buys out some of | ||
/// their LP shares, but it may not be sufficient to fully buy the | ||
/// LP out. In this case, the LP receives withdrawal shares equal in | ||
/// value to the present value they are owed. As idle capital | ||
/// becomes available, the pool will buy back these shares. | ||
function removeLiquidityZap( | ||
IHyperdrive _hyperdrive, | ||
uint256 _lpShares, | ||
uint256 _minOutputPerShare, | ||
IHyperdrive.Options calldata _options, | ||
ISwapRouter.ExactInputParams calldata _swapParams, | ||
bool _shouldWrap | ||
) external returns (uint256 proceeds, uint256 withdrawalShares); | ||
|
||
/// @notice Redeem withdrawal shares on Hyperdrive and converts the proceeds | ||
/// to the traders preferred asset by executing a swap on Uniswap | ||
/// v3. | ||
/// @param _hyperdrive The Hyperdrive pool to open the long on. | ||
/// @param _withdrawalShares The withdrawal shares to redeem. | ||
/// @param _minOutputPerShare The minimum amount the LP expects to | ||
/// receive for each withdrawal share that is burned. The units of | ||
/// this quantity are either base or vault shares, depending on the | ||
/// value of `_options.asBase`. | ||
/// @param _options The options that configure how the operation is settled. | ||
/// @param _swapParams The Uniswap swap parameters for a multi-hop fill. | ||
/// @param _shouldWrap A flag indicating whether or not the proceeds need to | ||
/// be wrapped. | ||
/// @return proceeds The proceeds of redeeming withdrawal shares. These | ||
/// proceeds will be in units determined by the Uniswap swap | ||
/// parameters. | ||
/// @return withdrawalSharesRedeemed The amount of withdrawal shares that | ||
/// were redeemed. | ||
function redeemWithdrawalSharesZap( | ||
IHyperdrive _hyperdrive, | ||
uint256 _withdrawalShares, | ||
uint256 _minOutputPerShare, | ||
IHyperdrive.Options calldata _options, | ||
ISwapRouter.ExactInputParams calldata _swapParams, | ||
bool _shouldWrap | ||
) external returns (uint256 proceeds, uint256 withdrawalSharesRedeemed); | ||
|
||
/// Longs /// | ||
|
||
/// @notice Executes a swap on Uniswap and uses the proceeds to open a long | ||
/// on Hyperdrive. | ||
/// @param _hyperdrive The Hyperdrive pool to open the long on. | ||
/// @param _minOutput The minimum number of bonds to receive. | ||
/// @param _minVaultSharePrice The minimum vault share price at which to | ||
/// open the long. This allows traders to protect themselves from | ||
/// opening a long in a checkpoint where negative interest has | ||
/// accrued. | ||
/// @param _hyperdriveOptions The options that configure how the Hyperdrive | ||
/// operation is settled. | ||
/// @param _zapInOptions The options that configure how the zap will be | ||
/// settled. | ||
/// @return maturityTime The maturity time of the bonds. | ||
/// @return longAmount The amount of bonds the trader received. | ||
function openLongZap( | ||
IHyperdrive _hyperdrive, | ||
uint256 _minOutput, | ||
uint256 _minVaultSharePrice, | ||
IHyperdrive.Options calldata _hyperdriveOptions, | ||
IUniV3Zap.ZapInOptions calldata _zapInOptions | ||
) external payable returns (uint256 maturityTime, uint256 longAmount); | ||
|
||
/// @notice Closes a long on Hyperdrive and converts the proceeds to the | ||
/// traders preferred asset by executing a swap on Uniswap v3. | ||
/// @param _hyperdrive The Hyperdrive pool to open the long on. | ||
/// @param _maturityTime The maturity time of the long. | ||
/// @param _bondAmount The amount of longs to close. | ||
/// @param _minOutput The minimum proceeds the trader will accept. The units | ||
/// of this quantity are either base or vault shares, depending on | ||
/// the value of `_options.asBase`. | ||
/// @param _options The options that configure how the Hyperdrive trade is | ||
/// settled. | ||
/// @param _swapParams The Uniswap swap parameters for a multi-hop fill. | ||
/// @param _shouldWrap A flag indicating whether or not the proceeds need to | ||
/// be wrapped. | ||
/// @return proceeds The proceeds of closing the long. These proceeds will | ||
/// be in units determined by the Uniswap swap parameters. | ||
function closeLongZap( | ||
IHyperdrive _hyperdrive, | ||
uint256 _maturityTime, | ||
uint256 _bondAmount, | ||
uint256 _minOutput, | ||
IHyperdrive.Options calldata _options, | ||
ISwapRouter.ExactInputParams calldata _swapParams, | ||
bool _shouldWrap | ||
) external returns (uint256 proceeds); | ||
|
||
/// Shorts /// | ||
|
||
/// @notice Executes a swap on Uniswap and uses the proceeds to open a short | ||
/// on Hyperdrive. | ||
/// @param _hyperdrive The Hyperdrive pool to open the long on. | ||
/// @param _maxDeposit The most the user expects to deposit for this trade. | ||
/// The units of this quantity are either base or vault shares, | ||
/// depending on the value of `_options.asBase`. | ||
/// @param _minVaultSharePrice The minimum vault share price at which to open | ||
/// the short. This allows traders to protect themselves from opening | ||
/// a short in a checkpoint where negative interest has accrued. | ||
/// @param _hyperdriveOptions The options that configure how the Hyperdrive | ||
/// operation is settled. | ||
/// @param _zapInOptions The options that configure how the zap will be | ||
/// settled. | ||
/// @return maturityTime The maturity time of the bonds. | ||
/// @return deposit The amount the user deposited for this trade. The units | ||
/// of this quantity are either base or vault shares, depending on | ||
/// the value of `_options.asBase`. | ||
function openShortZap( | ||
IHyperdrive _hyperdrive, | ||
uint256 _bondAmount, | ||
uint256 _maxDeposit, | ||
uint256 _minVaultSharePrice, | ||
IHyperdrive.Options calldata _hyperdriveOptions, | ||
IUniV3Zap.ZapInOptions calldata _zapInOptions | ||
) external payable returns (uint256 maturityTime, uint256 deposit); | ||
|
||
/// @notice Closes a short on Hyperdrive and converts the proceeds to the | ||
/// traders preferred asset by executing a swap on Uniswap v3. | ||
/// @param _hyperdrive The Hyperdrive pool to open the long on. | ||
/// @param _maturityTime The maturity time of the short. | ||
/// @param _bondAmount The amount of shorts to close. | ||
/// @param _minOutput The minimum output of this trade. The units of this | ||
/// quantity are either base or vault shares, depending on the value | ||
/// of `_options.asBase`. | ||
/// @param _options The options that configure how the Hyperdrive trade is | ||
/// settled. | ||
/// @param _swapParams The Uniswap swap parameters for a multi-hop fill. | ||
/// @param _shouldWrap A flag indicating whether or not the proceeds need to | ||
/// be wrapped. | ||
/// @return proceeds The proceeds of closing the short. These proceeds will | ||
/// be in units determined by the Uniswap swap parameters. | ||
function closeShortZap( | ||
IHyperdrive _hyperdrive, | ||
uint256 _maturityTime, | ||
uint256 _bondAmount, | ||
uint256 _minOutput, | ||
IHyperdrive.Options calldata _options, | ||
ISwapRouter.ExactInputParams calldata _swapParams, | ||
bool _shouldWrap | ||
) external returns (uint256 proceeds); | ||
|
||
/// Getters /// | ||
|
||
/// @notice Returns the Uniswap swap router. | ||
/// @return The Uniswap swap router. | ||
function swapRouter() external view returns (ISwapRouter); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.20; | ||
|
||
import { IERC20 } from "./IERC20.sol"; | ||
|
||
interface IWETH is IERC20 { | ||
function deposit() external payable; | ||
|
||
function withdraw(uint256 wad) external; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.20; | ||
|
||
import { IERC20 } from "./IERC20.sol"; | ||
|
||
interface IWrappedERC20 is IERC20 { | ||
function wrap(uint256 _amount) external returns (uint256); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.