diff --git a/contracts/interfaces/IPerpV2BasisTradingModule.sol b/contracts/interfaces/IPerpV2BasisTradingModule.sol new file mode 100644 index 000000000..4c0f89400 --- /dev/null +++ b/contracts/interfaces/IPerpV2BasisTradingModule.sol @@ -0,0 +1,159 @@ +/* + Copyright 2022 Set Labs Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache License, Version 2.0 +*/ +pragma solidity 0.6.10; +pragma experimental "ABIEncoderV2"; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { IPerpV2LeverageModuleV2 } from "./IPerpV2LeverageModuleV2.sol"; +import { ISetToken } from "./ISetToken.sol"; + +/** + * @title IPerpV2BasisTradingModule + * @author Set Protocol + * + * Interface for the PerpV2BasisTradingModule. Only specifies Manager permissioned functions, events + * and getters. PerpV2BasisTradingModule also inherits from ModuleBaseV2 and SetTokenAccessible which support + * additional methods. + */ +interface IPerpV2BasisTradingModule is IPerpV2LeverageModuleV2 { + + /* ============ Structs ============ */ + + struct FeeState { + address feeRecipient; // Address to accrue fees to + uint256 maxPerformanceFeePercentage; // Max performance fee manager commits to using (1% = 1e16, 100% = 1e18) + uint256 performanceFeePercentage; // Performance fees accrued to manager (1% = 1e16, 100% = 1e18) + } + + /* ============ Events ============ */ + + /** + * @dev Emitted on performance fee update + * @param _setToken Instance of SetToken + * @param _newPerformanceFee New performance fee percentage (1% = 1e16) + */ + event PerformanceFeeUpdated(ISetToken indexed _setToken, uint256 _newPerformanceFee); + + /** + * @dev Emitted on fee recipient update + * @param _setToken Instance of SetToken + * @param _newFeeRecipient New performance fee recipient + */ + event FeeRecipientUpdated(ISetToken indexed _setToken, address _newFeeRecipient); + + /** + * @dev Emitted on funding withdraw + * @param _setToken Instance of SetToken + * @param _collateralToken Token being withdrawn as funding (USDC) + * @param _amountWithdrawn Amount of funding being withdrawn from Perp (USDC) + * @param _managerFee Amount of performance fee accrued to manager (USDC) + * @param _protocolFee Amount of performance fee accrued to protocol (USDC) + */ + event FundingWithdrawn( + ISetToken indexed _setToken, + IERC20 _collateralToken, + uint256 _amountWithdrawn, + uint256 _managerFee, + uint256 _protocolFee + ); + + /* ============ State Variable Getters ============ */ + + // Mapping to store fee settings for each SetToken + function feeSettings(ISetToken _setToken) external view returns(FeeState memory); + + // Mapping to store funding that has been settled on Perpetual Protocol due to actions via this module + // and hasn't been withdrawn for reinvesting yet. Values are stored in precise units (10e18). + function settledFunding(ISetToken _settledFunding) external view returns (uint256); + + /* ============ External Functions ============ */ + + /** + * @dev MANAGER ONLY: Initializes this module to the SetToken and sets fee settings. Either the SetToken needs to + * be on the allowed list or anySetAllowed needs to be true. + * + * @param _setToken Instance of the SetToken to initialize + */ + function initialize( + ISetToken _setToken, + FeeState memory _settings + ) + external; + + /** + * @dev MANAGER ONLY: Similar to PerpV2LeverageModuleV2#trade. Allows manager to buy or sell perps to change exposure + * to the underlying baseToken. Any pending funding that would be settled during opening a position on Perpetual + * protocol is added to (or subtracted from) `settledFunding[_setToken]` and can be withdrawn later using + * `withdrawFundingAndAccrueFees` by the SetToken manager. + * NOTE: Calling a `nonReentrant` function from another `nonReentrant` function is not supported. Hence, we can't + * add the `nonReentrant` modifier here because `PerpV2LeverageModuleV2#trade` function has a reentrancy check. + * NOTE: This method doesn't update the externalPositionUnit because it is a function of UniswapV3 virtual + * token market prices and needs to be generated on the fly to be meaningful. + * + * @param _setToken Instance of the SetToken + * @param _baseToken Address virtual token being traded + * @param _baseQuantityUnits Quantity of virtual token to trade in position units + * @param _quoteBoundQuantityUnits Max/min of vQuote asset to pay/receive when buying or selling + */ + function tradeAndTrackFunding( + ISetToken _setToken, + address _baseToken, + int256 _baseQuantityUnits, + uint256 _quoteBoundQuantityUnits + ) + external; + + /** + * @dev MANAGER ONLY: Withdraws tracked settled funding (in USDC) from the PerpV2 Vault to a default position + * on the SetToken. Collects manager and protocol performance fees on the withdrawn amount. + * This method is useful when withdrawing funding to be reinvested into the Basis Trading product. + * + * NOTE: Within PerpV2, `withdraw` settles `owedRealizedPnl` and any pending funding payments + * to the Perp vault prior to transfer. + * + * @param _setToken Instance of the SetToken + * @param _notionalFunding Notional amount of funding to withdraw (in USDC decimals) + */ + function withdrawFundingAndAccrueFees( + ISetToken _setToken, + uint256 _notionalFunding + ) + external; + + /** + * @dev MANAGER ONLY. Update performance fee percentage. + * + * @param _setToken Instance of SetToken + * @param _newFee New performance fee percentage in precise units (1e16 = 1%) + */ + function updatePerformanceFee( + ISetToken _setToken, + uint256 _newFee + ) + external; + + /** + * @dev MANAGER ONLY. Update performance fee recipient (address to which performance fees are sent). + * + * @param _setToken Instance of SetToken + * @param _newFeeRecipient Address of new fee recipient + */ + function updateFeeRecipient(ISetToken _setToken, address _newFeeRecipient) + external; +} \ No newline at end of file diff --git a/contracts/interfaces/IPerpV2LeverageModule.sol b/contracts/interfaces/IPerpV2LeverageModuleV2.sol similarity index 95% rename from contracts/interfaces/IPerpV2LeverageModule.sol rename to contracts/interfaces/IPerpV2LeverageModuleV2.sol index 090ae9f97..21bcfba4e 100644 --- a/contracts/interfaces/IPerpV2LeverageModule.sol +++ b/contracts/interfaces/IPerpV2LeverageModuleV2.sol @@ -1,5 +1,5 @@ /* - Copyright 2021 Set Labs Inc. + Copyright 2022 Set Labs Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,14 +31,14 @@ import { IMarketRegistry } from "./external/perp-v2/IMarketRegistry.sol"; import { PerpV2Positions } from "../protocol/integration/lib/PerpV2Positions.sol"; /** - * @title IPerpV2LeverageModule + * @title IPerpV2LeverageModuleV2 * @author Set Protocol * - * Interface for the PerpV2LeverageModule. Only specifies Manager permissioned functions, events - * and getters. PerpV2LeverageModule also inherits from ModuleBase and SetTokenAccessible which support + * Interface for the PerpV2LeverageModuleV2. Only specifies Manager permissioned functions, events + * and getters. PerpV2LeverageModuleV2 also inherits from ModuleBase and SetTokenAccessible which support * additional methods. */ -interface IPerpV2LeverageModule { +interface IPerpV2LeverageModuleV2 { /* ============ Structs ============ */ @@ -121,7 +121,7 @@ interface IPerpV2LeverageModule { // Decimals of collateral token. We set this in the constructor for later reading function collateralDecimals() external view returns(uint8); - + /* ============ External Functions ============ */ /** @@ -269,12 +269,4 @@ interface IPerpV2LeverageModule { * + net quote balance (10**18) */ function getAccountInfo(ISetToken _setToken) external view returns (AccountInfo memory accountInfo); - - /** - * @dev Gets the mid-point price of a virtual asset from UniswapV3 markets maintained by Perp Protocol - * - * @param _baseToken Address of virtual token to price - * @return price Mid-point price of virtual token in UniswapV3 AMM market - */ - function getAMMSpotPrice(address _baseToken) external view returns (uint256 price); } \ No newline at end of file diff --git a/contracts/protocol-viewers/PerpV2LeverageModuleViewer.sol b/contracts/protocol-viewers/PerpV2LeverageModuleViewer.sol index 12acaae8a..b3cccbff8 100644 --- a/contracts/protocol-viewers/PerpV2LeverageModuleViewer.sol +++ b/contracts/protocol-viewers/PerpV2LeverageModuleViewer.sol @@ -28,7 +28,7 @@ import { SignedSafeMath } from "@openzeppelin/contracts/math/SignedSafeMath.sol" import { IAccountBalance } from "../interfaces/external/perp-v2/IAccountBalance.sol"; import { IClearingHouseConfig } from "../interfaces/external/perp-v2/IClearingHouseConfig.sol"; import { IIndexPrice } from "../interfaces/external/perp-v2/IIndexPrice.sol"; -import { IPerpV2LeverageModule } from "../interfaces/IPerpV2LeverageModule.sol"; +import { IPerpV2LeverageModuleV2 } from "../interfaces/IPerpV2LeverageModuleV2.sol"; import { ISetToken } from "../interfaces/ISetToken.sol"; import { PerpV2Positions } from "../protocol/integration/lib/PerpV2Positions.sol"; import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol"; @@ -39,7 +39,7 @@ import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol"; * @author Set Protocol * * PerpV2LeverageModuleViewer enables queries of information regarding open PerpV2 positions - * specifically for leverage ratios and issuance maximums. + * specifically for leverage ratios and issuance maximums. */ contract PerpV2LeverageModuleViewer { using SafeCast for int256; @@ -61,7 +61,7 @@ contract PerpV2LeverageModuleViewer { /* ============ State Variables ============ */ - IPerpV2LeverageModule public immutable perpModule; // PerpV2LeverageModule instance + IPerpV2LeverageModuleV2 public immutable perpModule; // PerpV2LeverageModule instance IAccountBalance public immutable perpAccountBalance; // Perp's Account Balance contract IClearingHouseConfig public immutable perpClearingHouseConfig; // PerpV2's ClearingHouseConfig contract ERC20 public immutable vQuoteToken; // Virtual Quote asset for PerpV2 (vUSDC) @@ -78,7 +78,7 @@ contract PerpV2LeverageModuleViewer { * @param _vQuoteToken Address of virtual Quote asset for PerpV2 (vUSDC) */ constructor( - IPerpV2LeverageModule _perpModule, + IPerpV2LeverageModuleV2 _perpModule, IAccountBalance _perpAccountBalance, IClearingHouseConfig _perpClearingHouseConfig, ERC20 _vQuoteToken @@ -103,7 +103,7 @@ contract PerpV2LeverageModuleViewer { * We want to find the point where freeCollateral = 0 after all trades have been executed. * freeCollateral = 0 => totalDebt = min(totalCollateral, accountValue) / initialMarginRatio * and, availableDebt = totalDebt - currentDebt - * + * * Now, accountValue = totalCollateral + unrealizedPnl * if unrealizedPnl >=0: * min(totalCollateral, accountValue) = totalCollateral @@ -113,7 +113,7 @@ contract PerpV2LeverageModuleViewer { * availableDebt = ((totalCollateral + unrealizedPnl) / imRatio) - currentDebt * * We also know that any slippage gets accrued to unrealizedPnl BEFORE any new collateral is being deposited so - * we need to account for our expected slippage accrual impact on accountValue by subtracting our expected amount + * we need to account for our expected slippage accrual impact on accountValue by subtracting our expected amount * of slippage divided by the imRatio from the availableDebt. We can then divide the availableDebtWithSlippage by * the absolute value of our current position and multiply by our totalSupply to get the max issue amount. * @@ -162,7 +162,7 @@ contract PerpV2LeverageModuleViewer { /** * @dev Returns relevant data for displaying current positions. Identifying info for each position plus current * size, index price, and leverage of each vAsset with an open position is returned. The sum quantity of vUSDC - * is returned along with identifying info in last index of array. + * is returned along with identifying info in last index of array. * * @param _setToken Instance of SetToken * @@ -217,7 +217,7 @@ contract PerpV2LeverageModuleViewer { * @return Total collateral value attributed to SetToken */ function _calculateTotalCollateralValue(ISetToken _setToken) internal view returns (int256) { - IPerpV2LeverageModule.AccountInfo memory accountInfo = perpModule.getAccountInfo(_setToken); + IPerpV2LeverageModuleV2.AccountInfo memory accountInfo = perpModule.getAccountInfo(_setToken); return accountInfo.collateralBalance .add(accountInfo.owedRealizedPnl)